<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="/feed.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="fr">
  <generator uri="https://11ty.dev/" version="3.1.7">Eleventy</generator>
  <title>Sylvain</title>
  <subtitle>Développeur backend &amp; DevOps à Bordeaux</subtitle>
  <link href="https://www.sylvain.dev/feed.xml" rel="self"/>
  <link href="https://www.sylvain.dev/"/>
  
    <updated>2026-10-29T00:00:00Z</updated>
  
  
  <id>https://sylvain.dev</id>
  <author>
    <name>Sylvain MÉTAYER</name>
    
    <uri>https://www.sylvain.dev/</uri>
  </author>
  
    
    <entry>
      <title>kdvc : faire le ménage dans les versions d&#39;un kDrive</title>
      <link href="https://www.sylvain.dev/article/kdrive-version-cleaner/"/>
      <published>2026-10-29T00:00:00Z</published>
      <updated>2026-10-29T00:00:00Z</updated>
      <id>https://sylvain.dev/article/kdrive-version-cleaner/</id>
      <content type="html">
        <![CDATA[
      <p><a href="https://github.com/sylvainmetayer/kdrive-version-cleaner">Sources (GitHub)</a> <a href="https://github.com/sylvainmetayer/kdrive-version-cleaner/releases/latest">Dernière version</a></p>
<h2 id="le-besoin" tabindex="-1"><a class="heading-link" href="#le-besoin">Le besoin</a></h2>
<p>L’espace occupé sur mon <a href="https://www.infomaniak.com/fr/kdrive">kDrive</a> augmentait régulièrement, alors que je n’y ajoutais que peu de fichiers. En cherchant un peu, j’ai trouvé d’où venait cet écart : les <strong>anciennes versions</strong> des fichiers. À chaque modification, kDrive garde une copie de l’ancienne version, ce qui est très pratique pour revenir en arrière, mais beaucoup moins quand un fichier modifié tous les jours finit par peser plusieurs fois sa taille (ma base KeePass par exemple, ou alors un dossier rempli de photos sur lequel on vient changer des métadonnées 🥲).</p>
<p>Grâce à l’outil présenté plus bas, j’ai pu libérer 3,2 Go, soit 686 anciennes versions. Au final, mon quota était largement respecté, mais je souhaitais quand même trouver une solution pour éviter de me retrouver un jour avec un kDrive saturé à cause des anciennes versions.</p>
<p>Ma première idée a été de faire cela via l’interface web de kDrive. Problème : celle d’Infomaniak ne permet de supprimer les versions qu’une par une, fichier par fichier. 😩</p>
<p>En revanche, Infomaniak propose une <a href="https://developer.infomaniak.com/docs/api">API</a> qui permet de lister les fichiers, leurs versions, et de les supprimer. De quoi se faire un petit outil !</p>
<h2 id="kdvc" tabindex="-1"><a class="heading-link" href="#kdvc">kdvc</a></h2>
<p><code>kdvc</code> (pour <em>kDrive Version Cleaner</em>) est donc une petite TUI<sup class="footnote-ref"><a href="#fn1" id="fnref1"><span class="visually-hidden">note </span>1</a></sup>, écrite en <a href="https://www.rust-lang.org/">Rust</a> avec <a href="https://ratatui.rs/">ratatui</a>. Elle scanne le drive une première fois, garde l’arborescence dans un cache SQLite local, puis affiche :</p>
<ul>
<li>des statistiques globales : nombre de fichiers, espace occupé par les anciennes versions</li>
<li>un explorateur, avec le poids des versions cumulé par dossier</li>
<li>le top des fichiers dont les versions prennent le plus de place</li>
<li>une recherche par nom, extension, taille ou nombre de versions</li>
<li>le journal des suppressions, exportable en CSV</li>
</ul>
<p>Pour faire le ménage, on sélectionne un fichier ou un dossier, et on choisit une règle : garder les N dernières versions, supprimer celles de plus de X jours, ou tout supprimer sauf la version courante.</p>
<h2 id="supprimer%2C-oui%2C-mais-pas-n%E2%80%99importe-quoi" tabindex="-1"><a class="heading-link" href="#supprimer%2C-oui%2C-mais-pas-n%E2%80%99importe-quoi">Supprimer, oui, mais pas n’importe quoi</a></h2>
<p>Un outil qui supprime des données en masse, ça mérite quelques garde-fous. Voici les deux principaux :</p>
<ul>
<li><strong>La version courante n’est jamais supprimée.</strong> L’API ne renvoie normalement que les anciennes versions, mais l’outil vérifie que la liste correspond exactement à ce que le scan a vu. Au moindre doute, la plus récente est protégée : au pire, on garde une version de trop.</li>
<li><strong>Toute suppression passe par un aperçu</strong>, qui liste les versions concernées et l’espace libéré, puis par une confirmation explicite de l’utilisateur.</li>
</ul>
<h2 id="%C3%A9crit-avec-un-agent-de-code" tabindex="-1"><a class="heading-link" href="#%C3%A9crit-avec-un-agent-de-code">Écrit avec un agent de code</a></h2>
<p>Ce projet est aussi l’occasion d’un test : je l’ai développé avec <a href="https://www.anthropic.com/claude-code">Claude Code</a>, en deux soirées. Mon rôle a surtout été de fixer les règles, puis de relire, laissant l’agent choisir le langage et ce qui lui semblait le plus juste.</p>
<p>Sans agent, cet outil serait resté une idée, car je n’aurais pas pris le temps d’apprendre Rust pour ça (ou alors, j’aurais attendu d’atteindre mon quota et sorti un petit script Python à la va-vite, non testé, et certainement moins fiable que cet outil).</p>
<p>Cependant, comme je ne connais pas Rust, je suis bien moins expert du code produit que si je l’avais écrit moi-même. Pour un projet perso de cette taille, c’est acceptable, sachant que la maintenance reste minime, vu le peu de fonctionnalités de l’outil.</p>
<h2 id="installation" tabindex="-1"><a class="heading-link" href="#installation">Installation</a></h2>
<p>Le plus simple est de passer par <a href="https://mise.jdx.dev">mise</a> :</p>
<pre class="shiki sylvain-dev"><code class="language-sh"><span class="line"><span class="tok-7cc4ff">mise</span><span class="tok-9fd88a"> use</span><span class="tok-9fd88a"> -g</span><span class="tok-9fd88a"> github:sylvainmetayer/kdrive-version-cleaner</span></span></code></pre>
<p>Des binaires pour Linux, macOS et Windows sont aussi disponibles sur la <a href="https://github.com/sylvainmetayer/kdrive-version-cleaner/releases/latest">page des releases</a>.</p>
<p>Il faudra ensuite créer un <a href="https://manager.infomaniak.com/v3/ng/profile/user/token/list">token d’API Infomaniak</a> avec le scope <code>drive</code> (et <code>accounts</code> pour que l’outil trouve vos comptes tout seul), puis l’exporter dans <code>KDRIVE_TOKEN</code>. Le <a href="https://github.com/sylvainmetayer/kdrive-version-cleaner#readme">README</a> détaille le reste.</p>
<p>Si vous venez à utiliser ce projet, n’hésitez pas à faire des retours ou à contribuer sur <a href="https://github.com/sylvainmetayer/kdrive-version-cleaner">GitHub</a> !</p>
<hr class="footnotes-sep">
<section class="footnotes" aria-label="Notes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>Terminal User Interface, une interface utilisateur en mode texte. <a href="#fnref1" class="footnote-backref" aria-label="Retour au texte (note 1)">↩︎</a></p>
</li>
</ol>
</section>

    ]]>
      </content>
      
        <category term="projet"/>
      
        <category term="rust"/>
      
        <category term="infomaniak"/>
      
      
        <summary type="html">
          Mon kDrive se remplissait tout seul. La faute aux anciennes versions des fichiers, que l&#39;interface ne permet pas de supprimer en masse.
        </summary>
      
    </entry>
  
    
    <entry>
      <title>SnowCamp 2025</title>
      <link href="https://www.sylvain.dev/article/snowcamp-2025/"/>
      <published>2025-01-30T00:00:00Z</published>
      <updated>2025-01-30T00:00:00Z</updated>
      <id>https://sylvain.dev/article/snowcamp-2025/</id>
      <content type="html">
        <![CDATA[
      <p><img src="/images/snowcamp-2025.jpg" alt="Amphithéâtre comble de SnowCamp face à deux orateurs sur scène et leurs slides"></p>
<p>Une fois n’est pas coutume, commençons par nous mettre à la place des organisateurs des événements tech’. <a href="https://fr.linkedin.com/company/snowcamp-io">Snowcamp</a>, comme beaucoup d’autres salons cette année a eu du mal à trouver des sponsors. Commençons donc par remercier très chaleureusement ceux qui ont pu rester fidèles.</p>
<p>C’est un vrai soucis, qui a mené d’autres conférences à l’annulation. Ces événements sont notre meilleur moyen d’apprendre, d’échanger, de confronter nos points de vues et d’ouvrir nos horizons. Espérons que ce n’est que passager et en attendant, nous tenons à apporter tout notre soutien aux organisateurs qui font un travail, bénévole, et magnifique !</p>
<p>Passons maintenant à nos retours sur quelques conférences que nous avons pu voir avec <a href="https://fr.linkedin.com/in/anaismoulin">Anaïs M.</a> et <a href="https://fr.linkedin.com/in/jerome-tama">Jérôme Tama</a>.</p>
<p>La journée de jeudi débute par une dissection technique de la faille XZ Utils de <a href="https://fr.linkedin.com/in/quentindunand">Quentin Dunand</a> et <a href="https://fr.linkedin.com/in/wassim-ahmedb">Wassim Ahmed-Belkacem</a>. Ils nous expliquent, étape par étape, la mise en oeuvre de la back door. La présentation est vivante, et l’explication pas à pas clarifie très bien l’ingénierie mise en oeuvre.</p>
<p>Vient ensuite le tour de <a href="https://fr.linkedin.com/in/jerome-tama">Jérôme Tama</a> de donner son sujet, ou il nous propose de (re)passer notre permis… de refactorer ! Nous découvrons alors les mécaniques d’OpenRewrite pour pouvoir effectuer des modifications de code à grande échelle, simplement et de manière automatisée.</p>
<p><a href="https://fr.linkedin.com/in/loic-gudet">Loic Gudet</a> nous fait ensuite une démonstration en live d’un prototype d’IA générative avec le thème des « Jeux olympiques de Paris 2024 ». Une manière entre autres de présenter concrètement comment sont utilisés les retours des utilisateurs pour améliorer les réponses proposées, quels sont les coûts liés à la maintenance de ces IA ainsi que les outils utilisés pour mesurer son efficacité. Une conférence instructive pour comprendre tout ce qui se cache derrière la mise en œuvre d’une IA générative.</p>
<p>Sur ce même créneau, <a href="https://fr.linkedin.com/in/pvulliemin-platform-engineer/fr">Paul Vulliemin</a> et <a href="https://fr.linkedin.com/in/m%C3%A9lissa-pinon">Mélissa Pinon</a> nous font un retour sur la façon de gérer les environnements de développement de leur équipes avec une solution Cloud, en mettant l’accent sur l’élasticité des ressources et la rapidité d’accostage pour les développeurs. Après un comparatif des solutions envisagées, ils nous montrent la solution retenue, Coder et sa mise en place avec une démonstration des fonctionnalités de l’outil et des intégrations sur nos IDE.</p>
<p>Suite à ces présentation, il est désormais l’heure pour moi de faire ma présentation, sur SOPS, dans laquelle je présente comment cet outil peut vous aider à stocker vos secrets de manière sécurisées dans vos dépôts Git, et ce même sans accès à un Secret Manager ou Vault externe.</p>
<p>Après le déjeuner, c’est au tour de <a href="https://fr.linkedin.com/in/leogatellier">Léo Gatellier</a> et  <a href="https://fr.linkedin.com/in/tim-ghibaudo-27401853">🚀 Tim Ghibaudo</a> de nous faire un REX sans filtre sur leur 3 ans passés à maintenir leur cluster Kubernetes, avec ce qui a bien fonctionné et ce qui reste toujours à améliorer. Dans l’objectif de rendre autonome les équipes de développement, ils présentent comment ils ont automatisé à l’aide de script, CLI et/ou API les tâches récurrentes afin de viser moins d’interventions manuelles, tout en garantissant les contraintes des ops niveau sécurité. Léo et Tim insistent également sur le fait que le plus gros changement n’est pas que technique, mais bien organisationnel et nécessite donc un bon accompagnement pour être une réussite.</p>
<p>Sur ce même créneau, <a href="https://fr.linkedin.com/in/olivierleplus">Olivier Leplus</a> et <a href="https://fr.linkedin.com/in/yohanlasorsa/fr">Yohan Lasorsa</a> nous font la présentation de plus de 10 fonctionnalités du web (avec une préférence pour la 9 ¾) qui sont parfois disponible depuis plusieurs années, méconnues et qui pourtant peuvent nous faciliter la vie. Que ce soit dans la gestion des Array ou bien pour centrer un div de manière efficace… Cette conférence apporte des solutions à des problèmes de tous les jours.</p>
<p>En fin de journée, c’est au tour de <a href="https://fr.linkedin.com/in/anaismoulin">Anaïs M.</a> de monter sur scène, pour un sujet trop peu évoqué, la discrimination positive, durant lequel elle nous fait part de ses propres expériences et de ses ressentis, montrant ainsi que bien que des progrès aient été effectuées, beaucoup restent encore à faire !</p>
<p>Ces 2 jours de conférences ont été l’occasion de découvrir de nouvelles choses mais également d’avoir des échanges de nombreuses personnes, que cela soit lors de la soirée speaker, ou des discussions autour d’un café lors de la journée de conférences. Merci à tous, participants comme speaker, pour ces échanges de qualités !</p>
<p>Nous souhaitons aussi remercier <a href="https://fr.linkedin.com/in/brunolavit">Bruno Lavit</a> pour les magnifiques photos qu’il a pris lors cette édition. Et finalement, un grand merci à <a href="https://fr.linkedin.com/company/onepoint">Onepoint</a> pour nous permettre de partager nos expériences lors de ces évènements !</p>

    ]]>
      </content>
      
        <category term="snowcamp"/>
      
        <category term="conference"/>
      
      
        <summary type="html">
          Nos retours sur SnowCamp 2025 : la faille XZ Utils, OpenRewrite, IA générative, environnements de développement avec Coder, Kubernetes en production et fonctionnalités méconnues du web.
        </summary>
      
    </entry>
  
    
    <entry>
      <title>Notre retour (Build &amp; Deploy) sur Devoxx France 2024</title>
      <link href="https://www.sylvain.dev/article/devoxx-france-2024-build-deploy/"/>
      <published>2024-05-30T00:00:00Z</published>
      <updated>2024-05-30T00:00:00Z</updated>
      <id>https://sylvain.dev/article/devoxx-france-2024-build-deploy/</id>
      <content type="html">
        <![CDATA[
      <p><img src="/images/devoxx-france-2024.jpg" alt="Bannière Devoxx France 2024 : un robot humanoïde sprinte sur une piste d'athlétisme"></p>
<p>Après les retours de nos collègues, nous allons faire les nôtres sur la partie Build &amp; Deploy de l’édition 2024 de Devoxx France.</p>
<p>Et comme chaque année, le moins que l’on puisse dire, c’est qu’il y avait du choix, avec plusieurs dizaines de conférences sur les façons de packager et déployer nos applications ! Sans plus attendre, voici les sujets qui nous ont marqué avec <a href="https://dev.to/cfarges">@cfarges</a> et <a href="https://dev.to/jtama">@jtama</a> dans cette catégorie.</p>
<h2 id="gatewayapi%2C-10-ans-de-maturation-pour-une-nouvelle-api-kubernetes" tabindex="-1"><a class="heading-link" href="#gatewayapi%2C-10-ans-de-maturation-pour-une-nouvelle-api-kubernetes">GatewayAPI, 10 ans de maturation pour une nouvelle API Kubernetes</a></h2>
<p>Cette année <a href="https://www.linkedin.com/in/davinkevin/">Kévin Davin</a> est venu nous parler de la Gateway API. &lt;3</p>
<p>En effet, avec pas mal de recul, le constat est clair : la ressource <em>Ingress</em> n’est pas suffisante. Elle prend en charge trop de responsabilité, n’est pas suffisamment spécifique, laissant chacune de ses implémentations faire différent choix pour la même solution (manque de portabilité), et ne rend pas non plus suffisamment de service.</p>
<p>La Gateway API est orientée <em>rôle</em> avec plusieurs <em>kinds</em>:</p>
<ul>
<li>La <em>GatewayClass</em>:: Pour le provider, celui qui connait le réseau</li>
<li>La <em>Gateway</em> :: Pour le cluster operator, celui qui connait le cluster 🤷</li>
<li>Les <em>GRPCRoute</em> / <em>HTTPRoute</em>:: Pour les développeurs, ceux qui connaissent les applications.</li>
</ul>
<p>Chaque personne ayant ses compétences, ses connaissances, ses responsabilités, et ses <em>kind</em>.</p>
<p>Cette api va suffisamment loin pour empiéter largement sur une partie des services offerts par les <em>service mesh</em> (dont le traffic splitting).</p>
<p><s class="dead-link" title="La vidéo du replay n'est plus disponible">Replay</s></p>
<h2 id="multi-kubernetes%2C-multi-r%C3%A9gions%2C-au-secours-!" tabindex="-1"><a class="heading-link" href="#multi-kubernetes%2C-multi-r%C3%A9gions%2C-au-secours-!">Multi Kubernetes, Multi Régions, Au-secours !</a></h2>
<p><a href="https://www.linkedin.com/in/aur%C3%A9lien-moreau-32075a105/">Aurélien Moreau</a> et <a href="https://www.linkedin.com/in/nicolas-lavacry-13a21415/">Nicolas Lavacry</a> présentent, au travers d’un REX avec pour exemple une entreprise fictive, les besoins de leur nouvelle entreprise : CASDAL. Cette dernière a en effet 2 marchés : un marché américain, et un français. Comment gérer l’hébergement de cette application ?</p>
<p>On découvre alors comment déployer un environnement Kubernetes sur plusieurs régions, et le besoin de créer plusieurs clusters pour assurer une latence faible, Kubernetes n’aimant en effet pas les latences si un continent sépare plusieurs nœuds. Leur démo, parfaitement maîtrisée permet de nous montrer l’envers du décor et des outils/méthodes pour garantir qualité de service, latence faible et  l’intégrité de nos données !</p>
<div class="video-player youtube" data-youtube="ADp3fonoDWM" data-title="Multi Kubernetes, Multi Régions, Au-secours !"><a href="https://www.youtube.com/watch?v=ADp3fonoDWM" class="youtube-link"><picture><source type="image/avif" srcset="/img/ZQ3AYue9mQ-480.avif"><source type="image/webp" srcset="/img/ZQ3AYue9mQ-480.webp"><img src="/img/ZQ3AYue9mQ-480.jpeg" alt="" loading="lazy" decoding="async" width="480" height="360"></picture><span class="youtube-play" aria-hidden="true"></span><span class="youtube-length" aria-hidden="true">45:27</span><span class="visually-hidden">Lire la vidéo « Multi Kubernetes, Multi Régions, Au-secours ! », durée 45 min</span></a></div>
<h2 id="notre-d%C3%A9pendance-%C3%A0-l%E2%80%99open-source-est-effrayante.-slsa%2C-sbom-et-sigstore-%C3%A0-la-rescousse" tabindex="-1"><a class="heading-link" href="#notre-d%C3%A9pendance-%C3%A0-l%E2%80%99open-source-est-effrayante.-slsa%2C-sbom-et-sigstore-%C3%A0-la-rescousse">Notre dépendance à l’Open Source est effrayante. SLSA, SBOM et Sigstore à la rescousse</a></h2>
<p>Cette conférence, très intéressante, nous montre à quel point nous dépendons de logiciels/dépendances tierces dans nos applications, sur lesquelles nous n’avons pas la main. Cela signifie-t-il pour autant qu’il faut les utiliser sans valider leur intégrité, pour éviter qu’un intermédiaire vienne injecter du code malveillant lors d’une étape de packaging de notre application ?</p>
<p><a href="https://www.linkedin.com/in/sabdelfettah/">Abdellfetah Sghiouar</a> nous présente alors des outils sur lesquels nous pouvons nous appuyer pour garantir la traçabilité de nos applications, tel que cosign pour signer nos images avant de les déployer dans notre cluster, ou encore SBOM pour lister tous les paquets utilisés dans notre application.</p>
<div class="video-player youtube" data-youtube="MEJ-ae_D8X4" data-title="Notre dépendance à l'Open Source est effrayante. SLSA, SBOM et Sigstore à la rescousse"><a href="https://www.youtube.com/watch?v=MEJ-ae_D8X4" class="youtube-link"><picture><source type="image/avif" srcset="/img/8w40p8Cdfj-480.avif"><source type="image/webp" srcset="/img/8w40p8Cdfj-480.webp"><img src="/img/8w40p8Cdfj-480.jpeg" alt="" loading="lazy" decoding="async" width="480" height="360"></picture><span class="youtube-play" aria-hidden="true"></span><span class="youtube-length" aria-hidden="true">43:21</span><span class="visually-hidden">Lire la vidéo « Notre dépendance à l'Open Source est effrayante. SLSA, SBOM et Sigstore à la rescousse », durée 43 min</span></a></div>
<h2 id="au-c%C5%93ur-de-la-ruche-ebpf!" tabindex="-1"><a class="heading-link" href="#au-c%C5%93ur-de-la-ruche-ebpf!">Au cœur de la ruche eBPF!</a></h2>
<p>J’avais déjà entendu parler plusieurs fois d’eBPF, sans vraiment savoir ce dont il s’agissait. Cette conférence était donc l’opportunité pour moi de creuser un peu le sujet ! Bien que très technique, <a href="https://www.linkedin.com/in/aboullaite/">Mohammed Aboullaite</a> a bien expliqué le fonctionnement d’un module du kernel et l’évolution d’eBPF. Je ne pense pas avoir l’usage dès demain d’écrire mon propre module kernel, mais je comprends mieux toute la “hype” autour de ça et la plus-value d’eBPF afin de pouvoir simplifier la distribution d’un nouveau module, tout en ayant des performances natives et en gardant la même sécurité.</p>
<div class="video-player youtube" data-youtube="XaBbxb0r0fc" data-title="Au cœur de la ruche eBPF!"><a href="https://www.youtube.com/watch?v=XaBbxb0r0fc" class="youtube-link"><picture><source type="image/avif" srcset="/img/o-bv1v1e54-480.avif"><source type="image/webp" srcset="/img/o-bv1v1e54-480.webp"><img src="/img/o-bv1v1e54-480.jpeg" alt="" loading="lazy" decoding="async" width="480" height="360"></picture><span class="youtube-play" aria-hidden="true"></span><span class="youtube-length" aria-hidden="true">46:42</span><span class="visually-hidden">Lire la vidéo « Au cœur de la ruche eBPF! », durée 47 min</span></a></div>
<h2 id="le-cauchemar-des-attaquants-%3A-une-infrastructure-sans-secret" tabindex="-1"><a class="heading-link" href="#le-cauchemar-des-attaquants-%3A-une-infrastructure-sans-secret">Le cauchemar des attaquants : une infrastructure sans secret</a></h2>
<p><a href="https://www.linkedin.com/in/thibault-lengagne-76a35583/">Thibault Lengagne</a> nous montre comment s’appuyer sur Vault et Boundary afin de supprimer la plupart des mots de passes<br>
de nos environnements tout en conservant une approche “Secure by design” et avoir une traçabilité complète des différents accès aux composants applicatifs.</p>
<p>Avec une architecture Zero-Credentials, on dispose d’un seul mot de passe par utilisateur qui permettra d’accéder à travers Boundary<br>
à nos applications. L’association de Boundary et Vault permet de créer des identifiants temporaires et de garder une traçabilité complète des accès aussi bien en environnement de développement que jusqu’à la production.</p>
<p>Thibault nous montre une solution d’architecture et les bonnes pratiques associées à ces concepts. A travers plusieurs petites démo, on commence à avoir envie de déployer ça dans nos environnements après avoir vu la taille de l’équipe grandir.</p>
<p>Fini les rotations de mot de passe à n’en plus finir, on a un accès et le reste est géré par les politiques définies dans le code source de notre infrastructure.</p>
<div class="video-player youtube" data-youtube="U3AL2pqPg3I" data-title="Le cauchemar des attaquants : une infrastructure sans secret"><a href="https://www.youtube.com/watch?v=U3AL2pqPg3I" class="youtube-link"><picture><source type="image/avif" srcset="/img/OnQ3Wg1c5J-480.avif"><source type="image/webp" srcset="/img/OnQ3Wg1c5J-480.webp"><img src="/img/OnQ3Wg1c5J-480.jpeg" alt="" loading="lazy" decoding="async" width="480" height="360"></picture><span class="youtube-play" aria-hidden="true"></span><span class="youtube-length" aria-hidden="true">45:27</span><span class="visually-hidden">Lire la vidéo « Le cauchemar des attaquants : une infrastructure sans secret », durée 45 min</span></a></div>
<h2 id="check-list-ultime-pour-rendre-vos-app-cloud-native" tabindex="-1"><a class="heading-link" href="#check-list-ultime-pour-rendre-vos-app-cloud-native">Check-list ultime pour rendre vos app cloud native</a></h2>
<p>Dans cette conférence <a href="https://www.linkedin.com/in/katiahimeur/">Katia Himeur</a> revient sur les différents contextes qui peuvent nous amener à déplacer nos applications sur le “cloud”.</p>
<p>Elle nous rappelle que la définition du “cloud” peut être vastement différente suivant nos interlocuteurs. La complexité, la pléthore de solutions disponibles (plus de 2000 outils disponibles chez la CNCF par exemple) et la diversité des fournisseurs doivent être pris en compte lors d’un projet cloud, que ce soit pour une nouvelle application<br>
ou le portage d’un existant.</p>
<p>Entre la méthodologie et le REX, la conférence de Katia est une mine d’informations et d’inspiration sur la manière d’aborder ce type de projet.</p>
<p>Les points présentés se situent autant au niveau de la technique que de l’humain, avec l’onboarding des équipes et la conduite du changement. Les principaux points durs de ces projets sont pris en compte, serait-ce la recette ultime ?</p>
<div class="video-player youtube" data-youtube="3s-gtziZ3UU" data-title="Check-list ultime pour rendre vos app cloud native"><a href="https://www.youtube.com/watch?v=3s-gtziZ3UU" class="youtube-link"><picture><source type="image/avif" srcset="/img/GYx8dDMKJF-480.avif"><source type="image/webp" srcset="/img/GYx8dDMKJF-480.webp"><img src="/img/GYx8dDMKJF-480.jpeg" alt="" loading="lazy" decoding="async" width="480" height="360"></picture><span class="youtube-play" aria-hidden="true"></span><span class="youtube-length" aria-hidden="true">45:25</span><span class="visually-hidden">Lire la vidéo « Check-list ultime pour rendre vos app cloud native », durée 45 min</span></a></div>
<h2 id="le-mot-de-la-fin" tabindex="-1"><a class="heading-link" href="#le-mot-de-la-fin">Le mot de la fin</a></h2>
<p>Merci à <a href="https://dev.to/onepoint">@onepoint</a> pour nous permettre de participer chaque année à ce moment privilégié !<br>
N’hésitez pas à aller regarder les autres articles publiés par nos collègues sur les autres thèmes !</p>
<p>Retrouvez notre série d’articles sur Devoxx :</p>
<ol>
<li><a href="https://dev.to/onepoint/devoxx-france-2024-8o">Intro</a></li>
<li><a href="https://dev.to/onepoint/notre-retour-frontend-sur-devoxx-2024-1jgg">Frontend</a></li>
<li><a href="https://dev.to/onepoint/mais-oui-ia-de-la-data-a-devoxx-france-2024--4kpe">Data/IA</a></li>
<li><a href="https://dev.to/onepoint/notre-retour-backend-sur-devoxx-2024-4knc">Backend</a></li>
</ol>

    ]]>
      </content>
      
        <category term="devoxx"/>
      
        <category term="conference"/>
      
        <category term="kubernetes"/>
      
      
        <summary type="html">
          Les conférences Build &amp; Deploy qui nous ont marqués à Devoxx France 2024 : Gateway API, Kubernetes multi-régions, supply chain, eBPF, Vault et Boundary.
        </summary>
      
    </entry>
  
    
    <entry>
      <title>DevoxxFR 2023</title>
      <link href="https://www.sylvain.dev/article/devoxx-france-2023/"/>
      <published>2023-04-27T00:00:00Z</published>
      <updated>2023-04-27T00:00:00Z</updated>
      <id>https://sylvain.dev/article/devoxx-france-2023/</id>
      <content type="html">
        <![CDATA[
      <p><img src="/images/devoxx-france-2023.jpg" alt="Bannière Devoxx France : la tour Eiffel au coucher du soleil, survolée par des drones"></p>
<p>Nous sommes (re)venus à <a href="https://www.devoxx.fr/">DevoxxFR</a> pour cette 11ème édition, et il y avait du choix ! Avec en moyenne 8 conférences/tool-in-action en parallèle, il y en a pour tous les goûts ! Ça tombe bien, ayant tous des préférences différentes, nous avons pu couvrir un bon nombre des conférences sur différents thèmes : front, IA, CI/CD,  Kubernetes…</p>
<p>Pour les moments où il y a trop de choix sur un même créneau, il est toujours possible de compter sur la <a href="https://www.youtube.com/@DevoxxFRvideos">chaîne YouTube de Devoxx</a>. En effet, la quasi-totalité des talks sont déjà disponibles en replay !</p>
<p>Parmi ce que nous avons eu l’occasion de voir, voici notre top 5 !</p>
<h2 id="top-5" tabindex="-1"><a class="heading-link" href="#top-5">Top 5</a></h2>
<h3 id="1er-dans-nos-%E2%9D%A4%EF%B8%8F-%E2%80%9Calice-au-pays-d%E2%80%99opentelemetry%E2%80%9D" tabindex="-1"><a class="heading-link" href="#1er-dans-nos-%E2%9D%A4%EF%B8%8F-%E2%80%9Calice-au-pays-d%E2%80%99opentelemetry%E2%80%9D">1<sup>er</sup> dans nos ❤️ “Alice au pays d’OpenTelemetry”</a></h3>
<p>Il s’agit d’un REX de la mise en place de l’observabilité dans un projet avec plusieurs briques logicielles. Après une présentation des concepts de l’observabilité, d’OpenTelemetry, <a href="https://dev.to/jtama">@jtama</a> nous présente de façon itérative son expérience et les obstacles rencontrés, afin de dompter ce “collecteur magique” et d’unifier nos logs, traces et métriques.</p>
<div class="video-player youtube" data-youtube="0xSCUgHxZu0" data-title="Alice au pays d’OpenTelemetry"><a href="https://www.youtube.com/watch?v=0xSCUgHxZu0" class="youtube-link"><picture><source type="image/avif" srcset="/img/ldZ_yUsNo2-480.avif"><source type="image/webp" srcset="/img/ldZ_yUsNo2-480.webp"><img src="/img/ldZ_yUsNo2-480.jpeg" alt="" loading="lazy" decoding="async" width="480" height="360"></picture><span class="youtube-play" aria-hidden="true"></span><span class="youtube-length" aria-hidden="true">46:08</span><span class="visually-hidden">Lire la vidéo « Alice au pays d’OpenTelemetry », durée 46 min</span></a></div>
<p><a href="https://jtama.github.io/alice-au-pays-d-opentelemetry/#/">Lien vers les slides</a><br>
<s class="dead-link" title="Le site du CFP n'est plus en ligne">Lien du CFP</s></p>
<h3 id="comprendre-et-utiliser-les-mod%C3%A8les-de-langage-d%E2%80%99ia" tabindex="-1"><a class="heading-link" href="#comprendre-et-utiliser-les-mod%C3%A8les-de-langage-d%E2%80%99ia">Comprendre et utiliser les modèles de langage d’IA</a></h3>
<p>Cette université de 3h présentée par <a href="https://twitter.com/collet_seb">Sébastien Collet</a> permet de découvrir les modèles de Machine Learning et Deep Learning, leur fonctionnements et limites ainsi que les évolutions des dernières années.</p>
<p>Un focus est également fait sur les modèles de langages prédictifs, ce qui permet de comprendre pourquoi les modèles tel que ChatGPT ont les biais qui ont été relevés récemment (hallucinations, toxicité…).</p>
<p>Si vous souhaitez un cours complet, vulgarisé et abordable, avec un historique des modèles d’IA, ce talk est pour vous !</p>
<div class="video-player youtube" data-youtube="ZbWL2W53BXY" data-title="Comprendre et utiliser les modèles de langage d'IA"><a href="https://www.youtube.com/watch?v=ZbWL2W53BXY" class="youtube-link"><picture><source type="image/avif" srcset="/img/w66zkAvOUz-480.avif"><source type="image/webp" srcset="/img/w66zkAvOUz-480.webp"><img src="/img/w66zkAvOUz-480.jpeg" alt="" loading="lazy" decoding="async" width="480" height="360"></picture><span class="youtube-play" aria-hidden="true"></span><span class="youtube-length" aria-hidden="true">2:49:50</span><span class="visually-hidden">Lire la vidéo « Comprendre et utiliser les modèles de langage d'IA », durée 2 h 50 min</span></a></div>
<p><a href="https://docs.google.com/presentation/d/e/2PACX-1vReIr93Udkzm3S0qn59AyFDYQjuXq0puGNYlFQYqDyoHqio_UgHbqQV1Qm4sUwt0ZeawfvGFdQOCHLc/pub#slide=id.g21f549ddc89_0_0">Slides</a><br>
<a href="https://github.com/sebastien-collet/talks/blob/master/Devoxx%20FR%202023/Ressources.md">Dépôt Github</a><br>
<s class="dead-link" title="Le site du CFP n'est plus en ligne">Lien du CFP</s></p>
<h3 id="une-architecture-gitops-from-scratch-%3A-gitlab%2C-ansible%2C-terraform%2C-kubernetes-et-aws" tabindex="-1"><a class="heading-link" href="#une-architecture-gitops-from-scratch-%3A-gitlab%2C-ansible%2C-terraform%2C-kubernetes-et-aws">Une Architecture GitOps from scratch : Gitlab, Ansible, Terraform, Kubernetes et AWS</a></h3>
<p>Avec cette université de 3 heures, <a href="https://www.twitter.com/@LoicOrtola">Loïc Ortola</a> et <a href="https://www.twitter.com/@AurelOps">Aurélien Moreau</a> de <a href="https://www.takima.fr/">Takima</a>, nous propose une plongée dans la mise en place d’un cluster Kubernetes via de l’<em>Infrastructure as code</em>.</p>
<p>L’utilisation de chaque outil est justifiée par son rôle. Le talk développe petit à petit la mise en place d’une infrastructure complexe, multi-cluster en partant du provisioning de l’infrastructure jusqu’au déploiement continue des applications dans une approche 100% Gitops.</p>
<div class="video-player youtube" data-youtube="FyAD_-LAMLo" data-title="Une Architecture GitOps from scratch : Gitlab, Ansible, Terraform, Kubernetes et AWS"><a href="https://www.youtube.com/watch?v=FyAD_-LAMLo" class="youtube-link"><picture><source type="image/avif" srcset="/img/mlKO5YVem5-480.avif"><source type="image/webp" srcset="/img/mlKO5YVem5-480.webp"><img src="/img/mlKO5YVem5-480.jpeg" alt="" loading="lazy" decoding="async" width="480" height="360"></picture><span class="youtube-play" aria-hidden="true"></span><span class="youtube-length" aria-hidden="true">2:46:41</span><span class="visually-hidden">Lire la vidéo « Une Architecture GitOps from scratch : Gitlab, Ansible, Terraform, Kubernetes et AWS », durée 2 h 47 min</span></a></div>
<p><a href="https://gitlab.com/takima-school/takione">Lien du dépôt Gitlab</a><br>
<s class="dead-link" title="Le site du CFP n'est plus en ligne">Lien du CFP</s></p>
<h3 id="g%C3%A9opolitique-de-la-data" tabindex="-1"><a class="heading-link" href="#g%C3%A9opolitique-de-la-data">Géopolitique de la data</a></h3>
<p>Avec cette keynote de 20 minutes, <a href="https://twitter.com/bayartb">Benjamin Bayart</a> co-fondateur de la quadrature du net, nous décrit à travers différents exemples et vulgarisations, ce qu’est la Géopolitique de la data et comment la réglementation européenne a évolué sur la protection des données personnelles.</p>
<p>Il clôture son discours en passant le message que tout ingénieur informatique fait de la géopolitique de la data.</p>
<div class="video-player youtube" data-youtube="EOOhYaGGArc" data-title="Géopolitique de la data"><a href="https://www.youtube.com/watch?v=EOOhYaGGArc" class="youtube-link"><picture><source type="image/avif" srcset="/img/pZFgKNEZoE-480.avif"><source type="image/webp" srcset="/img/pZFgKNEZoE-480.webp"><img src="/img/pZFgKNEZoE-480.jpeg" alt="" loading="lazy" decoding="async" width="480" height="360"></picture><span class="youtube-play" aria-hidden="true"></span><span class="youtube-length" aria-hidden="true">17:56</span><span class="visually-hidden">Lire la vidéo « Géopolitique de la data », durée 18 min</span></a></div>
<p><s class="dead-link" title="Le site du CFP n'est plus en ligne">Lien du CFP</s></p>
<h3 id="d%C3%A9mystifions-les-composants-internes-de-kubernetes" tabindex="-1"><a class="heading-link" href="#d%C3%A9mystifions-les-composants-internes-de-kubernetes">Démystifions les composants internes de Kubernetes</a></h3>
<p>L’objectif de ce talk est de démontrer que Kubernetes n’est pas “un outil automagique” mais qu’il se base sur des briques logicielles individuellement “simple” mais qui assemblées font la robustesse de Kubernetes.</p>
<p>Au travers d’une démonstration live, <a href="https://twitter.com/zwindler">Denis Germain</a> nous présente les différentes briques composant Kubernetes et leur utilité pour finalement arriver sur une application déployée sur un cluster “fait main” !</p>
<p>Si vous souhaitez savoir ce qui se cache derrière un “kubectl apply -f mon-deploiement.yaml” ou que vous souhaitez comprendre comment les composants “etcd”, “api-server”, “controller-manager”, “scheduler”, “kubelet”, “containerd” ou “CNI” fonctionnent ensemble, ce talk est pour vous !</p>
<div class="video-player youtube" data-youtube="OCMNA0dSAzc" data-title="Démystifions les composants internes de Kubernetes"><a href="https://www.youtube.com/watch?v=OCMNA0dSAzc" class="youtube-link"><picture><source type="image/avif" srcset="/img/R5NbiyViSo-480.avif"><source type="image/webp" srcset="/img/R5NbiyViSo-480.webp"><img src="/img/R5NbiyViSo-480.jpeg" alt="" loading="lazy" decoding="async" width="480" height="360"></picture><span class="youtube-play" aria-hidden="true"></span><span class="youtube-length" aria-hidden="true">43:37</span><span class="visually-hidden">Lire la vidéo « Démystifions les composants internes de Kubernetes », durée 44 min</span></a></div>
<p><a href="https://blog.zwindler.fr/talks/2023-demystifions-kubernetes/index.html">Slides</a><br>
<a href="https://github.com/zwindler/demystifions-kubernetes">Github contenant la démo</a><br>
<s class="dead-link" title="Le site du CFP n'est plus en ligne">Lien du CFP</s></p>
<h3 id="select-%E2%80%98amazing_features%E2%80%99-from-%E2%80%9Cpostgresql%E2%80%9D" tabindex="-1"><a class="heading-link" href="#select-%E2%80%98amazing_features%E2%80%99-from-%E2%80%9Cpostgresql%E2%80%9D">SELECT ‘amazing_features’ FROM “postgresql”</a></h3>
<p>Dans ce Tools in action, <a href="https://twitter.com/davinkevin">Kevin Davin</a> nous propose la (re)découverte de features méconnues ou oubliées de postgresql.</p>
<p>Entre les performances, les sucres syntaxiques et les bonnes pratiques, Kevin nous montre la vaste boite à outil dont dispose postgres pour aider le développeur à proposer des applications plus performantes et maintenables.</p>
<p>Il nous présente aussi quelques mauvaises pratiques qui sont pourtant monnaie courante lorsque l’on aborde ce SGBD d’un œil novice.</p>
<p>Que vous utilisiez ou non postgres, ce talk vous montrera ses super pouvoirs et vous invite à l’essayer.</p>
<div class="video-player youtube" data-youtube="I1rAkNDv1Ws" data-title="SELECT 'amazing_features' FROM &#34;postgresql&#34;"><a href="https://www.youtube.com/watch?v=I1rAkNDv1Ws" class="youtube-link"><picture><source type="image/avif" srcset="/img/Gl34A6vix1-480.avif"><source type="image/webp" srcset="/img/Gl34A6vix1-480.webp"><img src="/img/Gl34A6vix1-480.jpeg" alt="" loading="lazy" decoding="async" width="480" height="360"></picture><span class="youtube-play" aria-hidden="true"></span><span class="youtube-length" aria-hidden="true">29:06</span><span class="visually-hidden">Lire la vidéo « SELECT 'amazing_features' FROM &#34;postgresql&#34; », durée 29 min</span></a></div>
<p><a href="https://download.davinkevin.fr/presentations/select-amazing-features-from-postgresql/devoxxfr-2023/select-amazing-features-from-postgresql.pdf">Slides</a><br>
<a href="https://gitlab.com/davinkevin.fr/presentations/select-amazing_features-from-postgresql">Dépôt Gitlab</a><br>
<s class="dead-link" title="Le site du CFP n'est plus en ligne">Lien du CFP</s></p>
<h2 id="pour-finir" tabindex="-1"><a class="heading-link" href="#pour-finir">Pour finir</a></h2>
<p>DevoxxFR, c’est 3 jours de conférences, voyez ça comme un marathon, pas un sprint ! Planifiez votre programme, et prévoyez des temps de pause, pour faire un tour sur les nombreux stands de produits/logiciels que nous utilisons tous les jours (ou que nous avons eu l’occasion de découvrir), qui sont là pour recueillir des retours d’expérience et propositions d’améliorations !</p>
<p>Pour faciliter vos prises de notes, nous avons également développé un petit outil pour générer automatiquement vos templates de notes en fonction de vos favoris. <a href="https://github.com/cfrezier/devoxx2adoc/">Le dépôt Github</a></p>
<p>Écrit à 10 mains avec les fabuleux <a href="https://dev.to/cfrezier">@cfrezier</a> <a href="https://dev.to/cfarges">@cfarges</a> <a href="https://dev.to/jtama">@jtama</a> et <a href="https://dev.to/florianallainmat">@florianallainmat</a> !</p>
<p>On en profite pour faire passer un grand merci à <a href="https://www.groupeonepoint.com">onepoint</a> pour l’organisation de ces 3 jours au top !</p>
<p>Merci ! 😊</p>

    ]]>
      </content>
      
        <category term="devoxx"/>
      
        <category term="conference"/>
      
        <category term="kubernetes"/>
      
      
        <summary type="html">
          Les conférences qui nous ont marqués à la 11e édition de DevoxxFR : OpenTelemetry, modèles de langage, GitOps, géopolitique de la data, Kubernetes et PostgreSQL.
        </summary>
      
    </entry>
  
    
    <entry>
      <title>Premier Meetup</title>
      <link href="https://www.sylvain.dev/article/meetup-terraform/"/>
      <published>2022-02-05T00:00:00Z</published>
      <updated>2022-02-05T00:00:00Z</updated>
      <id>https://sylvain.dev/article/meetup-terraform/</id>
      <content type="html">
        <![CDATA[
      <p>J’ai eu l’occasion de faire mon premier meetup live avec onepoint le 1er février sur YouTube. Le sujet était : ‘Terraform, REX d’un développeur’. Pour celles et ceux qui souhaiteraient le regarder, je vous invite à le visionner en replay ici : <a href="https://www.youtube.com/watch?v=GR_YJIfo8jg&amp;list=PLm-YYS9h2JhWiAZ5QuuJD6jyghWjkK09q&amp;index=27">Lien YouTube</a>.</p>
<div class="video-player youtube" data-youtube="GR_YJIfo8jg" data-title="Terraform, REX d'un développeur"><a href="https://www.youtube.com/watch?v=GR_YJIfo8jg" class="youtube-link"><picture><source type="image/avif" srcset="/img/tjVxUjOjGb-480.avif"><source type="image/webp" srcset="/img/tjVxUjOjGb-480.webp"><img src="/img/tjVxUjOjGb-480.jpeg" alt="" loading="lazy" decoding="async" width="480" height="360"></picture><span class="youtube-play" aria-hidden="true"></span><span class="youtube-length" aria-hidden="true">50:10</span><span class="visually-hidden">Lire la vidéo « Terraform, REX d'un développeur », durée 50 min</span></a></div>
<p>Je suis content de moi, qui préfère d’habitude être derrière la caméra. Le fait d’avoir été encouragé à réaliser ce retour d’expérience m’a permis de me dépasser et finalement, la chose à retenir est que 45min, c’est à la fois long et court :)</p>

    ]]>
      </content>
      
        <category term="onepoint"/>
      
        <category term="terraform"/>
      
        <category term="meetup"/>
      
      
        <summary type="html">
          J&#39;ai eu l&#39;occasion de faire mon premier meetup le 1er février sur YouTube
        </summary>
      
    </entry>
  
    
    <entry>
      <title>Importer ses données Google Location dans PhoneTrack</title>
      <link href="https://www.sylvain.dev/article/importer-google-location-phonetrack/"/>
      <published>2021-05-17T00:00:00Z</published>
      <updated>2021-05-17T00:00:00Z</updated>
      <id>https://sylvain.dev/article/importer-google-location-phonetrack/</id>
      <content type="html">
        <![CDATA[
      <p>Si vous ne le saviez pas déjà, Google possède un historique de localisation de vos différents emplacements : <a href="https://www.google.com/maps/timeline">Google Location History</a>. J’ai utilisé ce service de 2011 à 2018, année à laquelle j’ai commencé à m’éloigner des <a href="https://degooglisons-internet.org/fr/">services Google</a>.</p>
<blockquote>
<p>Pour activer ou désactiver ce comportement, rendez-vous sur <a href="https://myactivity.google.com/activitycontrols?pli=1&amp;settings=location">les paramètres de votre compte Google</a></p>
</blockquote>
<p>Désormais, j’utilise l’application <a href="https://gitlab.com/eneiluj/phonetrack-oc">PhoneTrack</a> sur mon instance <a href="https://nextcloud.com/">Nextcloud</a>. Je souhaitais néanmoins récupérer mes données de 2011 à 2018 (représentant quelques milliers de km) sur ma nouvelle instance.</p>
<p>Cet article présente les différentes étapes pour réaliser cet import.</p>
<h2 id="r%C3%A9cup%C3%A9rer-les-donn%C3%A9es-de-google" tabindex="-1"><a class="heading-link" href="#r%C3%A9cup%C3%A9rer-les-donn%C3%A9es-de-google">Récupérer les données de Google</a></h2>
<p>Il faut tout d’abord récupérer l’historique des positions de Google. Pour cela, rendez-vous sur <a href="https://takeout.google.com/">Google Takeout</a>, puis décochez tout, sélectionnez uniquement <code>Historique des positions</code>, et précisez le format des données en <code>JSON</code> (<code>Formats multiples</code> puis <code>JSON</code>). L’export peut être long selon le nombre de données présentes.</p>
<blockquote>
<p>À titre indicatif, il m’a fallu environ 20 min pour avoir l’export à disposition</p>
</blockquote>
<h2 id="pr%C3%A9parer-les-donn%C3%A9es" tabindex="-1"><a class="heading-link" href="#pr%C3%A9parer-les-donn%C3%A9es">Préparer les données</a></h2>
<p>Une fois l’archive ZIP récupérée et extraite, vous trouverez un fichier <code>Historique des positions.json</code> dans le dossier <code>Historique des positions</code>. C’est ce fichier que nous allons importer dans PhoneTrack :)</p>
<p>Pour ma part, le fichier contient un peu plus d’un million et demi d’enregistrements, pour un poids de ~470 Mo.</p>
<pre class="shiki sylvain-dev"><code class="language-bash"><span class="line"><span class="tok-a9b8c8">~</span><span class="tok-d6e2ee">/wip</span></span>
<span class="line"><span class="tok-7cc4ff">$</span><span class="tok-9fd88a"> mv</span><span class="tok-9fd88a"> Historique</span><span class="tok-f2b56b">\ </span><span class="tok-9fd88a">des</span><span class="tok-f2b56b">\ </span><span class="tok-9fd88a">positions.json</span><span class="tok-9fd88a"> google.json</span></span>
<span class="line"></span>
<span class="line"><span class="tok-a9b8c8">~</span><span class="tok-d6e2ee">/wip</span></span>
<span class="line"><span class="tok-7cc4ff">$</span><span class="tok-9fd88a"> jq</span><span class="tok-a9b8c8"> '</span><span class="tok-9fd88a">.locations| length</span><span class="tok-a9b8c8">'</span><span class="tok-a9b8c8"> &#x3C;</span><span class="tok-9fd88a"> google.json</span></span>
<span class="line"><span class="tok-7cc4ff">1690273</span></span>
<span class="line"></span>
<span class="line"><span class="tok-a9b8c8">~</span><span class="tok-d6e2ee">/wip took 14s</span></span>
<span class="line"><span class="tok-7cc4ff">$</span><span class="tok-9fd88a"> ls</span><span class="tok-9fd88a"> -ailh</span><span class="tok-9fd88a"> google.json</span></span>
<span class="line"><span class="tok-7cc4ff">2498577</span><span class="tok-9fd88a"> -rw-rw-r--.</span><span class="tok-f2b56b"> 1</span><span class="tok-9fd88a"> user</span><span class="tok-9fd88a"> user</span><span class="tok-9fd88a"> 470M</span><span class="tok-f2b56b"> 17</span><span class="tok-9fd88a"> mai</span><span class="tok-9fd88a">   13:35</span><span class="tok-9fd88a"> google.json</span></span></code></pre>
<p>Il existe sûrement une meilleure façon de faire, mais lors de mes tests, un import direct du fichier dans PhoneTrack plantait, le fichier étant trop volumineux. Il a donc fallu que je découpe le fichier. Pour cela, j’ai fait un <a href="https://gist.github.com/sylvainmetayer/f4374861c79c669271e8734d8e7d9411">rapide script</a>, qui n’est pas parfait mais qui fait le job :)</p>
<pre class="shiki sylvain-dev"><code class="language-js"><span class="line"><span class="tok-c39bff">const</span><span class="tok-f2b56b"> fs</span><span class="tok-a9b8c8"> =</span><span class="tok-7cc4ff"> require</span><span class="tok-a9b8c8">(</span><span class="tok-a9b8c8">'</span><span class="tok-9fd88a">fs</span><span class="tok-a9b8c8">'</span><span class="tok-a9b8c8">);</span></span>
<span class="line"></span>
<span class="line"><span class="tok-c39bff">const</span><span class="tok-f2b56b"> data</span><span class="tok-a9b8c8"> =</span><span class="tok-f2b56b"> JSON</span><span class="tok-a9b8c8">.</span><span class="tok-7cc4ff">parse</span><span class="tok-a9b8c8">(</span><span class="tok-ff9a8a">fs</span><span class="tok-a9b8c8">.</span><span class="tok-7cc4ff">readFileSync</span><span class="tok-a9b8c8">(</span><span class="tok-a9b8c8">'</span><span class="tok-9fd88a">./google.json</span><span class="tok-a9b8c8">'</span><span class="tok-a9b8c8">,</span></span>
<span class="line"><span class="tok-a9b8c8">        {</span><span class="tok-d6e2ee"> encoding</span><span class="tok-a9b8c8">:</span><span class="tok-a9b8c8"> '</span><span class="tok-9fd88a">utf8</span><span class="tok-a9b8c8">'</span><span class="tok-a9b8c8">,</span><span class="tok-d6e2ee"> flag</span><span class="tok-a9b8c8">:</span><span class="tok-a9b8c8"> '</span><span class="tok-9fd88a">r</span><span class="tok-a9b8c8">'</span><span class="tok-a9b8c8"> }));</span></span>
<span class="line"></span>
<span class="line"><span class="tok-c39bff">const</span><span class="tok-f2b56b"> locations</span><span class="tok-a9b8c8"> =</span><span class="tok-ff9a8a"> data</span><span class="tok-a9b8c8">.</span><span class="tok-ff9a8a">locations</span><span class="tok-a9b8c8">;</span></span>
<span class="line"><span class="tok-c39bff">let</span><span class="tok-ff9a8a"> iterations</span><span class="tok-a9b8c8"> =</span><span class="tok-ff9a8a"> locations</span><span class="tok-a9b8c8">.</span><span class="tok-6fd6d0">length</span><span class="tok-a9b8c8">;</span></span>
<span class="line"></span>
<span class="line"><span class="tok-c39bff">let</span><span class="tok-ff9a8a"> dataFile</span><span class="tok-a9b8c8"> =</span><span class="tok-a9b8c8"> [];</span></span>
<span class="line"></span>
<span class="line"><span class="tok-c39bff">const</span><span class="tok-f2b56b"> fileName</span><span class="tok-a9b8c8"> =</span><span class="tok-a9b8c8"> '</span><span class="tok-9fd88a">google.</span><span class="tok-a9b8c8">'</span><span class="tok-a9b8c8">;</span></span>
<span class="line"><span class="tok-c39bff">let</span><span class="tok-ff9a8a"> fileSuffix</span><span class="tok-a9b8c8"> =</span><span class="tok-f2b56b"> 0</span><span class="tok-a9b8c8">;</span></span>
<span class="line"></span>
<span class="line"><span class="tok-ff9a8a">console</span><span class="tok-a9b8c8">.</span><span class="tok-7cc4ff">log</span><span class="tok-a9b8c8">(</span><span class="tok-a9b8c8">`${</span><span class="tok-ff9a8a">locations</span><span class="tok-a9b8c8">.</span><span class="tok-6fd6d0">length</span><span class="tok-a9b8c8">}</span><span class="tok-9fd88a"> locations</span><span class="tok-a9b8c8">`</span><span class="tok-a9b8c8">);</span></span>
<span class="line"><span class="tok-c39bff">for</span><span class="tok-a9b8c8"> (</span><span class="tok-ff9a8a">location</span><span class="tok-a9b8c8"> of</span><span class="tok-ff9a8a"> locations</span><span class="tok-a9b8c8">)</span><span class="tok-a9b8c8"> {</span></span>
<span class="line"><span class="tok-c39bff">        if</span><span class="tok-a9b8c8"> (</span><span class="tok-ff9a8a">dataFile</span><span class="tok-a9b8c8">.</span><span class="tok-6fd6d0">length</span><span class="tok-a9b8c8"> %</span><span class="tok-f2b56b"> 100000</span><span class="tok-a9b8c8"> ===</span><span class="tok-f2b56b"> 0</span><span class="tok-a9b8c8"> &#x26;&#x26;</span><span class="tok-ff9a8a"> dataFile</span><span class="tok-a9b8c8">.</span><span class="tok-6fd6d0">length</span><span class="tok-a9b8c8"> ></span><span class="tok-f2b56b"> 0</span><span class="tok-a9b8c8">)</span><span class="tok-a9b8c8"> {</span></span>
<span class="line"><span class="tok-c39bff">                const</span><span class="tok-f2b56b"> filename</span><span class="tok-a9b8c8"> =</span><span class="tok-a9b8c8"> `</span><span class="tok-9fd88a">google.</span><span class="tok-a9b8c8">${</span><span class="tok-ff9a8a">fileSuffix</span><span class="tok-a9b8c8">}</span><span class="tok-9fd88a">.json</span><span class="tok-a9b8c8">`</span><span class="tok-a9b8c8">;</span></span>
<span class="line"><span class="tok-ff9a8a">                fs</span><span class="tok-a9b8c8">.</span><span class="tok-7cc4ff">writeFileSync</span><span class="tok-a9b8c8">(</span><span class="tok-ff9a8a">filename</span><span class="tok-a9b8c8">,</span><span class="tok-f2b56b"> JSON</span><span class="tok-a9b8c8">.</span><span class="tok-7cc4ff">stringify</span><span class="tok-a9b8c8">({</span><span class="tok-d6e2ee"> locations</span><span class="tok-a9b8c8">:</span><span class="tok-ff9a8a"> dataFile</span><span class="tok-a9b8c8"> }));</span></span>
<span class="line"><span class="tok-ff9a8a">                console</span><span class="tok-a9b8c8">.</span><span class="tok-7cc4ff">log</span><span class="tok-a9b8c8">(</span><span class="tok-a9b8c8">`</span><span class="tok-9fd88a">Need to write file </span><span class="tok-a9b8c8">${</span><span class="tok-ff9a8a">fileSuffix</span><span class="tok-a9b8c8">}`</span><span class="tok-a9b8c8">);</span></span>
<span class="line"><span class="tok-ff9a8a">                fileSuffix</span><span class="tok-a9b8c8">++;</span></span>
<span class="line"><span class="tok-ff9a8a">                dataFile</span><span class="tok-a9b8c8"> =</span><span class="tok-a9b8c8"> [];</span></span>
<span class="line"><span class="tok-a9b8c8">        }</span></span>
<span class="line"><span class="tok-ff9a8a">        dataFile</span><span class="tok-a9b8c8">.</span><span class="tok-7cc4ff">push</span><span class="tok-a9b8c8">(</span><span class="tok-ff9a8a">location</span><span class="tok-a9b8c8">);</span></span>
<span class="line"><span class="tok-a9b8c8">}</span></span>
<span class="line"></span>
<span class="line"><span class="tok-c39bff">const</span><span class="tok-f2b56b"> filename</span><span class="tok-a9b8c8"> =</span><span class="tok-a9b8c8"> `</span><span class="tok-9fd88a">google.999.json</span><span class="tok-a9b8c8">`</span><span class="tok-a9b8c8">;</span></span>
<span class="line"><span class="tok-ff9a8a">fs</span><span class="tok-a9b8c8">.</span><span class="tok-7cc4ff">writeFileSync</span><span class="tok-a9b8c8">(</span><span class="tok-ff9a8a">filename</span><span class="tok-a9b8c8">,</span><span class="tok-f2b56b"> JSON</span><span class="tok-a9b8c8">.</span><span class="tok-7cc4ff">stringify</span><span class="tok-a9b8c8">({</span><span class="tok-d6e2ee"> locations</span><span class="tok-a9b8c8">:</span><span class="tok-ff9a8a"> dataFile</span><span class="tok-a9b8c8"> }));</span></span>
<span class="line"><span class="tok-ff9a8a">console</span><span class="tok-a9b8c8">.</span><span class="tok-7cc4ff">log</span><span class="tok-a9b8c8">(</span><span class="tok-a9b8c8">`</span><span class="tok-9fd88a">Wrote last data file with </span><span class="tok-a9b8c8">${</span><span class="tok-ff9a8a">dataFile</span><span class="tok-a9b8c8">.</span><span class="tok-6fd6d0">length</span><span class="tok-a9b8c8">}</span><span class="tok-9fd88a"> locations</span><span class="tok-a9b8c8">`</span><span class="tok-a9b8c8">);</span></span></code></pre>
<p>Pour l’usage, cela se passe comme ça : le script va lire un fichier (<code>google.json</code>) et le séparer en fichiers de <code>100 000</code> éléments chacun.</p>
<pre class="shiki sylvain-dev"><code class="language-bash"><span class="line"><span class="tok-a9b8c8">~</span><span class="tok-d6e2ee">/wip via ⬢ v14.15.0</span></span>
<span class="line"><span class="tok-7cc4ff">$</span><span class="tok-9fd88a"> node</span><span class="tok-9fd88a"> split.js</span></span>
<span class="line"><span class="tok-7cc4ff">1690273</span><span class="tok-9fd88a"> locations</span></span>
<span class="line"><span class="tok-7cc4ff">Need</span><span class="tok-9fd88a"> to</span><span class="tok-9fd88a"> write</span><span class="tok-9fd88a"> file</span><span class="tok-f2b56b"> 0</span></span>
<span class="line"><span class="tok-7cc4ff">Need</span><span class="tok-9fd88a"> to</span><span class="tok-9fd88a"> write</span><span class="tok-9fd88a"> file</span><span class="tok-f2b56b"> 1</span></span>
<span class="line"><span class="tok-7cc4ff">Need</span><span class="tok-9fd88a"> to</span><span class="tok-9fd88a"> write</span><span class="tok-9fd88a"> file</span><span class="tok-f2b56b"> 2</span></span>
<span class="line"><span class="tok-7cc4ff">Need</span><span class="tok-9fd88a"> to</span><span class="tok-9fd88a"> write</span><span class="tok-9fd88a"> file</span><span class="tok-f2b56b"> 3</span></span>
<span class="line"><span class="tok-7cc4ff">Need</span><span class="tok-9fd88a"> to</span><span class="tok-9fd88a"> write</span><span class="tok-9fd88a"> file</span><span class="tok-f2b56b"> 4</span></span>
<span class="line"><span class="tok-7cc4ff">Need</span><span class="tok-9fd88a"> to</span><span class="tok-9fd88a"> write</span><span class="tok-9fd88a"> file</span><span class="tok-f2b56b"> 5</span></span>
<span class="line"><span class="tok-7cc4ff">Need</span><span class="tok-9fd88a"> to</span><span class="tok-9fd88a"> write</span><span class="tok-9fd88a"> file</span><span class="tok-f2b56b"> 6</span></span>
<span class="line"><span class="tok-7cc4ff">Need</span><span class="tok-9fd88a"> to</span><span class="tok-9fd88a"> write</span><span class="tok-9fd88a"> file</span><span class="tok-f2b56b"> 7</span></span>
<span class="line"><span class="tok-7cc4ff">Need</span><span class="tok-9fd88a"> to</span><span class="tok-9fd88a"> write</span><span class="tok-9fd88a"> file</span><span class="tok-f2b56b"> 8</span></span>
<span class="line"><span class="tok-7cc4ff">Need</span><span class="tok-9fd88a"> to</span><span class="tok-9fd88a"> write</span><span class="tok-9fd88a"> file</span><span class="tok-f2b56b"> 9</span></span>
<span class="line"><span class="tok-7cc4ff">Need</span><span class="tok-9fd88a"> to</span><span class="tok-9fd88a"> write</span><span class="tok-9fd88a"> file</span><span class="tok-f2b56b"> 10</span></span>
<span class="line"><span class="tok-7cc4ff">Need</span><span class="tok-9fd88a"> to</span><span class="tok-9fd88a"> write</span><span class="tok-9fd88a"> file</span><span class="tok-f2b56b"> 11</span></span>
<span class="line"><span class="tok-7cc4ff">Need</span><span class="tok-9fd88a"> to</span><span class="tok-9fd88a"> write</span><span class="tok-9fd88a"> file</span><span class="tok-f2b56b"> 12</span></span>
<span class="line"><span class="tok-7cc4ff">Need</span><span class="tok-9fd88a"> to</span><span class="tok-9fd88a"> write</span><span class="tok-9fd88a"> file</span><span class="tok-f2b56b"> 13</span></span>
<span class="line"><span class="tok-7cc4ff">Need</span><span class="tok-9fd88a"> to</span><span class="tok-9fd88a"> write</span><span class="tok-9fd88a"> file</span><span class="tok-f2b56b"> 14</span></span>
<span class="line"><span class="tok-7cc4ff">Need</span><span class="tok-9fd88a"> to</span><span class="tok-9fd88a"> write</span><span class="tok-9fd88a"> file</span><span class="tok-f2b56b"> 15</span></span>
<span class="line"><span class="tok-7cc4ff">Wrote</span><span class="tok-9fd88a"> last</span><span class="tok-9fd88a"> data</span><span class="tok-9fd88a"> file</span><span class="tok-9fd88a"> with</span><span class="tok-f2b56b"> 90273</span><span class="tok-9fd88a"> locations</span></span>
<span class="line"><span class="tok-7cc4ff">$</span><span class="tok-9fd88a"> bc</span><span class="tok-a9b8c8"> &#x3C;&#x3C;&#x3C;</span><span class="tok-9fd88a"> 16</span><span class="tok-a9b8c8">*</span><span class="tok-9fd88a">100000+90273</span></span>
<span class="line"><span class="tok-7cc4ff">1690273</span></span></code></pre>
<p>On retrouve bien nos données séparées, plus qu’à les importer !</p>
<h2 id="import-dans-phonetrack" tabindex="-1"><a class="heading-link" href="#import-dans-phonetrack">Import dans PhoneTrack</a></h2>
<p>Pour cette partie, il vous faudra un accès à votre instance Nextcloud avec l’application PhoneTrack installée, ainsi qu’un accès à sa base de données (client MySQL / MariaDB).</p>
<p>Tout d’abord, voici comment sont organisées les données de PhoneTrack dans la base de données :</p>
<pre class="shiki sylvain-dev"><code class="language-sql"><span class="line"><span class="tok-d6e2ee">MariaDB </span><span class="tok-a9b8c8">[</span><span class="tok-d6e2ee">nextcloud</span><span class="tok-a9b8c8">]></span><span class="tok-d6e2ee"> SHOW TABLES </span><span class="tok-c39bff">WHERE</span><span class="tok-d6e2ee"> Tables_in_nextcloud </span><span class="tok-c39bff">LIKE</span><span class="tok-a9b8c8"> '</span><span class="tok-9fd88a">%phonetrack%</span><span class="tok-a9b8c8">'</span><span class="tok-d6e2ee">;</span></span>
<span class="line"><span class="tok-a9b8c8">+</span><span class="tok-8396ab tok-italic">-----------------------+</span></span>
<span class="line"><span class="tok-d6e2ee">| Tables_in_nextcloud      |</span></span>
<span class="line"><span class="tok-a9b8c8">+</span><span class="tok-8396ab tok-italic">--------------------------+</span></span>
<span class="line"><span class="tok-d6e2ee">| oc_phonetrack_devices    |</span></span>
<span class="line"><span class="tok-d6e2ee">| oc_phonetrack_filtersb   |</span></span>
<span class="line"><span class="tok-d6e2ee">| oc_phonetrack_geofences  |</span></span>
<span class="line"><span class="tok-d6e2ee">| oc_phonetrack_points     |</span></span>
<span class="line"><span class="tok-d6e2ee">| oc_phonetrack_proxims    |</span></span>
<span class="line"><span class="tok-d6e2ee">| oc_phonetrack_pubshares  |</span></span>
<span class="line"><span class="tok-d6e2ee">| oc_phonetrack_sessions   |</span></span>
<span class="line"><span class="tok-d6e2ee">| oc_phonetrack_shares     |</span></span>
<span class="line"><span class="tok-d6e2ee">| oc_phonetrack_tileserver |</span></span>
<span class="line"><span class="tok-a9b8c8">+</span><span class="tok-8396ab tok-italic">--------------------------+</span></span></code></pre>
<p>Je ne vais pas rentrer dans les détails, mais voici la compréhension que j’ai de comment sont structurées les données dans PhoneTrack :</p>
<p>Un <code>device</code> est un appareil qui envoie des points de localisation (<code>points</code>). Chaque <code>device</code> appartient à une <code>session</code>, et une session peut contenir plusieurs <code>device</code>. Vous trouverez des détails ici si cela vous intéresse : <a href="https://gitlab.com/eneiluj/phonetrack-oc/-/wikis/home">Wiki PhoneTrack - Gitlab</a></p>
<p>Problème : PhoneTrack ne permet pas de fusionner deux devices depuis l’interface (<a href="https://gitlab.com/eneiluj/phonetrack-oc/-/issues/377">une issue</a> le demandait d’ailleurs). Or, chaque fichier s’importe comme une nouvelle session, avec son propre device. Le plan est donc le suivant :</p>
<ol>
<li>importer chaque fichier depuis l’interface de PhoneTrack (une session par fichier) ;</li>
<li>créer un device dédié, <code>google_location</code>, qui accueillera tout l’historique ;</li>
<li>déplacer en base les points de chaque device importé vers ce device ;</li>
<li>supprimer les sessions de l’import, devenues vides.</li>
</ol>
<div class="callout callout-warning" role="note">
<p class="callout-title">Attention</p>
<p>On modifie directement la base de Nextcloud : pensez à faire une sauvegarde avant de vous lancer.</p>
</div>
<p>Une fois les imports terminés, voici les devices présents (<code>myPhone</code> et <code>myPhone2</code> sont mes téléphones, les autres viennent de l’import) :</p>
<pre class="shiki sylvain-dev"><code class="language-sql"><span class="line"><span class="tok-d6e2ee">MariaDB </span><span class="tok-a9b8c8">[</span><span class="tok-d6e2ee">nextcloud</span><span class="tok-a9b8c8">]></span><span class="tok-c39bff"> SELECT</span><span class="tok-a9b8c8"> *</span><span class="tok-c39bff"> FROM</span><span class="tok-d6e2ee"> oc_phonetrack_devices;</span></span>
<span class="line"><span class="tok-a9b8c8">+</span><span class="tok-8396ab tok-italic">----+------------------+-------+----------------------------------+---------+-------+----------------------------------+</span></span>
<span class="line"><span class="tok-d6e2ee">| id | </span><span class="tok-c39bff">name</span><span class="tok-d6e2ee">             | alias | sessionid                        | color   | shape | nametoken                        |</span></span>
<span class="line"><span class="tok-a9b8c8">+</span><span class="tok-8396ab tok-italic">----+------------------+-------+----------------------------------+---------+-------+----------------------------------+</span></span>
<span class="line"><span class="tok-d6e2ee">|  </span><span class="tok-f2b56b">5</span><span class="tok-d6e2ee"> | myPhone          | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">  | redacted_for_privacy             | #3ea8fa | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">  | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">                             |</span></span>
<span class="line"><span class="tok-d6e2ee">|  </span><span class="tok-f2b56b">8</span><span class="tok-d6e2ee"> | myPhone2         | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">  | redacted_for_privacy             | #ff0001 | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">  | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">                             |</span></span>
<span class="line"><span class="tok-d6e2ee">|  </span><span class="tok-f2b56b">9</span><span class="tok-d6e2ee"> | google1          | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">  | redacted_for_privacy             | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">    | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">  | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">                             |</span></span>
<span class="line"><span class="tok-d6e2ee">| </span><span class="tok-f2b56b">10</span><span class="tok-d6e2ee"> | google10         | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">  | redacted_for_privacy             | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">    | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">  | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">                             |</span></span>
<span class="line"><span class="tok-d6e2ee">| </span><span class="tok-f2b56b">11</span><span class="tok-d6e2ee"> | google11         | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">  | redacted_for_privacy             | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">    | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">  | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">                             |</span></span>
<span class="line"><span class="tok-d6e2ee">| </span><span class="tok-f2b56b">12</span><span class="tok-d6e2ee"> | google12         | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">  | redacted_for_privacy             | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">    | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">  | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">                             |</span></span>
<span class="line"><span class="tok-d6e2ee">| </span><span class="tok-f2b56b">13</span><span class="tok-d6e2ee"> | google13         | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">  | redacted_for_privacy             | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">    | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">  | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">                             |</span></span>
<span class="line"><span class="tok-d6e2ee">| </span><span class="tok-f2b56b">14</span><span class="tok-d6e2ee"> | google14         | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">  | redacted_for_privacy             | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">    | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">  | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">                             |</span></span>
<span class="line"><span class="tok-d6e2ee">| </span><span class="tok-f2b56b">15</span><span class="tok-d6e2ee"> | google15         | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">  | redacted_for_privacy             | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">    | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">  | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">                             |</span></span>
<span class="line"><span class="tok-d6e2ee">| </span><span class="tok-f2b56b">16</span><span class="tok-d6e2ee"> | google16         | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">  | redacted_for_privacy             | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">    | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">  | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">                             |</span></span>
<span class="line"><span class="tok-d6e2ee">| </span><span class="tok-f2b56b">17</span><span class="tok-d6e2ee"> | g2               | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">  | redacted_for_privacy             | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">    | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">  | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">                             |</span></span>
<span class="line"><span class="tok-d6e2ee">| </span><span class="tok-f2b56b">18</span><span class="tok-d6e2ee"> | g3               | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">  | redacted_for_privacy             | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">    | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">  | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">                             |</span></span>
<span class="line"><span class="tok-d6e2ee">| </span><span class="tok-f2b56b">19</span><span class="tok-d6e2ee"> | g4               | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">  | redacted_for_privacy             | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">    | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">  | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">                             |</span></span>
<span class="line"><span class="tok-d6e2ee">| </span><span class="tok-f2b56b">20</span><span class="tok-d6e2ee"> | g5               | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">  | redacted_for_privacy             | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">    | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">  | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">                             |</span></span>
<span class="line"><span class="tok-d6e2ee">| </span><span class="tok-f2b56b">21</span><span class="tok-d6e2ee"> | g6               | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">  | redacted_for_privacy             | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">    | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">  | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">                             |</span></span>
<span class="line"><span class="tok-d6e2ee">| </span><span class="tok-f2b56b">22</span><span class="tok-d6e2ee"> | g7               | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">  | redacted_for_privacy             | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">    | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">  | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">                             |</span></span>
<span class="line"><span class="tok-d6e2ee">| </span><span class="tok-f2b56b">23</span><span class="tok-d6e2ee"> | g8               | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">  | redacted_for_privacy             | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">    | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">  | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">                             |</span></span>
<span class="line"><span class="tok-d6e2ee">| </span><span class="tok-f2b56b">24</span><span class="tok-d6e2ee"> | g9               | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">  | redacted_for_privacy             | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">    | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">  | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">                             |</span></span>
<span class="line"><span class="tok-d6e2ee">| </span><span class="tok-f2b56b">25</span><span class="tok-d6e2ee"> | glast            | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">  | redacted_for_privacy             | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">    | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">  | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">                             |</span></span>
<span class="line"><span class="tok-d6e2ee">| </span><span class="tok-f2b56b">26</span><span class="tok-d6e2ee"> | google_location  | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">  | redacted_for_privacy             | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">    | </span><span class="tok-c39bff">NULL</span><span class="tok-d6e2ee">  | redacted_for_privacy             |</span></span>
<span class="line"><span class="tok-a9b8c8">+</span><span class="tok-8396ab tok-italic">----+------------------+-------+----------------------------------+---------+-------+----------------------------------+</span></span>
<span class="line"><span class="tok-f2b56b">20</span><span class="tok-c39bff"> rows</span><span class="tok-c39bff"> in</span><span class="tok-c39bff"> set</span><span class="tok-d6e2ee"> (</span><span class="tok-f2b56b">0</span><span class="tok-d6e2ee">.</span><span class="tok-f2b56b">001</span><span class="tok-d6e2ee"> sec)</span></span>
<span class="line"></span>
<span class="line"><span class="tok-d6e2ee">MariaDB </span><span class="tok-a9b8c8">[</span><span class="tok-d6e2ee">nextcloud</span><span class="tok-a9b8c8">]></span><span class="tok-c39bff"> SELECT</span><span class="tok-7cc4ff"> COUNT</span><span class="tok-d6e2ee">(</span><span class="tok-a9b8c8">*</span><span class="tok-d6e2ee">) </span><span class="tok-c39bff">FROM</span><span class="tok-d6e2ee"> oc_phonetrack_points </span><span class="tok-c39bff">WHERE</span><span class="tok-d6e2ee"> deviceid </span><span class="tok-c39bff">NOT</span><span class="tok-c39bff"> IN</span><span class="tok-d6e2ee">(</span><span class="tok-f2b56b">5</span><span class="tok-d6e2ee">,</span><span class="tok-f2b56b">8</span><span class="tok-d6e2ee">);</span></span>
<span class="line"><span class="tok-a9b8c8">+</span><span class="tok-8396ab tok-italic">----------+</span></span>
<span class="line"><span class="tok-d6e2ee">| </span><span class="tok-7cc4ff">COUNT</span><span class="tok-d6e2ee">(</span><span class="tok-a9b8c8">*</span><span class="tok-d6e2ee">) |</span></span>
<span class="line"><span class="tok-a9b8c8">+</span><span class="tok-8396ab tok-italic">----------+</span></span>
<span class="line"><span class="tok-d6e2ee">|  </span><span class="tok-f2b56b">1690271</span><span class="tok-d6e2ee"> |</span></span>
<span class="line"><span class="tok-a9b8c8">+</span><span class="tok-8396ab tok-italic">----------+</span></span>
<span class="line"><span class="tok-f2b56b">1</span><span class="tok-c39bff"> row</span><span class="tok-c39bff"> in</span><span class="tok-c39bff"> set</span><span class="tok-d6e2ee"> (</span><span class="tok-f2b56b">1</span><span class="tok-d6e2ee">.</span><span class="tok-f2b56b">154</span><span class="tok-d6e2ee"> sec)</span></span></code></pre>
<p>À quelques points près, on retrouve bien tous nos points importés en base. 🎉</p>
<p>Reste maintenant à les regrouper dans un seul device. Voici le nombre de points par device :</p>
<pre class="shiki sylvain-dev"><code class="language-sql"><span class="line"><span class="tok-d6e2ee">MariaDB </span><span class="tok-a9b8c8">[</span><span class="tok-d6e2ee">nextcloud</span><span class="tok-a9b8c8">]></span><span class="tok-c39bff"> SELECT</span><span class="tok-c39bff"> name</span><span class="tok-d6e2ee">, d.id </span><span class="tok-c39bff">as</span><span class="tok-d6e2ee"> deviceid, </span><span class="tok-7cc4ff">COUNT</span><span class="tok-d6e2ee">(p.id) </span><span class="tok-c39bff">as</span><span class="tok-d6e2ee"> points </span><span class="tok-c39bff">FROM</span><span class="tok-d6e2ee"> oc_phonetrack_points p </span><span class="tok-c39bff">RIGHT JOIN</span><span class="tok-d6e2ee"> oc_phonetrack_devices d </span><span class="tok-c39bff">ON</span><span class="tok-d6e2ee"> p.deviceid </span><span class="tok-a9b8c8">=</span><span class="tok-d6e2ee"> d.id </span><span class="tok-c39bff">GROUP BY</span><span class="tok-d6e2ee"> deviceid, </span><span class="tok-c39bff">name</span><span class="tok-d6e2ee">;</span></span>
<span class="line"><span class="tok-a9b8c8">+</span><span class="tok-8396ab tok-italic">------------------+----------+----------+</span></span>
<span class="line"><span class="tok-d6e2ee">| </span><span class="tok-c39bff">name</span><span class="tok-d6e2ee">             | deviceid | points   |</span></span>
<span class="line"><span class="tok-a9b8c8">+</span><span class="tok-8396ab tok-italic">------------------+----------+----------+</span></span>
<span class="line"><span class="tok-d6e2ee">| google1          |        </span><span class="tok-f2b56b">9</span><span class="tok-d6e2ee"> |        </span><span class="tok-f2b56b">1</span><span class="tok-d6e2ee"> |</span></span>
<span class="line"><span class="tok-d6e2ee">| myPhone          |        </span><span class="tok-f2b56b">5</span><span class="tok-d6e2ee"> |     </span><span class="tok-f2b56b">3162</span><span class="tok-d6e2ee"> |</span></span>
<span class="line"><span class="tok-d6e2ee">| myPhone2         |        </span><span class="tok-f2b56b">8</span><span class="tok-d6e2ee"> |   </span><span class="tok-f2b56b">218854</span><span class="tok-d6e2ee"> |</span></span>
<span class="line"><span class="tok-d6e2ee">| google10         |       </span><span class="tok-f2b56b">10</span><span class="tok-d6e2ee"> |   </span><span class="tok-f2b56b">100000</span><span class="tok-d6e2ee"> |</span></span>
<span class="line"><span class="tok-d6e2ee">| google11         |       </span><span class="tok-f2b56b">11</span><span class="tok-d6e2ee"> |   </span><span class="tok-f2b56b">100000</span><span class="tok-d6e2ee"> |</span></span>
<span class="line"><span class="tok-d6e2ee">| google12         |       </span><span class="tok-f2b56b">12</span><span class="tok-d6e2ee"> |   </span><span class="tok-f2b56b">100000</span><span class="tok-d6e2ee"> |</span></span>
<span class="line"><span class="tok-d6e2ee">| google13         |       </span><span class="tok-f2b56b">13</span><span class="tok-d6e2ee"> |   </span><span class="tok-f2b56b">100000</span><span class="tok-d6e2ee"> |</span></span>
<span class="line"><span class="tok-d6e2ee">| google14         |       </span><span class="tok-f2b56b">14</span><span class="tok-d6e2ee"> |   </span><span class="tok-f2b56b">100000</span><span class="tok-d6e2ee"> |</span></span>
<span class="line"><span class="tok-d6e2ee">| google15         |       </span><span class="tok-f2b56b">15</span><span class="tok-d6e2ee"> |   </span><span class="tok-f2b56b">100000</span><span class="tok-d6e2ee"> |</span></span>
<span class="line"><span class="tok-d6e2ee">| google16         |       </span><span class="tok-f2b56b">16</span><span class="tok-d6e2ee"> |   </span><span class="tok-f2b56b">100000</span><span class="tok-d6e2ee"> |</span></span>
<span class="line"><span class="tok-d6e2ee">| g2               |       </span><span class="tok-f2b56b">17</span><span class="tok-d6e2ee"> |   </span><span class="tok-f2b56b">100000</span><span class="tok-d6e2ee"> |</span></span>
<span class="line"><span class="tok-d6e2ee">| g3               |       </span><span class="tok-f2b56b">18</span><span class="tok-d6e2ee"> |    </span><span class="tok-f2b56b">99998</span><span class="tok-d6e2ee"> |</span></span>
<span class="line"><span class="tok-d6e2ee">| g4               |       </span><span class="tok-f2b56b">19</span><span class="tok-d6e2ee"> |   </span><span class="tok-f2b56b">100000</span><span class="tok-d6e2ee"> |</span></span>
<span class="line"><span class="tok-d6e2ee">| g5               |       </span><span class="tok-f2b56b">20</span><span class="tok-d6e2ee"> |   </span><span class="tok-f2b56b">100000</span><span class="tok-d6e2ee"> |</span></span>
<span class="line"><span class="tok-d6e2ee">| g6               |       </span><span class="tok-f2b56b">21</span><span class="tok-d6e2ee"> |   </span><span class="tok-f2b56b">100000</span><span class="tok-d6e2ee"> |</span></span>
<span class="line"><span class="tok-d6e2ee">| g7               |       </span><span class="tok-f2b56b">22</span><span class="tok-d6e2ee"> |   </span><span class="tok-f2b56b">100000</span><span class="tok-d6e2ee"> |</span></span>
<span class="line"><span class="tok-d6e2ee">| g8               |       </span><span class="tok-f2b56b">23</span><span class="tok-d6e2ee"> |   </span><span class="tok-f2b56b">100000</span><span class="tok-d6e2ee"> |</span></span>
<span class="line"><span class="tok-d6e2ee">| g9               |       </span><span class="tok-f2b56b">24</span><span class="tok-d6e2ee"> |   </span><span class="tok-f2b56b">100000</span><span class="tok-d6e2ee"> |</span></span>
<span class="line"><span class="tok-d6e2ee">| glast            |       </span><span class="tok-f2b56b">25</span><span class="tok-d6e2ee"> |    </span><span class="tok-f2b56b">90273</span><span class="tok-d6e2ee"> |</span></span>
<span class="line"><span class="tok-d6e2ee">| google_location  |       </span><span class="tok-f2b56b">26</span><span class="tok-d6e2ee"> |   </span><span class="tok-f2b56b">100000</span><span class="tok-d6e2ee"> |</span></span>
<span class="line"><span class="tok-a9b8c8">+</span><span class="tok-8396ab tok-italic">------------------+----------+----------+</span></span>
<span class="line"><span class="tok-f2b56b">20</span><span class="tok-c39bff"> rows</span><span class="tok-c39bff"> in</span><span class="tok-c39bff"> set</span><span class="tok-d6e2ee">, </span><span class="tok-f2b56b">1</span><span class="tok-d6e2ee"> warning (</span><span class="tok-f2b56b">1</span><span class="tok-d6e2ee">.</span><span class="tok-f2b56b">552</span><span class="tok-d6e2ee"> sec)</span></span></code></pre>
<p>Pour chaque device de l’import, on rattache ses points au device <code>google_location</code> (ici, l’id <code>26</code>). Un point appartient à un device, et un device à une session : en changeant le <code>deviceid</code> des points, ils rejoignent donc aussi la session de <code>google_location</code>.</p>
<pre class="shiki sylvain-dev"><code class="language-sql"><span class="line"><span class="tok-d6e2ee">MariaDB </span><span class="tok-a9b8c8">[</span><span class="tok-d6e2ee">nextcloud</span><span class="tok-a9b8c8">]></span><span class="tok-c39bff"> UPDATE</span><span class="tok-d6e2ee"> oc_phonetrack_points </span><span class="tok-c39bff">SET</span><span class="tok-d6e2ee"> deviceid</span><span class="tok-a9b8c8">=</span><span class="tok-f2b56b">26</span><span class="tok-c39bff"> WHERE</span><span class="tok-d6e2ee"> deviceid </span><span class="tok-a9b8c8">=</span><span class="tok-f2b56b"> 10</span><span class="tok-d6e2ee">;</span></span>
<span class="line"><span class="tok-d6e2ee">Query OK, </span><span class="tok-f2b56b">100000</span><span class="tok-c39bff"> rows</span><span class="tok-d6e2ee"> affected (</span><span class="tok-f2b56b">21</span><span class="tok-d6e2ee">.</span><span class="tok-f2b56b">417</span><span class="tok-d6e2ee"> sec)</span></span>
<span class="line"><span class="tok-c39bff">Rows</span><span class="tok-c39bff"> matched</span><span class="tok-d6e2ee">: </span><span class="tok-f2b56b">100000</span><span class="tok-d6e2ee">  Changed: </span><span class="tok-f2b56b">100000</span><span class="tok-d6e2ee">  Warnings: </span><span class="tok-f2b56b">0</span></span></code></pre>
<p>Une vingtaine de secondes par device, à répéter pour chacun d’eux. Une fois tous les devices traités :</p>
<pre class="shiki sylvain-dev"><code class="language-sql"><span class="line"><span class="tok-d6e2ee">MariaDB </span><span class="tok-a9b8c8">[</span><span class="tok-d6e2ee">nextcloud</span><span class="tok-a9b8c8">]></span><span class="tok-c39bff"> SELECT</span><span class="tok-c39bff"> name</span><span class="tok-d6e2ee">, d.id </span><span class="tok-c39bff">as</span><span class="tok-d6e2ee"> deviceid, </span><span class="tok-7cc4ff">COUNT</span><span class="tok-d6e2ee">(p.id) </span><span class="tok-c39bff">as</span><span class="tok-d6e2ee"> points </span><span class="tok-c39bff">FROM</span><span class="tok-d6e2ee"> oc_phonetrack_points p </span><span class="tok-c39bff">RIGHT JOIN</span><span class="tok-d6e2ee"> oc_phonetrack_devices d </span><span class="tok-c39bff">ON</span><span class="tok-d6e2ee"> p.deviceid </span><span class="tok-a9b8c8">=</span><span class="tok-d6e2ee"> d.id </span><span class="tok-c39bff">GROUP BY</span><span class="tok-d6e2ee"> deviceid, </span><span class="tok-c39bff">name</span><span class="tok-d6e2ee">;</span></span>
<span class="line"><span class="tok-a9b8c8">+</span><span class="tok-8396ab tok-italic">------------------+----------+---------+</span></span>
<span class="line"><span class="tok-d6e2ee">| </span><span class="tok-c39bff">name</span><span class="tok-d6e2ee">             | deviceid | points  |</span></span>
<span class="line"><span class="tok-a9b8c8">+</span><span class="tok-8396ab tok-italic">------------------+----------+---------+</span></span>
<span class="line"><span class="tok-d6e2ee">| g2               |       </span><span class="tok-f2b56b">17</span><span class="tok-d6e2ee"> |       </span><span class="tok-f2b56b">0</span><span class="tok-d6e2ee"> |</span></span>
<span class="line"><span class="tok-d6e2ee">| g3               |       </span><span class="tok-f2b56b">18</span><span class="tok-d6e2ee"> |       </span><span class="tok-f2b56b">0</span><span class="tok-d6e2ee"> |</span></span>
<span class="line"><span class="tok-d6e2ee">| g4               |       </span><span class="tok-f2b56b">19</span><span class="tok-d6e2ee"> |       </span><span class="tok-f2b56b">0</span><span class="tok-d6e2ee"> |</span></span>
<span class="line"><span class="tok-d6e2ee">| g5               |       </span><span class="tok-f2b56b">20</span><span class="tok-d6e2ee"> |       </span><span class="tok-f2b56b">0</span><span class="tok-d6e2ee"> |</span></span>
<span class="line"><span class="tok-d6e2ee">| g6               |       </span><span class="tok-f2b56b">21</span><span class="tok-d6e2ee"> |       </span><span class="tok-f2b56b">0</span><span class="tok-d6e2ee"> |</span></span>
<span class="line"><span class="tok-d6e2ee">| g7               |       </span><span class="tok-f2b56b">22</span><span class="tok-d6e2ee"> |       </span><span class="tok-f2b56b">0</span><span class="tok-d6e2ee"> |</span></span>
<span class="line"><span class="tok-d6e2ee">| g8               |       </span><span class="tok-f2b56b">23</span><span class="tok-d6e2ee"> |       </span><span class="tok-f2b56b">0</span><span class="tok-d6e2ee"> |</span></span>
<span class="line"><span class="tok-d6e2ee">| g9               |       </span><span class="tok-f2b56b">24</span><span class="tok-d6e2ee"> |       </span><span class="tok-f2b56b">0</span><span class="tok-d6e2ee"> |</span></span>
<span class="line"><span class="tok-d6e2ee">| glast            |       </span><span class="tok-f2b56b">25</span><span class="tok-d6e2ee"> |       </span><span class="tok-f2b56b">0</span><span class="tok-d6e2ee"> |</span></span>
<span class="line"><span class="tok-d6e2ee">| google10         |       </span><span class="tok-f2b56b">10</span><span class="tok-d6e2ee"> |       </span><span class="tok-f2b56b">0</span><span class="tok-d6e2ee"> |</span></span>
<span class="line"><span class="tok-d6e2ee">| google11         |       </span><span class="tok-f2b56b">11</span><span class="tok-d6e2ee"> |       </span><span class="tok-f2b56b">0</span><span class="tok-d6e2ee"> |</span></span>
<span class="line"><span class="tok-d6e2ee">| google12         |       </span><span class="tok-f2b56b">12</span><span class="tok-d6e2ee"> |       </span><span class="tok-f2b56b">0</span><span class="tok-d6e2ee"> |</span></span>
<span class="line"><span class="tok-d6e2ee">| google13         |       </span><span class="tok-f2b56b">13</span><span class="tok-d6e2ee"> |       </span><span class="tok-f2b56b">0</span><span class="tok-d6e2ee"> |</span></span>
<span class="line"><span class="tok-d6e2ee">| google14         |       </span><span class="tok-f2b56b">14</span><span class="tok-d6e2ee"> |       </span><span class="tok-f2b56b">0</span><span class="tok-d6e2ee"> |</span></span>
<span class="line"><span class="tok-d6e2ee">| google15         |       </span><span class="tok-f2b56b">15</span><span class="tok-d6e2ee"> |       </span><span class="tok-f2b56b">0</span><span class="tok-d6e2ee"> |</span></span>
<span class="line"><span class="tok-d6e2ee">| google16         |       </span><span class="tok-f2b56b">16</span><span class="tok-d6e2ee"> |       </span><span class="tok-f2b56b">0</span><span class="tok-d6e2ee"> |</span></span>
<span class="line"><span class="tok-d6e2ee">| myPhone          |        </span><span class="tok-f2b56b">5</span><span class="tok-d6e2ee"> |    </span><span class="tok-f2b56b">3162</span><span class="tok-d6e2ee"> |</span></span>
<span class="line"><span class="tok-d6e2ee">| myPhone2         |        </span><span class="tok-f2b56b">8</span><span class="tok-d6e2ee"> |  </span><span class="tok-f2b56b">218854</span><span class="tok-d6e2ee"> |</span></span>
<span class="line"><span class="tok-d6e2ee">| google_location  |       </span><span class="tok-f2b56b">26</span><span class="tok-d6e2ee"> | </span><span class="tok-f2b56b">1690271</span><span class="tok-d6e2ee"> |</span></span>
<span class="line"><span class="tok-a9b8c8">+</span><span class="tok-8396ab tok-italic">------------------+----------+---------+</span></span>
<span class="line"><span class="tok-f2b56b">19</span><span class="tok-c39bff"> rows</span><span class="tok-c39bff"> in</span><span class="tok-c39bff"> set</span><span class="tok-d6e2ee">, </span><span class="tok-f2b56b">1</span><span class="tok-d6e2ee"> warning (</span><span class="tok-f2b56b">1</span><span class="tok-d6e2ee">.</span><span class="tok-f2b56b">820</span><span class="tok-d6e2ee"> sec)</span></span></code></pre>
<p>Tous les points sont désormais rattachés à <code>google_location</code>. Il ne reste plus qu’à supprimer les sessions de l’import, désormais vides, depuis l’interface de PhoneTrack (en prenant soin de garder celle qui contient <code>google_location</code> !), et à profiter de quelques années d’historique sur sa propre instance :)</p>
<div class="callout callout-tip" role="note">
<p class="callout-title">Astuce</p>
<p>Afficher beaucoup de points d’un coup peut faire planter PhoneTrack : pensez à utiliser les filtres (par date notamment) lorsque vous consultez vos données.</p>
</div>

    ]]>
      </content>
      
        <category term="google"/>
      
        <category term="nextcloud"/>
      
      
        <summary type="html">
          J&#39;ai utilisé l&#39;historique de localisation de Google de 2011 à 2018. Voici comment j&#39;ai récupéré ces données dans PhoneTrack, sur mon instance Nextcloud.
        </summary>
      
    </entry>
  
    
    <entry>
      <title>Récupérer les dumps SQL depuis une instance MySQL/MariaDB qui ne démarre plus</title>
      <link href="https://www.sylvain.dev/article/recuperer-donnees-mysql/"/>
      <published>2021-05-04T00:00:00Z</published>
      <updated>2021-05-04T00:00:00Z</updated>
      <id>https://sylvain.dev/article/recuperer-donnees-mysql/</id>
      <content type="html">
        <![CDATA[
      <p>Suite à une mise à jour de mon raspberry pi qui s’est plus ou moins bien passée, ma base de données MariaDB ne démarrait plus, indiquant une erreur suite à la mise à jour. J’avais donc un MySQL qui refusait de démarrer, et bien sûr, pas de backup !</p>
<p>Néanmoins, je disposais quand même du dossier <code>/var/lib/mysql</code> qui semblait intact. J’ai donc fait un tar.gz du dossier avant de le récupérer en local pour voir ce que je pouvais en faire.</p>
<pre class="shiki sylvain-dev"><code class="language-bash"><span class="line"><span class="tok-8396ab tok-italic"># on créé le tar.gz sur le serveur</span></span>
<span class="line"><span class="tok-7cc4ff">$</span><span class="tok-9fd88a"> sudo</span><span class="tok-9fd88a"> tar</span><span class="tok-9fd88a"> -zcvf</span><span class="tok-9fd88a"> ~/mysql.tar.gz</span><span class="tok-9fd88a"> /var/lib/mysql</span></span>
<span class="line"><span class="tok-8396ab tok-italic"># on le récupère en local</span></span>
<span class="line"><span class="tok-7cc4ff">$</span><span class="tok-9fd88a"> scp</span><span class="tok-9fd88a"> pi:~mysql.tar.gz</span><span class="tok-9fd88a"> .</span></span></code></pre>
<p>Une fois cela fait, j’ai utilisé Docker et l’image mariadb (dans la version 10.3, qui était celle utilisée sur mon serveur pour éviter toute incompatibilité) pour pouvoir lancer une instance locale de mariadb, avec les données récupérées précédemment.</p>
<pre class="shiki sylvain-dev"><code class="language-bash"><span class="line"><span class="tok-8396ab tok-italic"># Extraction du tar.gz</span></span>
<span class="line"><span class="tok-7cc4ff">$</span><span class="tok-9fd88a"> tar</span><span class="tok-9fd88a"> -xzvf</span><span class="tok-9fd88a"> mysql.tar.gz</span></span>
<span class="line"><span class="tok-7cc4ff">$</span><span class="tok-9fd88a"> cd</span><span class="tok-9fd88a"> var/lib</span></span>
<span class="line"><span class="tok-8396ab tok-italic"># J'aurais besoin de ce dossier pour récupérer mes dump SQL plus tard</span></span>
<span class="line"><span class="tok-7cc4ff">$</span><span class="tok-9fd88a"> mkdir</span><span class="tok-9fd88a"> backup</span></span>
<span class="line"></span>
<span class="line"><span class="tok-7cc4ff">$</span><span class="tok-9fd88a"> docker</span><span class="tok-9fd88a"> run</span><span class="tok-9fd88a"> --name</span><span class="tok-9fd88a"> restore_mariadb</span><span class="tok-9fd88a"> -v</span><span class="tok-a9b8c8"> $(</span><span class="tok-7cc4ff">pwd</span><span class="tok-a9b8c8">)</span><span class="tok-9fd88a">/data:/var/lib/mysql</span><span class="tok-9fd88a"> -v</span><span class="tok-a9b8c8"> $(</span><span class="tok-7cc4ff">pwd</span><span class="tok-a9b8c8">)</span><span class="tok-9fd88a">:/backup</span><span class="tok-9fd88a"> -e</span><span class="tok-9fd88a"> MYSQL_ROOT_PASSWORD=root</span><span class="tok-9fd88a"> -d</span><span class="tok-9fd88a"> mariadb:10.3</span></span></code></pre>
<p>La variable d’environnement est nécessaire sinon l’image ne démarrera pas, mais il faut bien garder en tête qu’il faudra indiquer le mot de passe de votre instance MySQL telle qu’elle était sur votre serveur.</p>
<p>Une fois cela fait, il suffit de lancer la commande suivante pour se connecter au conteneur :</p>
<pre class="shiki sylvain-dev"><code class="language-bash"><span class="line"><span class="tok-7cc4ff">$</span><span class="tok-9fd88a"> docker</span><span class="tok-9fd88a"> exec</span><span class="tok-9fd88a"> -it</span><span class="tok-9fd88a"> restore_mariadb</span><span class="tok-9fd88a"> bash</span></span>
<span class="line"><span class="tok-7cc4ff">root@e11929a58f8b:/#</span><span class="tok-9fd88a"> mysql</span><span class="tok-9fd88a"> -u</span><span class="tok-9fd88a"> root</span><span class="tok-9fd88a"> -p</span></span>
<span class="line"><span class="tok-7cc4ff">Enter</span><span class="tok-9fd88a"> password:</span></span>
<span class="line"><span class="tok-7cc4ff">Welcome</span><span class="tok-9fd88a"> to</span><span class="tok-9fd88a"> the</span><span class="tok-9fd88a"> MariaDB</span><span class="tok-9fd88a"> monitor.</span><span class="tok-9fd88a">  Commands</span><span class="tok-9fd88a"> end</span><span class="tok-9fd88a"> with</span><span class="tok-a9b8c8"> ;</span><span class="tok-7cc4ff"> or</span><span class="tok-f2b56b"> \g</span><span class="tok-9fd88a">.</span></span>
<span class="line"><span class="tok-7cc4ff">Your</span><span class="tok-9fd88a"> MariaDB</span><span class="tok-9fd88a"> connection</span><span class="tok-9fd88a"> id</span><span class="tok-9fd88a"> is</span><span class="tok-f2b56b"> 8</span></span>
<span class="line"><span class="tok-7cc4ff">Server</span><span class="tok-9fd88a"> version:</span><span class="tok-9fd88a"> 10.3.23-MariaDB-1:10.3.23+maria~focal</span><span class="tok-9fd88a"> mariadb.org</span><span class="tok-9fd88a"> binary</span><span class="tok-9fd88a"> distribution</span></span>
<span class="line"></span>
<span class="line"><span class="tok-7cc4ff">Copyright</span><span class="tok-d6e2ee"> (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.</span></span>
<span class="line"></span>
<span class="line"><span class="tok-7cc4ff">Type</span><span class="tok-a9b8c8"> '</span><span class="tok-9fd88a">help;</span><span class="tok-a9b8c8">'</span><span class="tok-9fd88a"> or</span><span class="tok-a9b8c8"> '</span><span class="tok-9fd88a">\h</span><span class="tok-a9b8c8">'</span><span class="tok-9fd88a"> for</span><span class="tok-9fd88a"> help.</span><span class="tok-9fd88a"> Type</span><span class="tok-a9b8c8"> '</span><span class="tok-9fd88a">\c</span><span class="tok-a9b8c8">'</span><span class="tok-9fd88a"> to</span><span class="tok-9fd88a"> clear</span><span class="tok-9fd88a"> the</span><span class="tok-9fd88a"> current</span><span class="tok-9fd88a"> input</span><span class="tok-9fd88a"> statement.</span></span>
<span class="line"></span>
<span class="line"><span class="tok-7cc4ff">MariaDB</span><span class="tok-d6e2ee"> [(none)]</span><span class="tok-a9b8c8">></span></span></code></pre>
<p>Et enfin, on peut faire des mysqldump et stocker les résultats dans le dossier <code>/backup</code> que l’on a également monté pour pouvoir restaurer les données une fois la base de données de nouveau opérationnelle.</p>
<pre class="shiki sylvain-dev"><code class="language-bash"><span class="line"><span class="tok-7cc4ff">mysqldump</span><span class="tok-9fd88a"> -u</span><span class="tok-9fd88a"> root</span><span class="tok-9fd88a"> -p</span><span class="tok-9fd88a"> mabase</span><span class="tok-a9b8c8"> ></span><span class="tok-9fd88a"> /backup/mysql.sql</span></span></code></pre>
<p>En espérant que cela puisse être utile à d’autres !</p>
<blockquote>
<p>Et si jamais vous n’en avez pas de récentes, allez faire une sauvegarde de vos données dès maintenant :)</p>
</blockquote>

    ]]>
      </content>
      
        <category term="mysql"/>
      
      
        <summary type="html">
          Suite à une mise à jour de mon raspberry pi qui s&#39;est plus ou moins bien passée, ma base de données MariaDB ne démarrait plus
        </summary>
      
    </entry>
  
    
    <entry>
      <title>Gestionnaire d&#39;alias d&#39;emails</title>
      <link href="https://www.sylvain.dev/article/email-alias-manager/"/>
      <published>2020-01-27T00:00:00Z</published>
      <updated>2020-01-27T00:00:00Z</updated>
      <id>https://sylvain.dev/article/email-alias-manager/</id>
      <content type="html">
        <![CDATA[
      <p><a href="https://app.netlify.com/start/deploy?repository=https://github.com/sylvainmetayer/alias-gandi-angular"><img src="https://www.netlify.com/img/deploy/button.svg" alt="Deploy to Netlify"></a></p>
<h2 id="l%E2%80%99id%C3%A9e" tabindex="-1"><a class="heading-link" href="#l%E2%80%99id%C3%A9e">L’idée</a></h2>
<p>Trop de spam ? Marre de donner son adresse email à chaque service ? Les alias mail sont là à la rescousse !</p>
<p>Suite à une idée d’<a href="https://web.archive.org/web/20200814055750/https://adrienchinour.me/">Adrien Chinour</a>, j’ai décidé de créer à mon tour un petit gestionnaire d’alias pour mes adresses emails. L’objectif est de pouvoir générer rapidement des alias afin de ne pas donner sa véritable adresse email lors d’inscription sur des sites divers. Ainsi, si l’on constate que le site envoie un peu trop de mail à notre goût, que l’on n’utilise plus le service, ou que réussir à se désinscrire relève du parcours du combattant, on supprime l’alias, et plus de mails indésirables !</p>
<p>Ayant mes domaines gérés par <a href="https://gandi.net">Gandi</a>, j’ai regardé comment interagir avec mes adresses emails pour créer des alias depuis leur <a href="https://api.gandi.net/docs/">API</a>.</p>
<p>Au niveau des technologies utilisées, j’ai utilisé <a href="https://angular.io">Angular</a> et les fonctions serverless de <a href="https://netlify.com">Netlify</a> (en NodeJS) afin de gérer les appels à l’API Gandi.</p>
<p>Le principe est très simple : on s’authentifie avec un mot de passe, prédéfini dans les variables d’environnement des fonctions serverless de Netlify, on obtient un JWT Token signé avec un secret connu seulement par les fonctions serverless, et on peut ensuite considérer que l’on est authentifié. N’ayant pas besoin de gérer plusieurs utilisateurs, cela convient à mon cas d’utilisation.</p>
<p>Une fois authentifié, les fonctions serverless se chargent de récupérer la liste des domaines, ainsi que la liste des boites mails associées à ces domaines et on arrive ensuite sur l’écran suivant, qui nous permet de gérer les alias de chaque boite mail.</p>
<p><img src="/images/alias-email-desktop.png" alt="Rendu bureau : pour chaque boîte mail du domaine, la liste de ses alias avec des boutons Copier et Supprimer, et un champ pour en ajouter un"></p>
<h2 id="la-suite" tabindex="-1"><a class="heading-link" href="#la-suite">La suite</a></h2>
<p>Dans le cas où d’éventuels clients de Gandi souhaiteraient utiliser ce projet, j’ai tenté d’intégrer l’Oauth2, afin de permettre de s’authentifier via Gandi. Cela m’a également permis de comprendre mieux le fonctionnement de l’Oauth2.</p>
<p>J’ai donc demandé la création d’une application, obtenant ainsi un <code>applicationId</code> et un <code>applicationSecret</code> me permettant de mettre en place l’authentification. Afin de tester cela en local, j’ai utilisé un <a href="https://github.com/axa-group/oauth2-mock-server">mock oauth2 réalisé par le groupe AXA</a></p>
<p>Malheureusement, l’API v5 de Gandi est encore en beta et le fournisseur d’authentification ne permet pas encore d’interagir avec les domaines et boites mails. 😢</p>
<p>En attendant que cela soit disponible, j’ai laissé mon travail disponible sur une <a href="https://github.com/sylvainmetayer/alias-gandi-angular/tree/feature/oauth2">branche dédiée</a>.</p>
<p>J’ai également ajouté un bouton de déploiement Netlify en un clic pour ceux souhaitant se servir de ce petit projet. Il faudra néanmoins générer sa propre clé d’<a href="https://web.archive.org/web/20200110154834/https://docs.gandi.net/fr/noms_domaine/utilisateurs_avances/api.html">API depuis les paramètres de son compte Gandi</a> et renseigner quelques variables d’environnement, décrites ci-dessous.</p>
<p>Tableau : Variables d’environnement à renseigner</p>
<table>
<thead>
<tr>
<th>Paramètre</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>GANDI_API_KEY</td>
<td>Clé d’API Gandi</td>
</tr>
<tr>
<td>JWT_SECRET</td>
<td>Une chaîne de caractères aléatoire utilisée comme secret JWT</td>
</tr>
<tr>
<td>LOGIN_PASSWORD</td>
<td>Le mot de passe souhaité pour se connecter</td>
</tr>
<tr>
<td>GANDI_API_HOST</td>
<td>La racine de l’URL de l’API Gandi : <code>api.gandi.net</code></td>
</tr>
<tr>
<td>GANDI_API_VERSION</td>
<td>La version de l’API Gandi : <code>/v5</code></td>
</tr>
</tbody>
</table>
<p>Pour générer le JWT Secret, la commande suivante peut être utile</p>
<p><code>cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1</code></p>
<p>Les sources du projet sont disponibles sur <a href="https://github.com/sylvainmetayer/alias-gandi-angular">Github</a></p>

    ]]>
      </content>
      
        <category term="projet"/>
      
        <category term="angular"/>
      
        <category term="serverless"/>
      
      
        <summary type="html">
          Trop de spam ? Marre de donner son adresse email à chaque service ? Les alias mail sont là à la rescousse !
        </summary>
      
    </entry>
  
    
    <entry>
      <title>Suivi mémoire</title>
      <link href="https://www.sylvain.dev/article/suivi-memoire/"/>
      <published>2019-06-01T00:00:00Z</published>
      <updated>2019-06-01T00:00:00Z</updated>
      <id>https://sylvain.dev/article/suivi-memoire/</id>
      <content type="html">
        <![CDATA[
      <p>Bien que n’ayant pas communiqué sur le suivi de mon mémoire comme cela était <a href="/article/memoire/">indiqué ici</a>, j’ai bien avancé sur ce dernier. Je vais lister ici mes avancées et ce qu’il me reste à faire.</p>
<p>Tout d’abord, la génération du PDF final était pour moi quelque chose que je souhaitais de façon automatique. Je voulais pouvoir disposer à tout moment de 3 versions présentables. Une version dite de “travail”, sur laquelle je retrouve toutes mes notes en cours, une version numérique, avec des marges assez faibles, et une version papier avec des marges plus importantes, pour permettre une meilleure lisibilité lors de l’impression. J’ai donc utilisé <a href="https://travis-ci.org/">Travis CI</a> afin de pouvoir générer ces 3 documents à chaque tag sur mon dépôt.</p>
<p>J’ai également cherché à appliquer les bonnes pratiques LaTeX, avec l’utilisation du paquet <a href="https://ctan.org/pkg/nag">nag</a> qui permet de relever certaines erreurs et propose des corrections pour ces dernières.</p>
<p>Pour faciliter une diffusion plus facile de mon mémoire, j’ai mis en place une redirection vers la dernière version disponible accessible via le lien suivant : <a href="https://memoire.epsi.sylvainmetayer.fr">https://memoire.epsi.sylvainmetayer.fr</a></p>
<p>Un changement important à noter est le changement de ma problématique, afin d’éviter un potentiel hors-sujet et de me restreindre à un périmètre trop petit. La nouvelle problématique est la suivante : <strong>Comment l’automatisation peut-elle permettre d’améliorer le cycle de vie d’une application ?</strong>. Concernant le travail sur mon mémoire, j’ai finalisé le plan, qui comporte donc 3 parties.</p>
<ol>
<li>Le cycle de vie d’une application</li>
<li>L’intérêt de la mise en place d’une démarche d’automatisation, via une étude de cas</li>
<li>L’automatisation du cycle de vie d’une application</li>
</ol>
<p>La première partie est désormais bien avancée et la deuxième partie nécessite encore un peu de travail et de reformulation. La troisième partie dispose de la plupart des idées et concepts que je souhaite aborder, il ne restera plus qu’à l’écrire.</p>
<p>Prochaine deadline, 28 juin, où je présenterai une version (normalement) finalisée à mon tuteur. Comme indiqué dans l’article précédent, je suis preneur de vos retours, tant sur le fond que sur la forme !</p>

    ]]>
      </content>
      
        <category term="epsi"/>
      
        <category term="blog"/>
      
      
        <summary type="html">
          Avancée de la réalisation de mon mémoire de fin d&#39;études pour l&#39;EPSI
        </summary>
      
    </entry>
  
    
    <entry>
      <title>Rédaction d&#39;un mémoire de fin d&#39;études</title>
      <link href="https://www.sylvain.dev/article/memoire/"/>
      <published>2019-03-17T00:00:00Z</published>
      <updated>2019-03-17T00:00:00Z</updated>
      <id>https://sylvain.dev/article/memoire/</id>
      <content type="html">
        <![CDATA[
      <p>Ma dernière année d’études à l’EPSI Bordeaux signifie également la rédaction d’un mémoire. Afin d’assurer un suivi efficace des tuteurs EPSI, il est demandé aux étudiants de donner des états d’avancement, à des dates jalons, afin que les tuteurs puissent recadrer l’étudiant s’il part dans une mauvaise direction.</p>
<p>J’ai donc décidé de rédiger sur ce blog les avancées de mon mémoire, afin de permettre de garder une trace des étapes de réalisation de ce dernier.</p>
<p>L’objectif est de publier un article, même court, par semaine, indiquant les recherches effectuées, les difficultés rencontrées, notes diverses et variées…</p>
<p>Au niveau des différents jalons imposés, les voici :</p>
<ul>
<li>[x] 29 mars - premier point sur mon mémoire avec mon tuteur EPSI</li>
<li>[ ] 26 avril - 2ème point sur mon mémoire avec mon tuteur EPSI</li>
<li>[ ] 31 mai - 3ème point sur mon mémoire avec mon tuteur EPSI</li>
<li>[ ] 28 juin - 4ème point sur mon mémoire avec mon tuteur EPSI</li>
<li>[ ] 15 juillet - Rendu du mémoire</li>
<li>[ ] Début septembre - Soutenance de mémoire</li>
</ul>
<p>Concernant le document attendu pour le premier rendez-vous tuteur, voici ci-dessous les éléments attendus.</p>
<h2 id="le-contexte-de-l%E2%80%99alternance-ainsi-que-les-activit%C3%A9s-men%C3%A9es-en-stage-ou-alternance-et-le-sujet-principal-des-missions-d%E2%80%99alternance" tabindex="-1"><a class="heading-link" href="#le-contexte-de-l%E2%80%99alternance-ainsi-que-les-activit%C3%A9s-men%C3%A9es-en-stage-ou-alternance-et-le-sujet-principal-des-missions-d%E2%80%99alternance">Le contexte de l’alternance ainsi que les activités menées en stage ou alternance et le sujet principal des missions d’alternance</a></h2>
<p>J’effectue mon alternance au sein de <a href="https://groupeonepoint.com">onepoint</a>.</p>
<p>Le projet sur lequel je travaille actuellement comporte une équipe de 5 personnes, et nous effectuons le MCO<sup class="footnote-ref"><a href="#fn1" id="fnref1"><span class="visually-hidden">note </span>1</a></sup> ainsi que l’ajout de fonctionnalités d’une application web de certification et d’audit pour un client, Bureau Veritas. Cette application est développée avec Symfony (PHP) pour le back-office et AngularJS pour le front-office. De plus, l’architecture du projet est basée sur Docker.</p>
<p>Le back-office était initialement en Symfony 2, et nous avons procédé à sa montée de version, passant ainsi de PHP5 à PHP7 et de Symfony 2.8 à Symfony 3.4.</p>
<p>Également, j’interviens ponctuellement sur le front-office, après avoir reçu une formation en interne, pour des correctifs mineurs.</p>
<p>J’ai également mis en place un LDAP avec un container Docker dans l’environnement de développement, afin de pouvoir tester le comportement du LDAP sans avoir à atteindre les tests en recette ou en plateforme d’intégration.</p>
<p>J’ai auparavant travaillé sur 2 projets.</p>
<p>Le premier était un projet pour un client qui restera inconnu, pour des clauses commerciales liées au contrat. Ce projet consistait à la refonte d’un espace membre, avec un système de souscription, d’avantage, de quiz et de campagne email avec l’aide d’Adobe Campaign. Ce projet a été réalisé avec Drupal 8, un CMS<sup class="footnote-ref"><a href="#fn2" id="fnref2"><span class="visually-hidden">note </span>2</a></sup> PHP.</p>
<p>Le second projet est un ensemble de sous-projets, consistant à la refonte des sites de la région Nouvelle-Aquitaine, également sous Drupal 8. Ce choix était une contrainte client, puisque tous les utilisateurs (rédacteurs, traducteurs, …) sont déjà habitués à l’interface d’administration de Drupal 7, et qu’un changement aurait impliqué des frais de formation à un nouvel outil, pas forcément nécessaire et valable.</p>
<p>Les sites auxquels j’ai participé sont la refonte du <a href="https://transports.nouvelle-aquitaine.fr/">site des transports de la région</a> ainsi que la première version d’une régie publicitaire.</p>
<h2 id="le-sujet-ou-projet-d%E2%80%99%C3%A9tude-envisag%C3%A9" tabindex="-1"><a class="heading-link" href="#le-sujet-ou-projet-d%E2%80%99%C3%A9tude-envisag%C3%A9">Le sujet ou projet d’étude envisagé</a></h2>
<p>Concernant mon avancée, j’ai défini mon sujet, qui est le suivant : <strong>Comment l’automatisation peut permettre de réduire les erreurs humaines dans la mise en oeuvre d’une application ?</strong></p>
<p>Ce sujet va donc concerner en grande partie le déploiement et l’intégration continue d’une application (web, étant donné qu’il s’agit du domaine dans lequel je travaille), du poste du développeur, en passant par les tests automatisés, intégration, recette, pré-production et jusqu’à la phase de production.</p>
<p>Néanmoins, je compte également aborder le sujet de l’automatisation au sein d’une équipe de développeurs, afin de faciliter le travail de chacun, et réduire les potentielles erreurs manuelles, que ce soit au niveau des hooks git, des linters, de l’automatisation possible avec des IDE, …</p>
<p>Je compte également parler de l’automatisation au niveau de l’entreprise, sa mise en place, les personnes réticentes à convaincre pour mettre en place de tels systèmes, le pour et le contre, ainsi que les impacts possibles sur les KPI<sup class="footnote-ref"><a href="#fn3" id="fnref3"><span class="visually-hidden">note </span>3</a></sup>.</p>
<h2 id="les-comp%C3%A9tences-professionnelles-acquises-ou-en-cours-d%E2%80%99acquisition-pour-ce-sujet-ou-projet-d%E2%80%99%C3%A9tude" tabindex="-1"><a class="heading-link" href="#les-comp%C3%A9tences-professionnelles-acquises-ou-en-cours-d%E2%80%99acquisition-pour-ce-sujet-ou-projet-d%E2%80%99%C3%A9tude">Les compétences professionnelles acquises ou en cours d’acquisition pour ce sujet ou projet d’étude</a></h2>
<p>Ce sujet sera donc assez théorique, mais portera également une partie pratique.</p>
<p>D’une part avec la légère expérience personnelle que j’ai avec ce domaine, où j’ai automatisé certains projets, tels que par exemple <a href="/article/projets-epsi/#bot-telegram">un chatbot réalisé en 4ème année</a>, ou encore <a href="/article/ansible">ma découverte d’Ansible</a>, avec lequel j’ai automatisé l’installation d’un serveur Debian.</p>
<p>D’autre part avec le projet sur lequel je suis en train de travailler lors de mon alternance à <a href="https://groupeonepoint.com">onepoint</a>. L’objectif est de faire plus ou moins une refonte, ou du moins une amélioration de la chaîne d’industrialisation.</p>
<p>Ce projet va être pour moi une opportunité de pouvoir me confronter à des problématiques réelles d’entreprises, et monter en compétences sur tous les domaines concernant l’intégration et le déploiement continu. Ce projet devrait être lancé dans les semaines à venir.</p>
<h2 id="une-%C3%A9bauche-de-plan" tabindex="-1"><a class="heading-link" href="#une-%C3%A9bauche-de-plan">Une ébauche de plan</a></h2>
<p>Une première ébauche de plan a déjà été effectuée en décembre, et a continué d’être agrémentée d’idées, remaniée, …</p>
<p>Le brouillon est disponible <a href="https://github.com/sylvainmetayer/epsi-memoire/issues/8">sur Github</a>, et en voici son contenu, à ce jour :</p>
<ol start="0">
<li>Introduction</li>
<li>Historique</li>
<li>Pourquoi automatiser</li>
<li>État de l’art</li>
<li>Automatiser un projet
<ol>
<li>Localement</li>
<li>Intégration continue</li>
<li>Déploiement continu</li>
<li>Tests</li>
</ol>
</li>
<li>Bénéfices constatés</li>
<li>Limites</li>
<li>Conclusion</li>
</ol>
<p><a href="https://github.com/sylvainmetayer/epsi-memoire/releases/latest">Le PDF de l’état actuel de mon mémoire peut être consulté ici</a></p>
<h2 id="une-premi%C3%A8re-liste-bibliographique-d%C3%A9taill%C3%A9e" tabindex="-1"><a class="heading-link" href="#une-premi%C3%A8re-liste-bibliographique-d%C3%A9taill%C3%A9e">Une première liste bibliographique détaillée</a></h2>
<p>Je suis ainsi en train de lire deux livres :</p>
<ul>
<li>The Phoenix Project, plus sur la partie gestion de projet, qui aborde les interactions entre les différentes personnes impliquées dans un projet, et les conditions de succès d’un projet.</li>
<li>The DevOps Handbook, que je viens de commencer, traitant du monde DevOps, et de la façon de déployer des applications de façon continue.</li>
</ul>
<p>De plus, le livre <a href="https://leanpub.com/6cloud/">Le plan Copenhague</a> est un livre numérique, en cours de rédaction, très intéressant sur la façon de migrer des sites sous “Le cloud”.</p>
<p>Le site <a href="https://12factor.net/">12Factor</a> contient également des ressources intéressantes.</p>
<p>Je prévois également de lire un livre traitant d’Ansible, afin d’en savoir plus à ce sujet.</p>
<p>Voici pour cette première édition à propos de mon avancée sur mon mémoire.</p>
<p>Si vous avez des retours ou idées d’amélioration, remarques constructives, n’hésitez pas à laisser un commentaire ou [contactez-moi](mailto:?subject=Commentaire sur le mémoire) !</p>
<hr class="footnotes-sep">
<section class="footnotes" aria-label="Notes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>Maintien en condition opérationnelle <a href="#fnref1" class="footnote-backref" aria-label="Retour au texte (note 1)">↩︎</a></p>
</li>
<li id="fn2" class="footnote-item"><p>Content Management System <a href="#fnref2" class="footnote-backref" aria-label="Retour au texte (note 2)">↩︎</a></p>
</li>
<li id="fn3" class="footnote-item"><p>Key Performance Indicator, indicateur clé de performance <a href="#fnref3" class="footnote-backref" aria-label="Retour au texte (note 3)">↩︎</a></p>
</li>
</ol>
</section>

    ]]>
      </content>
      
        <category term="epsi"/>
      
      
        <summary type="html">
          Ma dernière année d&#39;études à l&#39;EPSI Bordeaux signifie également la rédaction d&#39;un mémoire. Afin d&#39;assurer un suivi efficace des tuteurs EPSI, il est demandé aux étudiants de donner des états d&#39;avancement, à des dates jalons, afin que les tuteurs puissent recadrer l&#39;étudiant s&#39;il part dans une mauvaise direction.
        </summary>
      
    </entry>
  
    
    <entry>
      <title>Gem : FontAwesome SVG</title>
      <link href="https://www.sylvain.dev/article/jekyll-gem-svg-fontawesome/"/>
      <published>2018-11-30T00:00:00Z</published>
      <updated>2018-11-30T00:00:00Z</updated>
      <id>https://sylvain.dev/article/jekyll-gem-svg-fontawesome/</id>
      <content type="html">
        <![CDATA[
      <h2 id="besoin" tabindex="-1"><a class="heading-link" href="#besoin">Besoin</a></h2>
<p>Je souhaitais utiliser <a href="http://fontawesome.com/">FontAwesome</a> sans pour autant intégrer toute la librairie, assez lourde.</p>
<p>J’ai donc cherché un moyen de n’inclure que les icônes utilisées, et c’est comme cela que je suis venu à chercher comment créer un plugin Jekyll.</p>
<p><a href="https://jekyllrb.com/docs/plugins/your-first-plugin/">La documentation</a> est assez bien fournie, ce qui m’a permis de rapidement prendre en main Jekyll.</p>
<h2 id="r%C3%A9alisation" tabindex="-1"><a class="heading-link" href="#r%C3%A9alisation">Réalisation</a></h2>
<p>Ne souhaitant qu’afficher des icônes, je me suis tourné vers 2 <code>Tag</code>, qui permettent de définir une balise et de lui passer des paramètres.</p>
<p>Ainsi, je passe à mon premier tag le type de l’icône que je souhaite utiliser (regular, solid ou brand), ainsi que son nom, et je génère la balise HTML<sup class="footnote-ref"><a href="#fn1" id="fnref1"><span class="visually-hidden">note </span>1</a></sup> correspondant à l’icône. Il ne me reste donc plus qu’à récupérer la définition SVG<sup class="footnote-ref"><a href="#fn2" id="fnref2"><span class="visually-hidden">note </span>2</a></sup> de l’icône et l’inclure dans un namespace, en bas de la page HTML.</p>
<p>Pour cela, j’ai ajouté aux données de la page Jekyll les icônes que j’utilise, dans un simple tableau.</p>
<p>C’est lors de l’usage du deuxième tag que je récupère toutes les icônes utilisées sur la page, et que je vais récupérer la définition SVG de l’icône.</p>
<p>J’ai tout d’abord réalisé ce plugin très simplement, en utilisant le répertoire <code>_plugins</code> de Jekyll. Mais une fois fonctionnel, j’ai souhaité en faire une Gem, mise à disposition sur <a href="https://rubygems.org/">RubyGems</a>, pour qu’elle soit disponible pour tous, si elle venait à être utile à certains :blush:.</p>
<p>La création d’une Gem a été assez simple, le guide de <a href="https://bundler.io/v1.17/guides/creating_gem.html">Bundler</a> étant très bien détaillé.</p>
<p>J’ai essayé d’être le plus en accord avec les conventions du langage Ruby, mais n’étant pas familier avec ce dernier, je suis ouvert à toutes remarques pour améliorer le code !</p>
<p>Il me reste à tester l’application de façon plus détaillée et à gérer les cas d’erreurs, qui sont pour le moment gérés de façon optimiste !</p>
<h2 id="usage" tabindex="-1"><a class="heading-link" href="#usage">Usage</a></h2>
<p>L’usage est le suivant :</p>
<p>Lorsque l’on souhaite afficher une icône, il faut utiliser le tag suivant. Le code ci-dessous va générer l’icône <a href="https://fontawesome.com/icons/twitter?style=brands">Twitter</a>.</p>
<pre class="shiki sylvain-dev"><code class="language-erb"><span class="line"><span class="tok-d6e2ee">{% fa_svg fab.fa-twitter %}</span></span></code></pre>
<p>Voici le résultat :</p>
<p>{% fa_svg fab.fa-twitter %}</p>
<p>Il faut ensuite ajouter à un endroit commun à toutes les pages (en général un footer), le tag de génération de la feuille SVG.</p>
<pre class="shiki sylvain-dev"><code class="language-erb"><span class="line"><span class="tok-d6e2ee">{% fa_svg_generate %}</span></span></code></pre>
<h2 id="liens" tabindex="-1"><a class="heading-link" href="#liens">Liens</a></h2>
<p>Si vous voulez voir le code, il est disponible sur ce <a href="https://github.com/sylvainmetayer/jekyll-fontawesome-svg">dépôt</a>.</p>
<p>Pour télécharger la Gem, c’est <a href="https://rubygems.org/gems/jekyll-fontawesome-svg">par ici</a> !</p>
<hr class="footnotes-sep">
<section class="footnotes" aria-label="Notes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>HyperText Markup Language <a href="#fnref1" class="footnote-backref" aria-label="Retour au texte (note 1)">↩︎</a></p>
</li>
<li id="fn2" class="footnote-item"><p>Scalable Vector Graphics <a href="#fnref2" class="footnote-backref" aria-label="Retour au texte (note 2)">↩︎</a></p>
</li>
</ol>
</section>

    ]]>
      </content>
      
        <category term="jekyll"/>
      
        <category term="ruby"/>
      
        <category term="projet"/>
      
      
        <summary type="html">
          Je souhaitais utiliser FontAwesome sans pour autant intégrer toute la librairie, assez lourde.
        </summary>
      
    </entry>
  
    
    <entry>
      <title>Ajout des commentaires sur le site</title>
      <link href="https://www.sylvain.dev/article/ajout-commentaires/"/>
      <published>2018-11-18T00:00:00Z</published>
      <updated>2018-11-18T00:00:00Z</updated>
      <id>https://sylvain.dev/article/ajout-commentaires/</id>
      <content type="html">
        <![CDATA[
      <p>Les commentaires sont maintenant disponibles sur le site !</p>
<p>Comme indiqué dans <a href="/article/site-personnel-v2">l’article précédent</a>, je cherchais désormais à intégrer une solution de commentaire, tout en évitant les solutions peu respectueuses de notre vie privée.</p>
<p>Mon choix s’était alors porté sur <a href="https://posativ.org/isso/">isso</a>, bien qu’il existe de nombreuses alternatives<sup class="footnote-ref"><a href="#fn1" id="fnref1"><span class="visually-hidden">note </span>1</a></sup>.</p>
<p>La chose que j’ai appréciée avec Isso, en plus du fait qu’il est libre et auto-hébergé, est qu’il ne requiert aucune inscription pour commenter. Il est possible d’indiquer son nom, site web et adresse email (qui ne sera jamais publiée), chaque champ étant optionnel. Une modération est également possible (étant donné que j’ai fait le choix de laisser la possibilité de commenter anonymement, j’ai également fait le choix d’activer la modération avant publication).</p>
<h2 id="installation" tabindex="-1"><a class="heading-link" href="#installation">Installation</a></h2>
<p>L’installation a été assez simple, de nombreux tutoriels<sup class="footnote-ref"><a href="#fn2" id="fnref2"><span class="visually-hidden">note </span>2</a></sup> existent sur internet et la <a href="https://posativ.org/isso/docs/install/">documentation</a> est assez claire.</p>
<p>Voici les différentes étapes pour installer isso.</p>
<ol>
<li>
<p>Installer les dépendances Python et virtualenv.</p>
<blockquote>
<p>Bien que virtualenv ne soit pas obligatoire, il est recommandé afin d’éviter d’interférer avec les dépendances existantes sur le système.</p>
</blockquote>
<pre class="shiki sylvain-dev"><code class="language-bash"><span class="line"><span class="tok-7cc4ff">sudo</span><span class="tok-9fd88a"> apt-get</span><span class="tok-9fd88a"> install</span><span class="tok-9fd88a"> build-essential</span><span class="tok-9fd88a"> python-dev</span><span class="tok-9fd88a"> python-pip</span><span class="tok-9fd88a"> virtualenv</span></span></code></pre>
</li>
<li>
<p>Une fois les dépendances installées, on initialise un environnement virtualenv</p>
<pre class="shiki sylvain-dev"><code class="language-bash"><span class="line"><span class="tok-7cc4ff">sudo</span><span class="tok-9fd88a"> virtualenv</span><span class="tok-9fd88a"> /opt/isso</span></span></code></pre>
<p>On active l’environnement, en tant que root.</p>
<pre class="shiki sylvain-dev"><code class="language-bash"><span class="line"><span class="tok-7cc4ff">sudo</span><span class="tok-9fd88a"> su</span></span>
<span class="line"><span class="tok-7cc4ff">source</span><span class="tok-9fd88a"> /opt/isso/bin/activate</span></span></code></pre>
<blockquote>
<p>Étant donné que <code>/opt</code> n’est pas accessible en écriture aux utilisateurs, on utilise sudo. Mais rien n’empêche de l’installer dans le répertoire personnel de l’utilisateur.</p>
</blockquote>
</li>
<li>
<p>Installation des dépendances</p>
<pre class="shiki sylvain-dev"><code class="language-bash"><span class="line"><span class="tok-7cc4ff">pip</span><span class="tok-9fd88a"> install</span><span class="tok-9fd88a"> isso</span><span class="tok-9fd88a"> gunicorn</span></span></code></pre>
<p>On peut désormais quitter virtualenv.</p>
<pre class="shiki sylvain-dev"><code class="language-bash"><span class="line"><span class="tok-7cc4ff">deactivate</span></span></code></pre>
</li>
</ol>
<h2 id="configuration" tabindex="-1"><a class="heading-link" href="#configuration">Configuration</a></h2>
<p>On ne souhaite pas que isso soit exécuté en tant que root car s’il venait à y avoir une faille, l’attaquant aurait alors tous les droits. On va donc créer un utilisateur dédié et lui donner les droits sur les répertoires nécessaires (log et données). On crée également un répertoire <code>/etc/isso</code> qui contiendra les différentes configurations.</p>
<pre class="shiki sylvain-dev"><code class="language-bash"><span class="line"><span class="tok-7cc4ff">sudo</span><span class="tok-9fd88a"> adduser</span><span class="tok-9fd88a"> isso</span></span>
<span class="line"><span class="tok-7cc4ff">sudo</span><span class="tok-9fd88a"> mkdir</span><span class="tok-9fd88a"> /var/lib/isso</span><span class="tok-9fd88a"> /var/log/isso</span></span>
<span class="line"><span class="tok-7cc4ff">sudo</span><span class="tok-9fd88a"> chown</span><span class="tok-9fd88a"> isso:isso</span><span class="tok-9fd88a"> /var/lib/isso</span></span>
<span class="line"><span class="tok-7cc4ff">sudo</span><span class="tok-9fd88a"> chown</span><span class="tok-9fd88a"> isso:isso</span><span class="tok-9fd88a"> /var/log/isso</span></span>
<span class="line"><span class="tok-7cc4ff">sudo</span><span class="tok-9fd88a"> mkdir</span><span class="tok-9fd88a"> /etc/isso</span></span></code></pre>
<p>Il reste maintenant à configurer Isso. Mon cas d’usage est le suivant : je souhaite avoir deux sites, un pour l’environnement de développement, l’autre pour la production. Voici ma configuration (<code>/etc/isso/isso.cfg</code> et <code>/etc/isso/isso.prod.cfg</code>).</p>
<p>Pour des détails sur chaque paramètre, se référer à <a href="https://isso-comments.de/docs/">la documentation d’isso</a>.</p>
<pre class="shiki sylvain-dev"><code class="language-ini"><span class="line"><span class="tok-a9b8c8">[</span><span class="tok-ff9a8a">general</span><span class="tok-a9b8c8">]</span></span>
<span class="line"><span class="tok-c39bff">dbpath</span><span class="tok-a9b8c8"> =</span><span class="tok-d6e2ee"> /var/lib/isso/prod.comments.db</span></span>
<span class="line"><span class="tok-8396ab tok-italic"># Etant donné que je configure plusieurs sites, il est nécessaire de mettre une valeur au champ name</span></span>
<span class="line"><span class="tok-c39bff">name</span><span class="tok-a9b8c8"> =</span><span class="tok-d6e2ee"> main</span></span>
<span class="line"><span class="tok-c39bff">host</span><span class="tok-a9b8c8"> =</span><span class="tok-d6e2ee"> https://sylvainmetayer.fr</span></span>
<span class="line"><span class="tok-c39bff">max-age</span><span class="tok-a9b8c8"> =</span><span class="tok-d6e2ee"> 15m</span></span>
<span class="line"><span class="tok-8396ab tok-italic"># Pour recevoir les notifications de nouveaux commentaires par email</span></span>
<span class="line"><span class="tok-c39bff">notify</span><span class="tok-a9b8c8"> =</span><span class="tok-d6e2ee"> smtp</span></span>
<span class="line"><span class="tok-c39bff">reply-notifications</span><span class="tok-a9b8c8">=</span><span class="tok-d6e2ee">false</span></span>
<span class="line"><span class="tok-c39bff">log-file</span><span class="tok-a9b8c8"> =</span></span>
<span class="line"><span class="tok-8396ab tok-italic"># Permet d'accéder à une interface d'administration permettant de visualiser les commentaires et de les approuver/rejeter/supprimer.</span></span>
<span class="line"><span class="tok-c39bff">admin_password</span><span class="tok-a9b8c8"> =</span><span class="tok-d6e2ee"> MySuperSecurePassword</span></span>
<span class="line"></span>
<span class="line"><span class="tok-a9b8c8">[</span><span class="tok-ff9a8a">moderation</span><span class="tok-a9b8c8">]</span></span>
<span class="line"><span class="tok-c39bff">enabled</span><span class="tok-a9b8c8"> =</span><span class="tok-d6e2ee"> true</span></span>
<span class="line"><span class="tok-c39bff">purge-after</span><span class="tok-a9b8c8"> =</span><span class="tok-d6e2ee"> 30d</span></span>
<span class="line"></span>
<span class="line"><span class="tok-a9b8c8">[</span><span class="tok-ff9a8a">server</span><span class="tok-a9b8c8">]</span></span>
<span class="line"><span class="tok-c39bff">listen</span><span class="tok-a9b8c8"> =</span><span class="tok-d6e2ee"> http://localhost:8080</span></span>
<span class="line"></span>
<span class="line"><span class="tok-a9b8c8">[</span><span class="tok-ff9a8a">smtp</span><span class="tok-a9b8c8">]</span></span>
<span class="line"><span class="tok-c39bff">username</span><span class="tok-a9b8c8"> =</span><span class="tok-d6e2ee"> me@mon.email.fr</span></span>
<span class="line"><span class="tok-8396ab tok-italic"># Malheureusement, le mot de passe doit être en clair.</span></span>
<span class="line"><span class="tok-8396ab tok-italic"># Il est donc recommandé de créer un compte email dédié pour l'envoi des notifications.</span></span>
<span class="line"><span class="tok-c39bff">password</span><span class="tok-a9b8c8"> =</span><span class="tok-d6e2ee"> MonMotDePasseEmail</span></span>
<span class="line"><span class="tok-c39bff">host</span><span class="tok-a9b8c8"> =</span><span class="tok-d6e2ee"> mail.gandi.net</span></span>
<span class="line"><span class="tok-c39bff">port</span><span class="tok-a9b8c8"> =</span><span class="tok-d6e2ee"> 587</span></span>
<span class="line"><span class="tok-c39bff">security</span><span class="tok-a9b8c8"> =</span><span class="tok-d6e2ee"> starttls</span></span>
<span class="line"><span class="tok-8396ab tok-italic"># L'adresse qui reçoit les notifications</span></span>
<span class="line"><span class="tok-c39bff">to</span><span class="tok-a9b8c8"> =</span><span class="tok-d6e2ee"> you@your.email.com</span></span>
<span class="line"><span class="tok-c39bff">from</span><span class="tok-a9b8c8"> =</span><span class="tok-d6e2ee"> me@mon.email.fr</span></span>
<span class="line"><span class="tok-c39bff">timeout</span><span class="tok-a9b8c8"> =</span><span class="tok-d6e2ee"> 10</span></span>
<span class="line"></span>
<span class="line"><span class="tok-a9b8c8">[</span><span class="tok-ff9a8a">guard</span><span class="tok-a9b8c8">]</span></span>
<span class="line"><span class="tok-8396ab tok-italic"># Enable basic spam protection features, e.g. rate-limit per IP address (/24</span></span>
<span class="line"><span class="tok-8396ab tok-italic"># for IPv4, /48 for IPv6).</span></span>
<span class="line"><span class="tok-c39bff">enabled</span><span class="tok-a9b8c8"> =</span><span class="tok-d6e2ee"> true</span></span>
<span class="line"><span class="tok-c39bff">ratelimit</span><span class="tok-a9b8c8"> =</span><span class="tok-d6e2ee"> 2</span></span>
<span class="line"><span class="tok-c39bff">direct-reply</span><span class="tok-a9b8c8"> =</span><span class="tok-d6e2ee"> 2</span></span>
<span class="line"><span class="tok-c39bff">reply-to-self</span><span class="tok-a9b8c8"> =</span><span class="tok-d6e2ee"> false</span></span>
<span class="line"><span class="tok-c39bff">require-author</span><span class="tok-a9b8c8"> =</span><span class="tok-d6e2ee"> false</span></span>
<span class="line"><span class="tok-c39bff">require-email</span><span class="tok-a9b8c8"> =</span><span class="tok-d6e2ee"> false</span></span>
<span class="line"></span>
<span class="line"><span class="tok-a9b8c8">[</span><span class="tok-ff9a8a">markup</span><span class="tok-a9b8c8">]</span></span>
<span class="line"><span class="tok-c39bff">options</span><span class="tok-a9b8c8"> =</span><span class="tok-d6e2ee"> strikethrough, autolink, fenced_code, no_intra_emphasis</span></span>
<span class="line"><span class="tok-8396ab tok-italic"># default, only a, blockquote, br, code, del, em, h1, h2, h3, h4, h5, h6, hr,</span></span>
<span class="line"><span class="tok-8396ab tok-italic"># ins, li, ol, p, pre, strong, table, tbody, td, th, thead and ul are allowed.</span></span>
<span class="line"><span class="tok-c39bff">allowed-elements</span><span class="tok-a9b8c8"> =</span></span>
<span class="line"><span class="tok-c39bff">allowed-attributes</span><span class="tok-a9b8c8"> =</span></span>
<span class="line"></span>
<span class="line"><span class="tok-a9b8c8">[</span><span class="tok-ff9a8a">hash</span><span class="tok-a9b8c8">]</span></span>
<span class="line"><span class="tok-8396ab tok-italic"># Utilisé pour générer des identicons sur les commentaires</span></span>
<span class="line"><span class="tok-c39bff">salt</span><span class="tok-a9b8c8"> =</span><span class="tok-d6e2ee"> SaltDe25Caractère</span></span>
<span class="line"><span class="tok-c39bff">algorithm</span><span class="tok-a9b8c8"> =</span><span class="tok-d6e2ee"> pbkdf2</span></span></code></pre>
<p>La configuration pour le site de développement est identique, il suffit donc de copier/coller le fichier et d’éditer quelques champs.</p>
<pre class="shiki sylvain-dev"><code class="language-ini"><span class="line"><span class="tok-a9b8c8">[</span><span class="tok-ff9a8a">general</span><span class="tok-a9b8c8">]</span></span>
<span class="line"><span class="tok-c39bff">dbpath</span><span class="tok-a9b8c8"> =</span><span class="tok-d6e2ee"> /var/lib/isso/dev.comments.db</span></span>
<span class="line"><span class="tok-c39bff">name</span><span class="tok-a9b8c8"> =</span><span class="tok-d6e2ee"> development</span></span>
<span class="line"><span class="tok-c39bff">host</span><span class="tok-a9b8c8"> =</span><span class="tok-d6e2ee"> https://development_url</span></span></code></pre>
<pre class="shiki sylvain-dev"><code class="language-bash"><span class="line"><span class="tok-7cc4ff">sudo</span><span class="tok-9fd88a"> chown</span><span class="tok-9fd88a"> root:</span><span class="tok-9fd88a"> /etc/isso/isso.cfg</span></span>
<span class="line"><span class="tok-7cc4ff">sudo</span><span class="tok-9fd88a"> chown</span><span class="tok-9fd88a"> root:</span><span class="tok-9fd88a"> /etc/isso/isso.prod.cfg</span></span></code></pre>
<p>Une fois la configuration terminée, il faut configurer le service pour qu’il démarre au lancement de l’OS.</p>
<p>On crée donc le script de démarrage du service dans <code>/opt/isso/isso-start.sh</code></p>
<pre class="shiki sylvain-dev"><code class="language-bash"><span class="line"><span class="tok-8396ab tok-italic">#!/bin/bash</span></span>
<span class="line"><span class="tok-7cc4ff">set</span><span class="tok-9fd88a"> -e</span></span>
<span class="line"><span class="tok-7cc4ff">source</span><span class="tok-9fd88a"> /opt/isso/bin/activate</span></span>
<span class="line"><span class="tok-c39bff">export</span><span class="tok-ff9a8a"> LANG</span><span class="tok-a9b8c8">=</span><span class="tok-ff9a8a">C</span><span class="tok-d6e2ee">.</span><span class="tok-ff9a8a">UTF-8</span></span>
<span class="line"><span class="tok-c39bff">export</span><span class="tok-ff9a8a"> ISSO_SETTINGS</span><span class="tok-a9b8c8">=</span><span class="tok-a9b8c8">"</span><span class="tok-9fd88a">/etc/isso/isso.cfg;/etc/isso/isso.prod.cfg</span><span class="tok-a9b8c8">"</span></span>
<span class="line"><span class="tok-7cc4ff">exec</span><span class="tok-9fd88a"> gunicorn</span><span class="tok-9fd88a"> -n</span><span class="tok-9fd88a"> gunicorn-isso</span><span class="tok-9fd88a"> -b</span><span class="tok-9fd88a"> 127.0.0.1:8080</span><span class="tok-9fd88a"> --preload</span><span class="tok-9fd88a"> -w</span><span class="tok-f2b56b"> 2</span><span class="tok-9fd88a"> --log-file</span><span class="tok-9fd88a"> /var/log/isso/isso.log</span><span class="tok-9fd88a"> isso.dispatch</span><span class="tok-a9b8c8"> 2>></span><span class="tok-9fd88a">/var/log/isso/isso.log</span></span></code></pre>
<pre class="shiki sylvain-dev"><code class="language-bash"><span class="line"><span class="tok-7cc4ff">sudo</span><span class="tok-9fd88a"> chown</span><span class="tok-9fd88a"> root:</span><span class="tok-9fd88a"> /opt/isso/isso-start.sh</span></span>
<span class="line"><span class="tok-7cc4ff">sudo</span><span class="tok-9fd88a"> chmod</span><span class="tok-f2b56b"> 755</span><span class="tok-9fd88a"> /opt/isso/isso-start.sh</span></span></code></pre>
<p>On crée maintenant le service.</p>
<pre class="shiki sylvain-dev"><code class="language-ini"><span class="line"><span class="tok-a9b8c8">[</span><span class="tok-ff9a8a">Unit</span><span class="tok-a9b8c8">]</span></span>
<span class="line"><span class="tok-c39bff">Description</span><span class="tok-a9b8c8">=</span><span class="tok-d6e2ee">isso commenting system</span></span>
<span class="line"></span>
<span class="line"><span class="tok-a9b8c8">[</span><span class="tok-ff9a8a">Service</span><span class="tok-a9b8c8">]</span></span>
<span class="line"><span class="tok-c39bff">ExecStart</span><span class="tok-a9b8c8">=</span><span class="tok-d6e2ee">/opt/isso/isso-start.sh</span></span>
<span class="line"></span>
<span class="line"><span class="tok-c39bff">Restart</span><span class="tok-a9b8c8">=</span><span class="tok-d6e2ee">on-failure</span></span>
<span class="line"><span class="tok-c39bff">TimeoutSec</span><span class="tok-a9b8c8">=</span><span class="tok-d6e2ee">1</span></span>
<span class="line"><span class="tok-c39bff">User</span><span class="tok-a9b8c8">=</span><span class="tok-d6e2ee">isso</span></span>
<span class="line"></span>
<span class="line"><span class="tok-c39bff">LimitNOFILE</span><span class="tok-a9b8c8">=</span><span class="tok-d6e2ee">16384</span></span>
<span class="line"><span class="tok-c39bff">LimitNPROC</span><span class="tok-a9b8c8">=</span><span class="tok-d6e2ee">16384</span></span>
<span class="line"><span class="tok-c39bff">LimitLOCKS</span><span class="tok-a9b8c8">=</span><span class="tok-d6e2ee">16384</span></span>
<span class="line"></span>
<span class="line"><span class="tok-8396ab tok-italic"># ensures that the service process and all its children can never gain new</span></span>
<span class="line"><span class="tok-8396ab tok-italic"># privileges.</span></span>
<span class="line"><span class="tok-c39bff">NoNewPrivileges</span><span class="tok-a9b8c8">=</span><span class="tok-d6e2ee">true</span></span>
<span class="line"></span>
<span class="line"><span class="tok-a9b8c8">[</span><span class="tok-ff9a8a">Install</span><span class="tok-a9b8c8">]</span></span>
<span class="line"><span class="tok-c39bff">WantedBy</span><span class="tok-a9b8c8">=</span><span class="tok-d6e2ee">multi-user.target</span></span></code></pre>
<p>On redémarre <code>systemctl</code> et on active isso au démarrage, puis on le lance !</p>
<pre class="shiki sylvain-dev"><code class="language-bash"><span class="line"><span class="tok-7cc4ff">sudo</span><span class="tok-9fd88a"> chown</span><span class="tok-9fd88a"> root:</span><span class="tok-9fd88a"> /lib/systemd/system/isso.service</span></span>
<span class="line"><span class="tok-7cc4ff">sudo</span><span class="tok-9fd88a"> chmod</span><span class="tok-f2b56b"> 644</span><span class="tok-9fd88a"> /lib/systemd/system/isso.service</span></span>
<span class="line"><span class="tok-7cc4ff">sudo</span><span class="tok-9fd88a"> systemctl</span><span class="tok-9fd88a"> daemon-reload</span></span>
<span class="line"><span class="tok-7cc4ff">sudo</span><span class="tok-9fd88a"> systemctl</span><span class="tok-9fd88a"> enable</span><span class="tok-9fd88a"> isso</span></span>
<span class="line"><span class="tok-7cc4ff">sudo</span><span class="tok-9fd88a"> systemctl</span><span class="tok-9fd88a"> start</span><span class="tok-9fd88a"> isso</span></span></code></pre>
<p>Il reste maintenant à configurer le reverse proxy (nginx dans mon cas).</p>
<pre class="shiki sylvain-dev"><code class="language-nginx"><span class="line"><span class="tok-c39bff">location</span><span class="tok-d6e2ee"> / {</span></span>
<span class="line"><span class="tok-c39bff">    proxy_pass </span><span class="tok-d6e2ee">http://127.0.0.1:8080/</span><span class="tok-a9b8c8">;</span></span>
<span class="line"><span class="tok-c39bff">    proxy_redirect </span><span class="tok-f2b56b">default</span><span class="tok-a9b8c8">;</span></span>
<span class="line"><span class="tok-c39bff">    proxy_set_header </span><span class="tok-d6e2ee">Host </span><span class="tok-a9b8c8">$</span><span class="tok-ff9a8a">host</span><span class="tok-a9b8c8">;</span></span>
<span class="line"><span class="tok-c39bff">    proxy_set_header </span><span class="tok-d6e2ee">X-Forwarded-Host </span><span class="tok-a9b8c8">$</span><span class="tok-ff9a8a">host</span><span class="tok-a9b8c8">;</span></span>
<span class="line"><span class="tok-c39bff">    proxy_set_header </span><span class="tok-d6e2ee">X-Forwarded-Server </span><span class="tok-a9b8c8">$</span><span class="tok-ff9a8a">host</span><span class="tok-a9b8c8">;</span></span>
<span class="line"><span class="tok-c39bff">    proxy_set_header </span><span class="tok-d6e2ee">X-Real-IP </span><span class="tok-a9b8c8">$</span><span class="tok-ff9a8a">remote_addr</span><span class="tok-a9b8c8">;</span></span>
<span class="line"><span class="tok-c39bff">    proxy_set_header </span><span class="tok-d6e2ee">X-Forwarded-For </span><span class="tok-a9b8c8">$</span><span class="tok-ff9a8a">proxy_add_x_forwarded_for</span><span class="tok-a9b8c8">;</span></span>
<span class="line"><span class="tok-c39bff">    proxy_set_header </span><span class="tok-d6e2ee">X-Forwarded-Proto </span><span class="tok-a9b8c8">$</span><span class="tok-ff9a8a">scheme</span><span class="tok-a9b8c8">;</span></span>
<span class="line"><span class="tok-d6e2ee">}</span></span></code></pre>
<p>Les headers sont importants, puisque s’ils ne sont pas présents, isso enverra des emails avec des liens pointant vers <code>localhost:8080</code> et ne fonctionnera pas bien côté client.</p>
<p>Il ne reste maintenant plus qu’à configurer notre client ! Voici le code que j’ai ajouté dans mon fichier <code>_layouts/post.html</code>. J’ai également ajouté un attribut <code>enable_comments</code> dans mes posts, lorsque je souhaite activer les commentaires.</p>
<p>Le script est chargé en asynchrone, afin de ne pas gêner le chargement de la page.</p>
<pre class="shiki sylvain-dev"><code class="language-js"><span class="line"></span>
<span class="line"><span class="tok-a9b8c8">{%</span><span class="tok-c39bff"> if</span><span class="tok-ff9a8a"> page</span><span class="tok-a9b8c8">.</span><span class="tok-ff9a8a">enable_comments</span><span class="tok-a9b8c8"> %}</span></span>
<span class="line"><span class="tok-a9b8c8">    &#x3C;</span><span class="tok-ff9a8a">hr</span><span class="tok-a9b8c8">></span></span>
<span class="line"><span class="tok-a9b8c8">    &#x3C;</span><span class="tok-ff9a8a">h2</span><span class="tok-a9b8c8">></span><span class="tok-d6e2ee">Commentaires</span><span class="tok-a9b8c8">&#x3C;/</span><span class="tok-ff9a8a">h2</span><span class="tok-a9b8c8">></span></span>
<span class="line"><span class="tok-a9b8c8">    &#x3C;</span><span class="tok-ff9a8a">script</span><span class="tok-ff9a8a"> async</span></span>
<span class="line"><span class="tok-ff9a8a">    data-isso</span><span class="tok-a9b8c8">=</span><span class="tok-a9b8c8">"</span><span class="tok-9fd88a">{{site.isso.url}}</span><span class="tok-a9b8c8">"</span></span>
<span class="line"><span class="tok-ff9a8a">    data-isso-id</span><span class="tok-a9b8c8">=</span><span class="tok-a9b8c8">"</span><span class="tok-9fd88a">{{page.id}}</span><span class="tok-a9b8c8">"</span></span>
<span class="line"><span class="tok-ff9a8a">    data-isso-feed</span><span class="tok-a9b8c8">=</span><span class="tok-a9b8c8">"</span><span class="tok-9fd88a">true</span><span class="tok-a9b8c8">"</span></span>
<span class="line"><span class="tok-ff9a8a">    src</span><span class="tok-a9b8c8">=</span><span class="tok-a9b8c8">"</span><span class="tok-9fd88a">{{site.isso.script}}</span><span class="tok-a9b8c8">"</span><span class="tok-a9b8c8">>&#x3C;/</span><span class="tok-ff9a8a">script</span><span class="tok-a9b8c8">></span></span>
<span class="line"></span>
<span class="line"><span class="tok-a9b8c8">    &#x3C;</span><span class="tok-ff9a8a">section</span><span class="tok-ff9a8a"> id</span><span class="tok-a9b8c8">=</span><span class="tok-a9b8c8">"</span><span class="tok-9fd88a">isso-thread</span><span class="tok-a9b8c8">"</span><span class="tok-a9b8c8">>&#x3C;/</span><span class="tok-ff9a8a">section</span><span class="tok-a9b8c8">></span></span>
<span class="line"><span class="tok-a9b8c8">    &#x3C;</span><span class="tok-ff9a8a">hr</span><span class="tok-a9b8c8">></span></span>
<span class="line"><span class="tok-a9b8c8">{%</span><span class="tok-ff9a8a"> endif</span><span class="tok-a9b8c8"> %}</span></span>
<span class="line"></span></code></pre>
<p>Pour plus d’informations sur les paramètres disponibles côté client, <a href="https://isso-comments.de/docs/">voir la documentation d’isso</a>.</p>
<p>⚠ Lorsqu’un fil de commentaire est vide (ce qui est le cas lorsqu’un article ne contient pas encore de commentaire), isso répond avec une erreur HTTP 404, ce qui peut faire croire qu’une page est manquante ou invalide. <a href="https://github.com/isso-comments/isso/issues/301">Une issue est ouverte sur le dépôt Github</a> pour renvoyer un code HTTP 204 (no content) à la place.</p>
<p>Et voici le résultat !</p>
<p><img src="/images/isso.png" alt="Bloc de commentaires Isso : formulaire (commentaire, nom, courriel, site web, boutons Soumettre et Aperçu) suivi de deux commentaires anonymes"></p>
<blockquote>
<p>Ce n’est qu’une image, les commentaires se trouvent plus bas 😉</p>
</blockquote>
<blockquote>
<p>Edit 16.07.2020 : Les commentaires ne sont pour le moment plus disponibles. Migration vers Eleventy en cours, ils devraient être remplacés à l’aide des Webmentions d’ici les prochaines semaines/mois.</p>
</blockquote>
<hr class="footnotes-sep">
<section class="footnotes" aria-label="Notes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p><a href="https://lisakov.com/projects/open-source-comments/">Voici un site répertoriant plusieurs solutions existant</a> <a href="#fnref1" class="footnote-backref" aria-label="Retour au texte (note 1)">↩︎</a></p>
</li>
<li id="fn2" class="footnote-item"><p><a href="https://blog.phusion.nl/isso-simple-self-hosted-commenting-system/">Ce tutoriel très similaire à cet article m’a été bien utile</a> <a href="#fnref2" class="footnote-backref" aria-label="Retour au texte (note 2)">↩︎</a></p>
</li>
</ol>
</section>

    ]]>
      </content>
      
        <category term="jekyll"/>
      
        <category term="blog"/>
      
      
        <summary type="html">
          Les commentaires sont maintenant disponibles sur le site
        </summary>
      
    </entry>
  
    
    <entry>
      <title>Nouvelle version du site 💥</title>
      <link href="https://www.sylvain.dev/article/site-personnel-v2/"/>
      <published>2018-11-15T00:00:00Z</published>
      <updated>2018-11-15T00:00:00Z</updated>
      <id>https://sylvain.dev/article/site-personnel-v2/</id>
      <content type="html">
        <![CDATA[
      <!-- {\% include toc.html %\} -->
<h2 id="le-passage-de-php-%C3%A0-jekyll" tabindex="-1"><a class="heading-link" href="#le-passage-de-php-%C3%A0-jekyll">Le passage de PHP à Jekyll</a></h2>
<p>Après quelques années d’existence, mon ancien site commençait à vieillir.</p>
<p>(<a href="https://github.com/sylvainmetayer/sylvainmetayer-old">Les sources de mon ancien site sont toujours disponibles sur Github</a>, mais remontent à l’époque de mon DUT, soyez indulgents ! 😁)</p>
<p>De plus, <a href="/article/l-effet-parthenay">le premier et unique article</a> présent sur ce site n’était même pas hébergé sur ce site, mais sur un sous-domaine (désormais inexistant) et avec la plateforme <a href="https://ghost.org/">Ghost</a> (qui est un excellent logiciel libre au passage !).</p>
<p>Cela faisait donc deux sites à maintenir, pour un trafic plus que faible 😀 !</p>
<p>Le choix de PHP avait été fait à l’époque car il s’agissait du seul langage que je maîtrisais.</p>
<p>En y réfléchissant, pour effectuer une refonte du site, j’ai listé les points que je souhaitais avoir.</p>
<h3 id="1.-des-performances-am%C3%A9lior%C3%A9es" tabindex="-1"><a class="heading-link" href="#1.-des-performances-am%C3%A9lior%C3%A9es">1. Des performances améliorées</a></h3>
<p>Pour cette refonte, je souhaitais obtenir des performances dignes de ce nom. N’ayant pas de logique côté serveur (puisque le but de ce site est simplement de servir du contenu, pas d’effectuer un traitement dessus ou de traiter des données externes), le choix d’un langage côté serveur ne me semblait plus très cohérent.</p>
<p>Étant donné que je n’ai que du contenu statique, pourquoi ne pas envoyer au client un simple fichier HTML, plutôt que de consommer du temps CPU et des processus PHP pour générer une page d’une faible complexité ? Pourquoi ne pas construire une fois toutes les pages nécessaires, pour n’avoir plus qu’à les servir ensuite, supprimant le temps de génération de la page côté serveur ?</p>
<p>J’ai donc commencé à creuser la question des générateurs de sites et en ai trouvé plusieurs (le très bon site <a href="https://www.staticgen.com/">StaticGen</a> m’a beaucoup aidé à trouver des ressources et des avis). C’est ainsi que mon choix s’est porté sur <a href="https://jekyllrb.com/">Jekyll</a>.</p>
<p>Voici une illustration des performances actuelles du site, ainsi qu’un rapport <a href="https://www.dareboost.com/fr/report/d_5bec937de967905e05bb64cb">Dareboost</a>. Je suis assez satisfait du résultat, même s’il me reste du travail à faire dessus (mais comme le produit parfait n’existe pas, le site parfait n’existe pas non plus ! 😜)</p>
<p><img src="/images/speed-test.png" alt="Résultat Google PageSpeed : chargement en 2 s, note Excellent, plus rapide que les sites les plus performants du secteur (4,3 s)"></p>
<h3 id="2.-le-contenu-prime-sur-le-design-(pour-moi)" tabindex="-1"><a class="heading-link" href="#2.-le-contenu-prime-sur-le-design-(pour-moi)">2. Le contenu prime sur le design (pour moi)</a></h3>
<p>Je suis un très mauvais designer et l’intégration CSS est pour moi un vrai calvaire.</p>
<p>C’est d’ailleurs pour cela que je suis parti d’un template Jekyll que j’ai ensuite adapté à mes besoins.</p>
<blockquote>
<p><a href="https://github.com/sergiokopplin/indigo">Le thème de base que j’ai utilisé peut être consulté ici</a></p>
</blockquote>
<p>Néanmoins, je ne voulais pas d’un thème complexe, qui allait ainsi influer sur les performances du site (plus il y a de CSS et de JS, plus le site sera long à charger pour l’utilisateur). C’est pourquoi le thème que j’ai choisi n’intègre aucun javascript. Ainsi, seule une feuille de style, quelques emojis provenant de Github, et une feuille SVG<sup class="footnote-ref"><a href="#fn1" id="fnref1"><span class="visually-hidden">note </span>1</a></sup> sont chargées en plus du contenu.</p>
<blockquote>
<p>Je n’exclus pas d’utiliser du javascript lorsque je ferai évoluer le site, mais je vais tenter d’en limiter au maximum l’usage.</p>
</blockquote>
<p>Certes, le thème du site semblera au mieux austère à certains, au pire hideux à d’autres, … Mais au moins, le site est lisible sur (presque, je n’ai pas de montre connectée pour tester !) tous les supports et charge rapidement 😀</p>
<h3 id="3.-la-r%C3%A9daction-doit-se-faire-en-markdown-et-une-s%C3%A9paration-style%2Fcontenu-doit-exister" tabindex="-1"><a class="heading-link" href="#3.-la-r%C3%A9daction-doit-se-faire-en-markdown-et-une-s%C3%A9paration-style%2Fcontenu-doit-exister">3. La rédaction doit se faire en <a href="https://fr.wikipedia.org/wiki/Markdown">Markdown</a> et une séparation style/contenu doit exister</a></h3>
<p>C’est également l’une des raisons qui m’a poussé vers les générateurs de sites statiques.</p>
<p>J’aime beaucoup le markdown, et m’en sert beaucoup en cours pour ma prise de note. Il s’agit d’un langage extrêmement simple pour la rédaction, et en même temps, très puissant.</p>
<p>Concernant la séparation style/contenu, les <code>layouts</code> de Jekyll répondent parfaitement à ce besoin.</p>
<h3 id="4.-s%C3%A9curit%C3%A9" tabindex="-1"><a class="heading-link" href="#4.-s%C3%A9curit%C3%A9">4. Sécurité</a></h3>
<p>Je souhaitais un site qui ne sera pas facilement corrompu. Avec des pages HTML, aucune faille PHP / Node / Java / (mettez le nom de votre langage préféré ici) possible. Avec un générateur de site statique, on génère le contenu une fois, on publie le résultat et on sert le contenu, c’est tout !</p>
<p>Concernant l’hébergement, je me suis tout d’abord dit que j’allais profiter de l’hébergement avec <a href="https://pages.github.com/">Github Pages</a>. Cela fonctionne très simplement, même avec un domaine personnel, puisqu’il suffit simplement d’utiliser le gestionnaire DNS de son registrar pour faire pointer le domaine sur l’IP de Github Page.</p>
<p>Néanmoins, cela a un inconvénient majeur à mon sens : la maîtrise des paramètres du site est impossible, que cela soit au niveau du cache, des headers de sécurité, … Github empêche toute modification des headers sur les sites hébergés par Github Pages<sup class="footnote-ref"><a href="#fn2" id="fnref2"><span class="visually-hidden">note </span>2</a></sup></p>
<p>Au final, nous ne sommes jamais aussi bien servis que par soi-même, j’ai donc utilisé <a href="https://travis-ci.org/">Travis CI</a> pour déployer le site généré sur mon petit <a href="https://www.raspberrypi.org/">Raspberry</a> avec un Rsync : pas besoin de plus compliqué, cela me suffit amplement. Un serveur web devant, un certificat <a href="https://letsencrypt.org">Let’s Encrypt</a> et voilà !</p>
<p>J’ai ainsi pu obtenir une note convenable, selon <a href="https://developer.mozilla.org/fr/observatory/analyze?host=sylvain.dev">l’observatoire Mozilla</a> et <a href="https://cryptcheck.fr/https/sylvain.dev">Cryptcheck</a>. Il me reste néanmoins un peu de travail à faire sur les <a href="https://developer.mozilla.org/fr/docs/Web/HTTP/CSP">CSP (Content Security Policy)</a>, ce concept n’est pas évident à appréhender 😣 !</p>
<h3 id="5.-seo" tabindex="-1"><a class="heading-link" href="#5.-seo">5. SEO</a></h3>
<p>Il s’agit de ma première réelle expérience SEO<sup class="footnote-ref"><a href="#fn3" id="fnref3"><span class="visually-hidden">note </span>3</a></sup> et Jekyll offre de nombreux plugins<sup class="footnote-ref"><a href="#fn4" id="fnref4"><span class="visually-hidden">note </span>4</a></sup> permettant de générer des sitemap, un flux <a href="https://fr.wikipedia.org/wiki/RSS">RSS</a>, des métadonnées, … J’ai donc essayé de tirer profit de cela au maximum.</p>
<h2 id="workflow" tabindex="-1"><a class="heading-link" href="#workflow">Workflow</a></h2>
<p>Mon processus de développement est assez simple :</p>
<ul>
<li>Je développe en local mes articles et pages.</li>
<li>Le code est versionné sur <a href="https://github.com/sylvainmetayer/sylvainmetayer">Github</a></li>
<li>Travis s’assure de la qualité du site, avec des tests de validité des liens et des images, ainsi que la structure des pages HTML.</li>
<li>Travis déploie une version (correspondant à la branche master) de production.</li>
<li>Je déploie également avec une autre branche une version de développement, qui me permet de tester le site avant d’effectuer un merge sur master :smiley:</li>
</ul>
<h2 id="un-nouveau-site%2C-pour-quoi-faire" tabindex="-1"><a class="heading-link" href="#un-nouveau-site%2C-pour-quoi-faire">Un nouveau site, pour quoi faire</a></h2>
<p>Ce site va principalement me servir à exposer mes projets réalisés, et à effectuer ma veille technologique. J’y écrirai des articles sur mes expériences de développement, afin de garder une trace de ce qui m’est arrivé. Je ne m’impose cependant aucun rythme de publication, il est donc possible que le site reste quelques mois sans nouveaux contenus.</p>
<p><span id="evolutions"></span></p>
<h2 id="%C3%A9volutions" tabindex="-1"><a class="heading-link" href="#%C3%A9volutions">Évolutions</a></h2>
<p>Ce site est fonctionnel, mais pourtant il me reste quelques petits éléments à améliorer/régler.</p>
<h3 id="syst%C3%A8me-de-commentaire" tabindex="-1"><a class="heading-link" href="#syst%C3%A8me-de-commentaire">Système de commentaire</a></h3>
<p>Étant sur un site statique, il n’est pas possible d’inclure des commentaires directement, puisqu’il n’y a aucun traitement côté serveur.</p>
<p>Évidemment, il est possible d’intégrer des solutions telles que <a href="https://disqus.com/">Disqus</a> ou encore <a href="https://developers.facebook.com/docs/plugins/comments/">Facebook Comments</a> mais ces solutions étant peu protectrices de notre vie privée, j’ai préféré chercher une alternative.</p>
<p>Après quelques recherches, j’ai trouvé 2 solutions :</p>
<ol>
<li><a href="https://posativ.org/isso/">Isso</a></li>
<li><a href="https://staticman.net/">Staticman</a></li>
</ol>
<p>Le premier est un serveur de commentaire basique et léger écrit en Python. Je n’ai pas encore eu beaucoup de temps à consacrer à ce sujet, notamment pour l’auto-héberger, mais je pense qu’il s’agit d’une très bonne solution et risque de me pencher dessus dans les prochaines semaines !</p>
<p>Le deuxième semblait très prometteur mais malheureusement victime de son succès. En effet, il s’agit d’un bot Github, interagissant avec le dépôt Github, et qui ajoute les commentaires directement dans la branche <code>master</code> ou crée une pull request si une approbation est nécessaire avant la publication des commentaires.</p>
<p>De plus, comme indiqué sur leur site, cet outil s’intègre très bien avec Jekyll et Github. Néanmoins, il utilise l’API Github, et étant un projet public commençant à prendre de l’ampleur, les limitations de l’API Github semblent bloquer/ralentir ce projet, entraînant de nombreuses erreurs.</p>
<p>Une solution pour parer au problème serait d’auto-héberger le projet avec une clé d’API Github personnelle mais semble beaucoup pour “simplement des commentaires”, même si j’aimais beaucoup l’idée de pouvoir avoir des pull request pour chaque commentaire !</p>
<blockquote>
<p>Edit : Les commentaires sont maintenant disponibles ! 💥</p>
<p><a href="/article/ajout-commentaires">Voir l’article</a></p>
</blockquote>
<h2 id="conclusion" tabindex="-1"><a class="heading-link" href="#conclusion">Conclusion</a></h2>
<p>Merci à tous d’avoir lu cet article, j’espère qu’il vous aura plu.</p>
<p>Si vous avez des remarques, n’hésitez pas à me faire vos retours !</p>
<hr class="footnotes-sep">
<section class="footnotes" aria-label="Notes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>Scalable Vector Graphics <a href="#fnref1" class="footnote-backref" aria-label="Retour au texte (note 1)">↩︎</a></p>
</li>
<li id="fn2" class="footnote-item"><p>Ce qui n’est en soi pas une mauvaise chose, si une totale liberté était donnée à tous, ils se retrouveraient sûrement avec des sites mal configurés dans certains cas et leur infrastructure pourrait alors être compromise ! <a href="#fnref2" class="footnote-backref" aria-label="Retour au texte (note 2)">↩︎</a></p>
</li>
<li id="fn3" class="footnote-item"><p><a href="https://fr.wikipedia.org/wiki/Optimisation_pour_les_moteurs_de_recherche">Définition Wikipédia du SEO</a> <a href="#fnref3" class="footnote-backref" aria-label="Retour au texte (note 3)">↩︎</a></p>
</li>
<li id="fn4" class="footnote-item"><p>Pour en citer quelques-uns : <code>jekyll-sitemap</code>, <code>jekyll-seo-tag</code> et <code>jekyll-feed</code> <a href="#fnref4" class="footnote-backref" aria-label="Retour au texte (note 4)">↩︎</a></p>
</li>
</ol>
</section>

    ]]>
      </content>
      
        <category term="jekyll"/>
      
        <category term="blog"/>
      
      
        <summary type="html">
          Après quelques années d&#39;existence, mon ancien site commençait à vieillir.
        </summary>
      
    </entry>
  
    
    <entry>
      <title>Latex Starter Kit</title>
      <link href="https://www.sylvain.dev/article/latex-starterkit/"/>
      <published>2018-11-01T00:00:00Z</published>
      <updated>2018-11-01T00:00:00Z</updated>
      <id>https://sylvain.dev/article/latex-starterkit/</id>
      <content type="html">
        <![CDATA[
      <p><a href="https://github.com/sylvainmetayer/LaTeX-starterkit">Sources (Github)</a></p>
<p>Ce projet personnel a été réalisé pour disposer d’un modèle lors de la réalisation d’écrits avec LaTeX.</p>
<p>Il utilise également <a href="https://travis-ci.org/">Travis CI</a> afin de générer automatiquement le PDF lors du tag sur le dépôt Github et permet d’effectuer une vérification orthographique basique.</p>

    ]]>
      </content>
      
        <category term="latex"/>
      
        <category term="projet"/>
      
      
        <summary type="html">
          Ce projet personnel a été réalisé pour disposer d&#39;un modèle lors de la réalisation d&#39;écrits avec LaTeX.
        </summary>
      
    </entry>
  
    
    <entry>
      <title>Configuration d&#39;un serveur avec Ansible</title>
      <link href="https://www.sylvain.dev/article/ansible/"/>
      <published>2018-09-15T00:00:00Z</published>
      <updated>2018-09-15T00:00:00Z</updated>
      <id>https://sylvain.dev/article/ansible/</id>
      <content type="html">
        <![CDATA[
      <p><a href="https://github.com/EPSIBordeaux/ansible-deployment">Sources (Github)</a></p>
<p><a href="https://www.ansible.com/">Consulter le site d’Ansible</a></p>
<p>J’ai réalisé ce projet personnel afin de me familiariser avec Ansible et pouvoir recréer un serveur à l’identique sans intervention humaine.</p>
<p>Le choix d’Ansible m’a semblé intéressant car il ne nécessite pas l’installation d’un agent sur le serveur cible pour effectuer le déploiement. Seul Python est requis, et la plupart, pour ne pas dire la totalité des serveurs linux disposent de python de base. De plus, la syntaxe pour écrire les playbooks (jeu d’instructions) est du <a href="http://yaml.org/">YAML</a>, simple à lire et à écrire.</p>
<p>J’ai tenté de réaliser les différents playbooks de la façon la plus modulaire possible, rendant l’ajout de fonctionnalités simple.</p>
<p>Ce projet permet ainsi de :</p>
<ul>
<li>Déployer un serveur et le sécuriser avec des clés SSH, Fail2Ban, Iptables.</li>
<li>Déployer certaines applications réalisées lors de ma formation (afin de tester plusieurs types de déploiement, que ce soit des applications en PHP ou en NodeJS)</li>
<li>Mettre en place une solution de monitoring avec <a href="https://mmonit.com/monit/">Monit</a></li>
<li>Configurer automatiquement un serveur Web (Nginx) et effectuer des demandes de certificats HTTPS auprès de <a href="https://letsencrypt.org/">Let’s Encrypt</a> de façon automatique, y compris pour le renouvellement.</li>
</ul>
<p>Le travail sur ce projet n’est pas encore terminé, puisqu’il reste encore par exemple à gérer la question de la sauvegarde et de la restauration des données des différentes applications installées. <a href="https://github.com/EPSIBordeaux/ansible-deployment/issues">Vous pouvez contribuer au projet à cette adresse</a>.</p>

    ]]>
      </content>
      
        <category term="devops"/>
      
        <category term="projet"/>
      
      
        <summary type="html">
          J&#39;ai réalisé ce projet personnel afin de me familiariser avec Ansible et pouvoir recréer un serveur à l&#39;identique sans intervention humaine.
        </summary>
      
    </entry>
  
    
    <entry>
      <title>TBM Interruption Tracker Bot</title>
      <link href="https://www.sylvain.dev/article/tbm-interruption/"/>
      <published>2018-02-14T00:00:00Z</published>
      <updated>2018-02-14T00:00:00Z</updated>
      <id>https://sylvain.dev/article/tbm-interruption/</id>
      <content type="html">
        <![CDATA[
      <p><a href="https://github.com/sylvainmetayer/tbm_interruption_tracker">Sources (Github)</a> <a href="https://twitter.com/tbm_issues_bot">Compte Twitter : @tbm_issues_bot</a></p>
<p>J’ai réalisé ce bot afin de permettre un suivi des interruptions des trams bordelais.</p>
<p>Les informations sont récupérées depuis les comptes officiels Twitter de TBM, et repère des mots clés afin de compter les jours sans interruptions.</p>
<p><img src="/images/tbm_tracker_bot.jpg" alt="Photo de profil du bot : rails de tramway qui se croisent sur des pavés" title="Le bot tweete tous les jours, à 18h."></p>

    ]]>
      </content>
      
        <category term="ruby"/>
      
        <category term="twitter"/>
      
        <category term="bot"/>
      
      
        <summary type="html">
          J&#39;ai réalisé ce bot afin de permettre un suivi des interruptions des trams bordelais.
        </summary>
      
    </entry>
  
    
    <entry>
      <title>Projets réalisés en LP DAWIN</title>
      <link href="https://www.sylvain.dev/article/projets-dawin/"/>
      <published>2017-07-31T00:00:00Z</published>
      <updated>2017-07-31T00:00:00Z</updated>
      <id>https://sylvain.dev/article/projets-dawin/</id>
      <content type="html">
        <![CDATA[
      <p>Le présent article liste les différents projets que j’ai pu réaliser durant mon année de licence professionnelle DAWIN<sup class="footnote-ref"><a href="#fn1" id="fnref1"><span class="visually-hidden">note </span>1</a></sup> à l’IUT de Gradignan. Ces projets ont été réalisés la plupart du temps en binôme ou en groupe.</p>
<h2 id="agent-ready" tabindex="-1"><a class="heading-link" href="#agent-ready">Agent Ready</a></h2>
<p><a href="https://github.com/sylvainmetayer/agent-ready/">Sources (Github)</a> <a href="https://agent-ready.pages.dev/">Voir le jeu</a></p>
<p>Le but de ce projet était de réaliser un ‘Jeu dont vous êtes le héros’ avec diverses actions, tout en utilisant jQuery.</p>
<p>Ce projet a été réalisé lors de ma licence professionnelle DAWIN.</p>
<p><img src="/images/agent-ready.png" alt="Page d'accueil du jeu « Agent Ready, an Ingress Story » avec le bouton « Commencer l'immersion ! »"></p>
<h2 id="macbernick" tabindex="-1"><a class="heading-link" href="#macbernick">Macbernick</a></h2>
<p><a href="https://github.com/sylvainmetayer/macbernik">Sources (Github)</a> <a href="https://sylvainmetayer.github.io/macbernik/">Voir le jeu</a></p>
<p>Ce projet a été réalisé durant ma licence professionnelle DAWIN.</p>
<p>Il a été réalisé durant une semaine (janvier 2017) avec 6 autres étudiants et nous a initiés au déroulement d’un projet agile, de l’idée à la livraison du projet.</p>
<p>Il s’agit d’un jeu sur navigateur dans lequel on joue contre l’ordinateur (plusieurs niveaux de difficulté) ou à 2 joueurs (localement) pour obtenir le plus de points possible.</p>
<p><img src="/images/macbernick.png" alt="Écran d'accueil de MacBernick, « Famille Pirate » : jouer contre un ami, contre Bigorneau (facile), contre Victor (moyen), meilleurs scores"></p>
<h2 id="tetris" tabindex="-1"><a class="heading-link" href="#tetris">Tetris</a></h2>
<p><a href="https://github.com/sylvainmetayer/tetris">Sources (Github)</a> <s class="dead-link" title="Le jeu n'est plus maintenu ni disponible sur le Play Store">Télécharger le jeu</s> (plus maintenu, plus disponible)</p>
<p>Projet universitaire réalisé afin de se familiariser avec le développement d’application Android.</p>
<p>Le but était de réaliser un Tetris. Le jeu a ensuite été publié sur le PlayStore et est disponible au téléchargement.</p>
<p><img src="/images/tetris.png" alt="Partie perdue du Tetris sur Android : grille de blocs, temps 00:26, score 100 et message « Vous avez perdu ! »"></p>
<h2 id="semaine-innovante" tabindex="-1"><a class="heading-link" href="#semaine-innovante">Semaine Innovante</a></h2>
<p><a href="https://github.com/sylvainmetayer/semaine-innovante-dawin">Sources (Github)</a></p>
<p>La semaine innovante fait partie de la formation DAWIN, durant laquelle le but est de réaliser une application innovante.</p>
<p>Une grande liberté nous a été donnée pour réaliser les projets et nous avons eu à disposition différents outils.</p>
<p>Nous avons travaillé sur le fitbit, et plus particulièrement le <a href="https://www.fitbit.com/fr/charge2">Fitbit Charge 2</a> qui intègre un capteur cardiaque. Nous avons ainsi réalisé une application permettant d’effectuer un <a href="https://fr.wikipedia.org/wiki/Test_de_Ruffier">test de Ruffier</a> et d’afficher les résultats en récupérant les données via l’API de Fitbit.</p>
<hr class="footnotes-sep">
<section class="footnotes" aria-label="Notes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>Développement d’Application Web et Innovation Numérique <a href="#fnref1" class="footnote-backref" aria-label="Retour au texte (note 1)">↩︎</a></p>
</li>
</ol>
</section>

    ]]>
      </content>
      
        <category term="android"/>
      
        <category term="javascript"/>
      
        <category term="fitbit"/>
      
        <category term="dawin"/>
      
        <category term="projet"/>
      
      
        <summary type="html">
          Le présent article liste les différents projets que j&#39;ai pu réaliser durant mon année de licence professionnelle DAWIN à l&#39;IUT de Gradignan
        </summary>
      
    </entry>
  
    
    <entry>
      <title>Projets réalisés - EPSI Bordeaux</title>
      <link href="https://www.sylvain.dev/article/projets-epsi/"/>
      <published>2017-07-31T00:00:00Z</published>
      <updated>2017-07-31T00:00:00Z</updated>
      <id>https://sylvain.dev/article/projets-epsi/</id>
      <content type="html">
        <![CDATA[
      <p>Le présent article liste une partie des projets que j’ai pu réaliser durant mes deux années à l’EPSI Bordeaux. La plupart du code réalisé sur ces deux années est disponible au sein de l’organisation Github <a href="https://github.com/EPSIBordeaux">EPSIBordeaux</a></p>
<h2 id="open-innovation" tabindex="-1"><a class="heading-link" href="#open-innovation">Open innovation</a></h2>
<blockquote>
<p>25 février 2019</p>
</blockquote>
<p><a href="https://github.com/EPSIBordeaux/memoryProject">Sources (Github)</a> <s class="dead-link" title="L'application n'est plus maintenue ni disponible sur Expo">Tester l’application</s> (plus maintenue, plus disponible)</p>
<p>Ce projet, réalisé en équipe, s’inscrivait dans la démarche Open Innovation de l’EPSI, impliquant plusieurs promotions et nécessitant donc d’être organisé. L’objectif était de réaliser un jeu de “Jeu dont vous êtes le héros” sur mobile, en laissant la possibilité de personnaliser simplement le parcours de jeu.</p>
<p>Nous avons développé la première version avec <a href="https://reactnative.dev/">React Native</a> afin de fournir un support pour Android et iOS.</p>
<h2 id="ar-cube" tabindex="-1"><a class="heading-link" href="#ar-cube">AR-Cube</a></h2>
<blockquote>
<p>1 février 2019</p>
</blockquote>
<p><a href="https://github.com/EPSIBordeaux/ar-cube">Sources (Github)</a> <a href="https://epsibordeaux.github.io/ar-cube/">Testez-le sur mobile !</a></p>
<p>Ce projet, réalisé avec une équipe de 4 personnes, avait pour objectif d’être une introduction à la réalité augmentée.</p>
<p>À l’aide de la librairie Javascript <a href="https://github.com/jeromeetienne/AR.js">AR.js</a>, il fallait réaliser le dessin d’un cube en réalité virtuelle, lorsque les marqueurs étaient détectés à l’aide de la caméra du téléphone utilisé. Il fallait également que ce dernier puisse évoluer si l’on venait à bouger le téléphone.</p>
<p>Pour tester le résultat, imprimez le patron du cube présent sur le dépôt Github. Coloriez les faces de différentes couleurs et rendez-vous sur <a href="https://epsibordeaux.github.io/ar-cube/">cette adresse</a> depuis votre mobile. Après avoir autorisé l’usage de la caméra, pointez votre téléphone vers le patron et observez le résultat !</p>
<h2 id="earthquake" tabindex="-1"><a class="heading-link" href="#earthquake">Earthquake</a></h2>
<blockquote>
<p>1 février 2019</p>
</blockquote>
<p><a href="https://github.com/EPSIBordeaux/earthquake">Sources (Github)</a> <a href="https://epsibordeaux.github.io/earthquake/">Voir le résultat</a></p>
<p>Ce projet, réalisé avec une équipe de 3 personnes, avait pour objectif d’être une introduction à WebGL.</p>
<p>À l’aide de la librairie Javascript <a href="https://threejs.org/">three.js</a>, il fallait réaliser une carte du monde indiquant les différents séismes (récupérés à l’aide de l’API <a href="https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/significant_month.geojson">Earthquake.usgs.gov</a>) ainsi que leur gravité/épicentre.</p>
<h2 id="pong" tabindex="-1"><a class="heading-link" href="#pong">Pong</a></h2>
<blockquote>
<p>30 septembre 2018</p>
</blockquote>
<p><a href="https://github.com/EPSIBordeaux/temps-reel">Sources (Github)</a></p>
<p>Ce projet, réalisé en binôme durant ma formation à l’EPSI, avait pour but de concevoir un jeu avec un système temps réel.</p>
<p>Nous avons donc décidé de réaliser un pong, en utilisant l’API mise à notre disposition pour ce projet.</p>
<p><img src="/images/pong.png" alt="Écran du jeu de Pong : choix du joueur et de l'adversaire, terrain avec les deux raquettes et la balle"></p>
<h2 id="syst%C3%A8me-expert" tabindex="-1"><a class="heading-link" href="#syst%C3%A8me-expert">Système Expert</a></h2>
<blockquote>
<p>20 mai 2018</p>
</blockquote>
<p><a href="https://github.com/EPSIBordeaux/epsi-expert-system">Sources (Github)</a></p>
<p>Ce projet avait pour but de concevoir un système expert capable de détecter des formes (rectangle, carré, triangle, …).</p>
<p>Pour ce faire, nous avions à notre disposition une base de faits et de règles. Pour résoudre le problème, nous ajoutons nos faits et faisons tourner notre algorithme avec la base de règles, qui va comparer les différentes conditions et retourner la bonne réponse.</p>
<p>Le projet a été réalisé avec NodeJS et a été testé avec <a href="https://www.cypress.io/">Cypress</a>.</p>
<h2 id="bot-telegram" tabindex="-1"><a class="heading-link" href="#bot-telegram">Bot Telegram</a></h2>
<blockquote>
<p>30 mars 2018</p>
</blockquote>
<p><a href="https://github.com/EPSIBordeaux/Telegram_Bot">Sources (Github)</a> <a href="https://telegram.me/EPSI_UsainBot"><s>Parler avec le Bot</s> Bot hors ligne</a></p>
<p>Ce projet, réalisé en binôme, avait pour but de réaliser un chatbot de recrutement.</p>
<p>Nous avons choisi de réaliser ce bot sur la plateforme <a href="https://telegram.org/">Telegram</a>. L’objectif du bot était de poser quelques questions de développement puis de réseau afin de déterminer le niveau du candidat. Si le candidat a un niveau suffisant, alors une proposition lui est faite et il est invité à renseigner ses coordonnées pour être recontacté. Dans le cas contraire, on lui demande s’il souhaite laisser ses coordonnées afin d’être recontacté lorsque de nouvelles offres seront disponibles.</p>
<h2 id="machine-learning" tabindex="-1"><a class="heading-link" href="#machine-learning">Machine Learning</a></h2>
<blockquote>
<p>20 février 2018</p>
</blockquote>
<p><a href="https://github.com/EPSIBordeaux/epsi-expert-system">Sources (Github)</a></p>
<p>Ce projet, réalisé en binôme durant ma formation à l’EPSI, avait pour but de découvrir le fonctionnement des algorithmes de machine learning.</p>
<video controls muted preload="none" poster="/images/machine_learning-poster.webp" width="960" height="468" aria-label="Vidéo du projet Machine Learning, sans son, 4 min" aria-describedby="machine-learning-video">
  <source src="/images/machine_learning.mp4" type="video/mp4">
  <track kind="captions" src="/images/machine_learning.fr.vtt" srclang="fr" label="Français">
  Désolé, votre navigateur ne permet pas de lire la vidéo.
</video>
<p id="machine-learning-video">Ce que montre la vidéo : le résultat du projet. On fait un dessin dans un canvas, et l'application détecte l'emoji qui lui correspond.</p>
<p><a href="/images/machine_learning.mp4">Télécharger la vidéo (MP4, 1,2 Mo)</a></p>

    ]]>
      </content>
      
        <category term="android"/>
      
        <category term="javascript"/>
      
        <category term="php"/>
      
        <category term="epsi"/>
      
        <category term="projet"/>
      
      
        <summary type="html">
          Le présent article liste les différents projets que j&#39;ai pu réaliser durant mes deux années à l&#39;EPSI Bordeaux
        </summary>
      
    </entry>
  
    
    <entry>
      <title>L&#39;effet Parthenay</title>
      <link href="https://www.sylvain.dev/article/l-effet-parthenay/"/>
      <published>2017-03-28T00:00:00Z</published>
      <updated>2017-03-28T00:00:00Z</updated>
      <id>https://sylvain.dev/article/l-effet-parthenay/</id>
      <content type="html">
        <![CDATA[
      <blockquote>
<p>Traduction de l’article “The Parthenay Effect: How a Small French Town Might Save Civilization” paru le 27 mars 2017 sur <a href="https://www.huffingtonpost.com/entry/the-parthenay-effect-how-a-small-french-town-might_us_58d810c8e4b0c0980ac0e73f?">The Huffington Post</a></p>
</blockquote>
<blockquote>
<p>⚠ Avertissement<br>
Je ne suis ni traducteur, ni bilingue. Mon objectif est de fournir une traduction de cet article pour les personnes ayant des difficultés avec l’anglais. Bien qu’ayant tenté de traduire au mieux cet article, je ne peux garantir l’exactitude de ce qui suit.</p>
<p>Tous les droits sur cet article, ainsi que les photos, reviennent à sa rédactrice <a href="https://www.huffingtonpost.com/author/rebecca-novick">Rebecca Novick</a>.</p>
</blockquote>
<p><img src="/images/parthenay-1.jpg" alt="Rue de la vau Saint-Jacques" title="Rue Saint Jacques, le passage du pèlerin par Parthenay sur le pèlerinage de Saint Jacques de Compostelle"></p>
<p>Le printemps dernier, j’ai déménagé à Parthenay, une ville de 11.000 habitants, ce qui est un petit peu plus qu’un village. Il est normal que vous n’en ayez jamais entendu parler. Même mes amis français ont dû chercher où cela se situait. C’est également une commune, ou plutôt ce qui est appelé une “communauté de communes” avec 6 communes voisines. Elle est située dans le département des Deux-Sèvres, au cœur de la Nouvelle Aquitaine et au sud de la vallée de la Loire. La ville de Parthenay a une beauté ancienne avec peu de lignes droites et beaucoup de paniers à fleurs et de toits en tuiles rouges. Les gens marchent souvent avec tellement de baguettes à la main que vous vous demandez comment ils peuvent toutes les manger. Il y a même des distributeurs de baguette automatiques, prêts pour ces inévitables urgences. Pour ceux qui vivent dans les villages environnants, une fourgonnette livre du pain fraîchement cuit à votre porte (vous pouvez également acheter la moitié d’une baguette pour 47 centimes). Il y a tellement de gens qui élèvent des poulets que des œufs frais sont constamment échangés entre voisins, et peu daigneraient consommer ceux élevés en batterie. Même ma maison située dans l’hyper-centre de la ville est paisible parmi ces bourdonnements d’oiseaux qui rappellent à nombre d’entre nous des souvenirs d’enfants. J’avais voyagé pendant quelques mois en Inde une fois, et j’étais habituée à beaucoup de chaos et d’agitation. Il m’a fallu quelques mois pour m’habituer à cette nouvelle tranquillité.</p>
<blockquote>
<p>“C’est tellement calme ici”, disais-je à un ami. “C’est l’heure du déjeuner” me répondit-il. Puis, souriant, il ajouta : “Ça sera encore plus calme après le déjeuner.”</p>
</blockquote>
<p>La seule fois où mon sommeil a été interrompu par une perturbation humaine fut durant une nuit d’été, pendant un festival de musique. J’ai été réveillée à 3 heures du matin par le bruit d’un jeune homme qui jouait de la guitare et chantait une ballade française dans la rue, sous la fenêtre de ma chambre. J’étais ici, heureuse, avant de retomber dans les bras de Morphée.</p>
<p>Parthenay repose dans une courbe de la rivière du Thouet, vieux français pour “Tranquille”. Établi au milieu du 11ème siècle, ses charmantes maisons médiévales et son château donnent l’impression de la terre du Milieu croisée avec le château de Tintagel (<em>Note du traducteur : Tintagel est une localité et une paroisse civile de la côte nord-ouest du comté de Cornouailles en Angleterre.</em>). Parthenay est située dans l’une des Gâtines de la France. Le mot ‘Gâtine’ est connu dans la légende arthurienne pour être un endroit stérile et déserté. La prophétie dit que la terre deviendra fertile une fois la quête du Saint Graal achevée. Le nom fait référence au granit rocheux qui rend l’agriculture difficile. Mais il est riche en faune. (<em>traduction manquante</em>). Ses haies abritent des lapins et ses chênes et hêtres sont des postes de sentinelles pour les buses. Ses champs sont remplis de moutons mais aussi de la superbe race locale de vaches, la “Parthenaise”, rousse et musclée. Les terres du Sud Deux-Sèvres sont de loin bien plus cultivables. Des champs de tournesol offrent une vue magnifique en été. Le blé, l’avoine, les pommes de terre, les pommes et les noix sont cultivés en abondance et le marché aux légumes du mercredi est rempli d’agriculteurs vendant des fromages de chèvres locaux et des tomates de la taille d’une balle de tennis. Vingt ans plus tôt, le gouvernement français payait les agriculteurs pour qu’ils laissent leur terre en jachère un an afin qu’ils puissent recommencer sans pesticides. Ce léger mouvement pour les produits bio a reçu assez peu d’attention.</p>
<p>Des méandres amènent sur un moulin abandonné ou sur un ruisseau bouillonnant, des chênes ou encore une église à moitié oubliée. Aucune industrie dans les environs et l’air purifiant des eaux de l’Atlantique, je n’hésite pas à inspirer profondément l’air de Gâtine dans mes poumons. J’ai vécu à Londres, Los Angeles et New Delhi. Ici, je peux respirer d’une façon que j’avais presque oubliée. J’ai un jour été choquée de voir une canette de Coca-Cola flotter dans le Thouet. C’était parce que ce déchet était une aberration que je l’ai remarqué.</p>
<p><img src="/images/parthenay-2.jpg" alt="Le Thouet" title="La rivière du Thouet un jour d'été."></p>
<p>J’ai vécu une grande partie de ma vie dans les montagnes et je pensais qu’elles me manqueraient, mais les ciels de Gâtine sont infinis, à tel point que les nuages deviennent ici des montagnes, formant les gammes de la chaîne de l’Himalaya. Le soleil prend tellement de temps à se lever que vous pouvez vous amuser des heures durant avec des palettes kaléidoscopiques de violet, vermillon, topaze et magenta. Une étendue non obstruée vers l’Ouest offre aux habitants de la Gâtine ce que j’appelle “Le second soleil”, surtout en été. Alors que le soleil descend, aux alentours de vingt heures, il tombe souvent derrière une nuée de nuages mais comme il n’y a pas de bâtiment bloquant la vue à l’horizon, il réémerge une demi-heure plus tard, offrant jusqu’à deux heures supplémentaires de sa lumière. Cette topographie explique pourquoi Parthenay enregistre le deuxième plus grand temps d’ensoleillement dans toute la France. Ce ciel spacieux et le peu de pollution lumineuse sont faits pour les amateurs d’astronomie. Une fois, en août, un groupe d’amis et moi avons conduit jusqu’à un endroit surnommé la “colline du lapin” et avons regardé en silence les météores des Perséides exécuter leur ballet argenté à travers le firmament.</p>
<p><img src="/images/parthenay-3.jpg" alt="Le ciel de Parthenay aux aurores" title="Le ciel de Parthenay aux aurores."></p>
<p>Parthenay et ses environs ont été en grande partie protégés du développement rongeant le monde moderne. Après avoir échappé à la pollution et à l’architecture sans âme, les <a href="https://www.parthenaisiens.fr/">Parthenaisiens</a> (habitants de Parthenay) ont aussi surpassé les nombreuses formes de cynismes et narcissismes ravageant le psychisme moderne. Le rythme de vie est simple, respectueux, calme, et cela fournit le cadre parfait pour cette espèce en voie de disparition, le temps.</p>
<p>Je me promène régulièrement ici, en explorant les passages étroits et les escaliers de pierre qui relient la ville ensemble, tout en jetant un œil aux vieilles portes en bois qui s’ouvrent sur les vergers de pommiers et les jardins d’herbes médiévales. Je m’allonge dans l’herbe et j’entends les chants des grives et des merles, l’odeur de l’herbe et de la terre dans mes narines. Je me sens comme j’ai autrefois été une enfant. J’ai entrepris des projets photos avec Parthenay comme sujet. Elle est profondément photogénique mais sans la vanité des grandes villes françaises. Je l’étudie sous différentes lumières et différentes saisons, sous beaucoup d’angles, et j’écris à propos d’elle dans mon <a href="https://web.archive.org/web/20170328045502/https://theparthenayproject.com/">blog, le “Projet Parthenay”</a>. La ville a été nommée Ville d’Arts et d’Histoire. De nombreux artistes vivent ici, un nombre impressionnant de professeurs de Yoga et de Qi Gong ainsi qu’une communauté d’invalides indépendante.</p>
<p>Alors que je me promène dans les rues le soir, ma caméra à mes côtés, les chats sautent des murs, se frottent contre mes jambes pour une caresse. Les locaux sont assis dans des cafés sirotant le café noir en parcourant les journaux locaux ou en partageant une blague sur les minuscules verres de Rosé (à la différence des Britanniques, les Français tiennent l’alcool. À ce jour, je n’ai entendu qu’une histoire d’état d’ivresse sur la voie publique, ce qui a alimenté les conversations des semaines durant, tellement cela était rare).</p>
<blockquote>
<p>Il est tout à fait normal de saluer plutôt que d’ignorer un étranger ici. Même les jeunes vous saluent lorsque vous leur passez devant.</p>
</blockquote>
<p>Mais la ville ne prospère pas. Les enseignes ferment à un rythme alarmant et presque toutes les rues sont à vendre, les vitrines converties en mini galeries d’art. Les anciennes industries textiles ont disparu, ainsi que le train, qui a transporté ses derniers passagers il y a 23 ans. Une zone commerciale à la périphérie de la ville a aspiré la quasi-totalité des commerces du centre-ville. (<em>traduction manquante</em>). Les quelques touristes qui arrivent à cet endroit (au détour d’une sortie en vélo le plus souvent) marchent comme s’ils avaient trébuché sur leur propre conte de fées. Parthenay est une beauté endormie, attendant d’être réveillée.</p>
<p><img src="/images/parthenay-4.jpg" alt="Porte Saint-Jacques" title="Porte Saint Jacques, sur le Thouet, ancienne porte de pèlerinage de Parthenay"></p>
<p>Pourtant, cela n’a pas toujours été le cas. Parthenay était autrefois une ville marchande, capitale de la Gâtine Vendéenne. Pendant des siècles, c’était une étape importante sur le Camino de Compostela, le pèlerinage à la crypte de Saint Jacques, censé avoir le pouvoir de pardonner tous les péchés, qui traversait toute la France et se terminait à la Cathédrale de Santiago de Compostela au nord-ouest de l’Espagne. Depuis les années 1980, le Camino, ou la “voie” a connu une renaissance spectaculaire attirant près de 300.000 pèlerins modernes par an, venant du monde entier. L’itinéraire original prenait des mois à effectuer, mais de nos jours, même les plus aventureux commencent leur voyage près de la frontière espagnole, le long des Pyrénées, sur la frontière française. Pourtant, j’imagine des réfugiés du fascisme arrivant comme des pèlerins par l’ancienne voie de la Porte Saint Jacques, qui se dresse au-dessus de la rivière, accueillant les naufragés de cette triste civilisation en déclin.</p>
<p>Les matins d’automne, la brume recouvre les rues et les champs. La ville fortifiée de Parthenay est construite sur une légende. Il est dit qu’elle a été créée par la baguette d’une femme magique, nommée Mélusine. Il y a trois couches de fortifications faites à partir de granit. En effet, c’est un endroit digne de protection. Il y a plus une éthique de vie qu’une éthique de travail ici. La seule chose ouverte le dimanche est l’église. Les déjeuners durent deux à trois heures et sont considérés comme un moment sacré. Même les restaurants sont fermés le lundi et beaucoup ne sont ouverts que quelques heures par semaine, avec des écriteaux sur leurs portes disant “Heure d’ouverture 14-17h le mercredi”. Oui, il peut être compliqué de faire quelque chose. Mais ça va, puisqu’il y a le temps de le faire ici.</p>
<p><img src="/images/parthenay-5.jpg" alt="Le Thouet, vu depuis les murs du château" title="Le Thouet, vu depuis les murs du château."></p>
<p>Est-ce que j’exagère ? Oui, mais seulement un peu. Bien sûr, de mauvaises choses arrivent, même à Parthenay. Il y a de la méchanceté ici également. Il y a des commérages et de la jalousie. Ce n’est pas pour tout le monde. Il n’y a pas d’hypermarché, seulement une petite salle de cinéma, et peu de grandes chaînes industrielles. L’heure de pointe sont quelques Peugeot qui se bousculent pour une place. Pas même un Starbucks (chut !), ce qui est ironique puisque leur logo est basé sur la dame à queue de poisson, Mélusine, elle-même. Mais il y a plus que ça. Je suis d’un côté effrayée d’en parler, et de l’autre effrayée de ne pas en parler. Si la ville dort, pourquoi ne pas la laisser dormir ? Récemment, un de mes amis discutait à propos d’<a href="https://fr.wikipedia.org/wiki/Hylozo%C3%AFsme">hylozoïsme</a>, la théorie comme quoi les objets inanimés auraient une conscience et peuvent, dans une certaine mesure faire leurs propres choix. Une ville peut-elle choisir ses résidents ? J’aime à penser que les pierres et brouillards de Parthenay sont en quelque sorte capables de décider qui vient, et qui pourra s’installer ici. Comme nos gouvernements continuent de nous décevoir, nous devons créer plus de communautés intentionnelles dans le monde.</p>
<p>Pour moi, Parthenay est comme un refuge dans cette tempête. Ici, j’apprends à dérouler les nœuds de mon passé, à embrasser la paix sous toutes ses formes. Je me souviens de la maison d’Elrond dans le Seigneur des Anneaux qui accueillait les voyageurs épuisés et leur fournissait un endroit où ils pouvaient retrouver leur énergie ainsi que leur inspiration. Comme l’écrit Tolkien, ‘Si seulement il y avait une cure pour la fatigue, la peur et la tristesse.’</p>
<p>Parthenay est ma maison d’Elrond. Pourrait-elle être la vôtre ?</p>

    ]]>
      </content>
      
        <category term="autres"/>
      
        <category term="parthenay"/>
      
      
        <summary type="html">
          L&#39;effet Parthenay : Comment une petite ville pourrait bien sauver la civilisation française.
        </summary>
      
    </entry>
  
    
    <entry>
      <title>Développement d&#39;une solution de recherche de données personnelles</title>
      <link href="https://www.sylvain.dev/article/cartographie-gdpr/"/>
      <published>2017-02-01T00:00:00Z</published>
      <updated>2017-02-01T00:00:00Z</updated>
      <id>https://sylvain.dev/article/cartographie-gdpr/</id>
      <content type="html">
        <![CDATA[
      <p>Lors de mon alternance à Atos en Licence Professionnelle DAWIN, j’ai eu l’occasion de développer la première version d’un outil de recherche de données personnelles dans le cadre du <a href="https://web.archive.org/web/20170123025715/http://www.eugdpr.org/">GDPR</a> (General Data Protection Regulation)</p>
<p>Le projet a été réalisé en Python avec une équipe de trois personnes.</p>
<p>J’ai travaillé avec les méthodes agiles (<a href="https://fr.wikipedia.org/wiki/Scrum_(d%C3%A9veloppement)">SCRUM</a>) afin de réaliser un outil capable de s’adapter à plusieurs <a href="https://fr.wikipedia.org/wiki/Base_de_donn%C3%A9es_relationnelle">SGBDR</a>.</p>

    ]]>
      </content>
      
        <category term="atos"/>
      
        <category term="python"/>
      
        <category term="projet"/>
      
      
        <summary type="html">
          Lors de mon alternance à Atos en Licence Professionnelle DAWIN, j&#39;ai eu l&#39;occasion de développer la première version d&#39;un outil de recherche de données personnelles dans le cadre du GDPR
        </summary>
      
    </entry>
  
    
    <entry>
      <title>Nuit de l&#39;info</title>
      <link href="https://www.sylvain.dev/article/nuit-info/"/>
      <published>2016-12-02T00:00:00Z</published>
      <updated>2016-12-02T00:00:00Z</updated>
      <id>https://sylvain.dev/article/nuit-info/</id>
      <content type="html">
        <![CDATA[
      <p><a href="https://github.com/Clovis-Portron/Nuit-info2016">Source de l’édition 2016 ( Char Ibout; )</a></p>
<p>La nuit de l’info réunit étudiants, enseignants et entreprises afin de réaliser en une nuit une application web sur un thème national donné.</p>
<p>Accompagné d’une équipe de 14 personnes, j’ai eu l’occasion de participer à l’édition 2015 à Bordeaux.</p>
<p>J’ai également participé à l’édition 2016 de cet évènement, toujours à Bordeaux, accompagné d’une équipe de 10 personnes.</p>

    ]]>
      </content>
      
        <category term="dawin"/>
      
        <category term="dut-info"/>
      
      
        <summary type="html">
          La nuit de l&#39;info réunit étudiants, enseignants et entreprises afin de réaliser en une nuit une application web sur un thème national donné.
        </summary>
      
    </entry>
  
    
    <entry>
      <title>Projets réalisés en DUT Info</title>
      <link href="https://www.sylvain.dev/article/projets-dut-info/"/>
      <published>2016-06-30T00:00:00Z</published>
      <updated>2016-06-30T00:00:00Z</updated>
      <id>https://sylvain.dev/article/projets-dut-info/</id>
      <content type="html">
        <![CDATA[
      <p>Le présent article liste les différents projets que j’ai pu réaliser durant mes années de DUT Informatique à Limoges. Ces projets ont été réalisés la plupart du temps en binôme, ou en groupe.</p>
<h2 id="bataille-navale" tabindex="-1"><a class="heading-link" href="#bataille-navale">Bataille navale</a></h2>
<p><a href="https://github.com/sylvainmetayer/BatailleNavale">Source (Github)</a> <a href="https://github.com/sylvainmetayer/BatailleNavale/blob/master/versionGraphique.jar?raw=true">Version Graphique (.jar)</a></p>
<p>Réalisé en binôme entre mars et mai 2015, ce projet nous a permis de nous familiariser avec Java Swing et de constituer nos premières interfaces graphiques.</p>
<p>Le jeu se joue à deux joueurs, avec la possibilité de sauvegarder les parties.</p>
<p>Il était demandé de réaliser une version console et une version graphique du jeu.</p>
<p><img src="/images/bataille_navale.jpg" alt="Illustration de bataille navale : un cuirassé fait feu de nuit sur une mer agitée"></p>
<p><span id="betisier-de-l%E2%80%99iut"></span></p>
<h2 id="b%C3%AAtisier-de-l%E2%80%99iut" tabindex="-1"><a class="heading-link" href="#b%C3%AAtisier-de-l%E2%80%99iut">Bêtisier de l’IUT</a></h2>
<p><a href="https://github.com/sylvainmetayer/Betisier-TP">Source (Github)</a> <a href="https://betisier.sylvain.dev">Voir le site</a></p>
<p>Ce projet universitaire constituait une découverte du PHP. Il consistait à réaliser un site rassemblant les perles de profs, permettant leur ajout, notation par des élèves, …</p>
<p>Un module d’administration était également demandé, afin de gérer entre autres les utilisateurs, et mettre un système de modération sur les citations.</p>
<p>Ce projet a été réalisé entre octobre et décembre 2015.</p>
<p><img src="/images/betisier.gif" alt="Logo du Bêtisier de l'IUT du Limousin : panneau de danger où un cerveau dévale une pente à 20 %"></p>
<h2 id="gemao" tabindex="-1"><a class="heading-link" href="#gemao">GEMAO</a></h2>
<p><a href="https://gitlab.com/TheoG/ProjetTuteure/tree/Pedagogie">Sources (Gitlab)</a></p>
<p>GEMAO<sup class="footnote-ref"><a href="#fn1" id="fnref1"><span class="visually-hidden">note </span>1</a></sup> est un projet tuteuré qui consistait à réaliser une application permettant la gestion d’une école de musique avec JavaEE.</p>
<p>Il s’agissait de la continuité d’un projet commencé l’année dernière par un autre groupe d’étudiants.</p>
<p>Réalisé en groupe (5 étudiants) pour l’école de musique Anacrouse, située à La Chapelle Saint Ursin, de septembre 2015 à avril 2016.</p>
<p><img src="/images/gemao.png" alt="Logo de L'Anacrouse, école de musique de La Chapelle Saint Ursin"></p>
<h2 id="pygame" tabindex="-1"><a class="heading-link" href="#pygame">Pygame</a></h2>
<p><a href="https://github.com/sylvainmetayer/pygame">Source (Github)</a></p>
<p>Ce projet universitaire consistait à réaliser un mini-jeu en réseau, à l’aide des librairies PyGame et PodSixNet.</p>
<p>Il a été réalisé entre février et avril 2016.</p>
<p><img src="/images/pygame.jpg" alt="Illustration du jeu : un envahisseur en pixel art, à la Space Invaders"></p>
<hr class="footnotes-sep">
<section class="footnotes" aria-label="Notes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>Gestion d’École de Musique Assistée par Ordinateur <a href="#fnref1" class="footnote-backref" aria-label="Retour au texte (note 1)">↩︎</a></p>
</li>
</ol>
</section>

    ]]>
      </content>
      
        <category term="java"/>
      
        <category term="php"/>
      
        <category term="python"/>
      
        <category term="dut-info"/>
      
        <category term="projet"/>
      
      
        <summary type="html">
          Le présent article liste les différents projets que j&#39;ai pu réaliser durant mes années de DUT Informatique à Limoges
        </summary>
      
    </entry>
  
    
    <entry>
      <title>Rapport DUT Informatique</title>
      <link href="https://www.sylvain.dev/article/memoire-dut/"/>
      <published>2016-06-20T00:00:00Z</published>
      <updated>2016-06-20T00:00:00Z</updated>
      <id>https://sylvain.dev/article/memoire-dut/</id>
      <content type="html">
        <![CDATA[
      <p><a href="https://gitlab.com/ocyhc/memoire-dut-info/tree/master" data-auth title="Accès réservé : nécessite un compte GitLab">Sources (Gitlab)</a> <a href="https://gitlab.com/ocyhc/memoire-dut-info/blob/master/main.pdf" data-auth title="Accès réservé : nécessite un compte GitLab">Voir le PDF</a></p>
<p>Ce mémoire détaille le travail réalisé durant mon stage au sein de <a href="https://www.nextmedia.fr/">NextMedia</a>, effectué d’avril à juillet 2016.</p>
<p>J’y ai réalisé la refonte de l’administration du site vitrine de la société, ainsi qu’un gestionnaire de version pour le produit phare de la société : <a href="https://www.quizzbox.com/fr/">un boîtier de vote interactif, Quizzbox</a>. Ce site permet ainsi aux différents clients de Quizzbox de pouvoir télécharger les versions du logiciel sur une plateforme, et d’avoir un suivi des mises à jour disponibles.</p>
<p>Pour ce projet, j’ai également été amené à générer des miniatures à partir d’un document PowerPoint, pour pouvoir afficher un aperçu du document sur le site.</p>
<p><img src="/images/rapport_dut.png" alt="Page de garde de mon rapport de stage de DUT Informatique"></p>

    ]]>
      </content>
      
        <category term="dut-info"/>
      
      
        <summary type="html">
          Ce mémoire détaille le travail réalisé durant mon stage au sein de Nextmedia
        </summary>
      
    </entry>
  
</feed>