Browse Source

Initial import.

master
David Soulayrol 2 months ago
commit
1538631d84
  1. 15
      .eslintrc.js
  2. 2
      .gitignore
  3. 5
      .stylelintrc.json
  4. 34
      assets/dev/css/ds.css
  5. 1
      assets/dev/css/simple.min.css
  6. BIN
      assets/dev/files/partitions/202010.pdf
  7. BIN
      assets/dev/files/partitions/202106.pdf
  8. BIN
      assets/dev/files/partitions/202107.pdf
  9. BIN
      assets/dev/fonts/Colombia-Rp0DV.ttf
  10. BIN
      assets/dev/fonts/ColombiaItalic-BWGZB.ttf
  11. 1
      assets/production
  12. 77
      content/cv/2000_cv_dsoulayrol.txt
  13. 2363
      content/cv/20051010_cv_dsoulayrol.pdf
  14. BIN
      content/cv/2012/2012_cv.pdf
  15. BIN
      content/cv/2012/2012_europass.pdf
  16. BIN
      content/cv/2012/2012_experiences.pdf
  17. 60
      content/cv/2012/cv.tex
  18. 65
      content/cv/2012/europass.tex
  19. 57
      content/cv/2012/experience.tex
  20. 169
      content/cv/2012/fragments/atlantide.tex
  21. 24
      content/cv/2012/fragments/contact.tex.in
  22. 52
      content/cv/2012/fragments/formation.tex
  23. 5
      content/cv/2012/fragments/interests.tex
  24. 3
      content/cv/2012/fragments/leisure.tex
  25. 38
      content/cv/2012/fragments/netcentrex.tex
  26. 22
      content/cv/2012/fragments/nexcom.tex
  27. 2
      content/cv/2012/fragments/skills_languages.tex
  28. 1
      content/cv/2012/fragments/skills_methods.tex
  29. 1
      content/cv/2012/fragments/skills_protocols.tex
  30. 1
      content/cv/2012/fragments/skills_systems.tex
  31. 3
      content/cv/2012/fragments/skills_tools.tex
  32. 38
      content/cv/2012/makefile
  33. 111
      content/cv/2022/2022_cv_dsoulayrol.ms
  34. 14
      content/cv/2022/README
  35. 99
      content/documents/hide-long-headers.md
  36. 108
      content/documents/identifying-contexts-in-logs.md
  37. 298
      content/documents/using-firefox-micro-summaries.md
  38. BIN
      content/documents/using-firefox-micro-summaries/screenshot-live_titles-1.png
  39. BIN
      content/documents/using-firefox-micro-summaries/screenshot-live_titles-2.png
  40. BIN
      content/documents/using-firefox-micro-summaries/screenshot-live_titles-3.png
  41. BIN
      content/documents/using-firefox-micro-summaries/screenshot-xpath-1.png
  42. BIN
      content/documents/using-firefox-micro-summaries/screenshot-xpath-2.png
  43. 1267
      content/documents/wonderful-26.md
  44. 53
      content/index.md
  45. 24
      layouts/default.njk
  46. 14
      layouts/document.njk
  47. 17
      layouts/footer.njk
  48. 14575
      package-lock.json
  49. 62
      package.json
  50. 20
      scripts/config.js
  51. 108
      scripts/metalsmith-helpers.js
  52. 63
      scripts/metalsmith-statistics-plugin.js
  53. 82
      scripts/metalsmith.js
  54. 71
      scripts/run.js

15
.eslintrc.js

@ -0,0 +1,15 @@
module.exports = {
env: {
browser: true,
commonjs: true,
es2021: true
},
extends: [
'standard'
],
parserOptions: {
ecmaVersion: 12
},
rules: {
}
}

2
.gitignore

@ -0,0 +1,2 @@
dist
node_modules

5
.stylelintrc.json

@ -0,0 +1,5 @@
{
"extends": "stylelint-config-standard",
"ignoreFiles": ["**/*.min.css"]
}

34
assets/dev/css/ds.css

@ -0,0 +1,34 @@
@font-face {
font-family: colombia;
src: url(/fonts/Colombia-Rp0DV.ttf);
}
@font-face {
font-family: colombia;
src: url(/fonts/ColombiaItalic-BWGZB.ttf);
font-style: italic;
}
body {
margin: 1em 0;
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-family: colombia, sans-serif;
margin: 1em 0 0.4em 0;
padding: 0;
}
footer {
padding: 0;
}
p {
margin: 0 0 0.4em 0;
padding: 0;
}

1
assets/dev/css/simple.min.css

File diff suppressed because one or more lines are too long

BIN
assets/dev/files/partitions/202010.pdf

Binary file not shown.

BIN
assets/dev/files/partitions/202106.pdf

Binary file not shown.

BIN
assets/dev/files/partitions/202107.pdf

Binary file not shown.

BIN
assets/dev/fonts/Colombia-Rp0DV.ttf

Binary file not shown.

BIN
assets/dev/fonts/ColombiaItalic-BWGZB.ttf

Binary file not shown.

1
assets/production

@ -0,0 +1 @@
dev/

77
content/cv/2000_cv_dsoulayrol.txt

@ -0,0 +1,77 @@
David Soulayrol
Français, 23 ans, célibataire.
Dégagé des obligations militaires.
60, Les Hauts de la fontaine
34980 - COMBAILLAUX
Tel.: 0 671 057 557
david.soulayrol@enib.fr
Ingénieur en Développement Informatique
Expérience professionnelle
==========================
* Stage en entreprise -- Ifremer, Centre de Brest. Durée : 5 mois
Développement d'un logiciel de navigation en temps réel pour le
positionnement de bouées acoustiques sous-marines.
Le logiciel a été réalisé sous LabVIEW de National Instruments. Il
comprend essentiellement trois parties : manipulation de données GPS (à
l'aide d'une bibliothèque de fonctions C), réception et tri des données
provenant de l'unité acoustique BENTHOS DS-7000 à travers une liaison série
RS-232 et enfin intégration de ces données dans un algorithme de type
moindres carrés.
Ce stage m'a permis de découvrir les outils LabVIEW et MatLab. J'ai
en outre participé à l'installation de Linux (SuSE 6.1) sur plusieurs PC,
ainsi qu'à leur intégration dans le réseau du laboratoire. Cela m'a permis
d'approfondir mes connaissances sur les systèmes UNIX.
Formation
=========
Elève Ingénieur
Actuellement en dernière année à l' Ecole Nationale d'Ingénieurs de
Brest.
Projet de Fin d'études : ARéVi
ARéVi est un outil de gestion et de navigation au sein
d'environnements virtuels orienté agents. Il est développé sous Visual C++.
Mon rôle consistait à implémenter une interface entre le logiciel et
des moteurs de synthèse et de reconnaissance vocale. J'ai en outre porté le
support de périphériques (gant de données) depuis une version Unix sur
Windows.
Modules d'approfondissement suivis :
* Systèmes Temps Réel
* Intelligence Artificielle
* Interfaces
* Réalité virtuelle
Baccalauréat Série E
Lycée Mas de Tesse, Montpellier (1994).
Connaissances acquises
======================
Langages maitrisés :
C, C++, Prolog, Langage G de LabVIEW.
Langages abordés :
Assembleur (sur MC68k et Intel x86), Java, Scheme, Perl, HTML,
JavaScript.
Systèmes d'exploitation :
Unix (Linux, System V et BSD, Irix), Windows 9x/NT, DOS.
Systèmes temps réel :
VxWorks.
Langue vivante :
Anglais : lu+++, parlé++, écrit+++
Autres activités
================
* Administration des services réseaux pour les étudiants de l'Enib. Ce
réseau comprend une dizaine de machines sous Linux.
* Participation au projet DreamOs (www.dreamos.fr.st).
* Musique (guitare), lecture...
* Activités de plein air : marche, cerf-volant, ...

2363
content/cv/20051010_cv_dsoulayrol.pdf

File diff suppressed because it is too large

BIN
content/cv/2012/2012_cv.pdf

Binary file not shown.

BIN
content/cv/2012/2012_europass.pdf

Binary file not shown.

BIN
content/cv/2012/2012_experiences.pdf

Binary file not shown.

60
content/cv/2012/cv.tex

@ -0,0 +1,60 @@
\documentclass[10pt,a4paper]{moderncv}
\usepackage{ucs}
\usepackage[utf8x]{inputenc}
\usepackage[frenchb]{babel}
\usepackage{ifthen}
% Type of document
\newboolean{europass}
\setboolean{europass}{false}
\newboolean{cv}
\setboolean{cv}{true}
\newboolean{details}
\setboolean{details}{false}
% Custom style
\addtolength{\textwidth}{2cm}
\addtolength{\hoffset}{-1cm}
\addtolength{\textheight}{1cm}
\addtolength{\voffset}{-1cm}
%\setlength{\parskip}{0.5cm}
\moderncvtheme[orange]{classic}
\AtBeginDocument{\recomputelengths}
% Personal data
\input{fragments/contact}
\begin{document}
\maketitle
\renewcommand{\labelitemi}{$\triangleright$ }
\section{Expérience professionnelle}
\input{fragments/nexcom}
\input{fragments/netcentrex}
\input{fragments/atlantide}
\section{Formation}
\input{fragments/formation}
\section{Compétences}
\cvline{Langages}{\input{fragments/skills_languages}}
\cvline{Outils}{\input{fragments/skills_tools}}
\cvline{Protocoles}{\input{fragments/skills_protocols}}
\cvline{Systèmes}{\input{fragments/skills_systems}}
\cvline{Méthodologies}{\input{fragments/skills_methods}}
\section{Langues}
\cvlanguage{Anglais}{Courant}{}
\section{Intérêts}
\cvline{Logiciel Libre}{\input{fragments/interests}}
\cvline{Loisirs}{\input{fragments/leisure}}
\section{Addenda}
\cvlistitem[$\triangleright$ ]{Nationalité Française}
\cvlistitem[$\triangleright$ ]{Permis B}
\end{document}

65
content/cv/2012/europass.tex

@ -0,0 +1,65 @@
\documentclass[a4paper,french,arial,narrow]{europecv}
\usepackage{ucs}
\usepackage[T1]{fontenc}
\usepackage[utf8x]{inputenc}
\usepackage[frenchb]{babel}
\usepackage{graphicx} % Required to draw the logo
\usepackage[a4paper,top=1.27cm,left=1cm,right=1cm,bottom=2cm]{geometry}
\usepackage{url}
\usepackage{ifthen}
% Type of document
\newboolean{europass}
\setboolean{europass}{true}
\newboolean{cv}
\setboolean{cv}{false}
\newboolean{details}
\setboolean{details}{false}
% Define personal data.
\input{fragments/contact}
\begin{document}
\begin{europecv}
\ecvpersonalinfo[5pt]
%\ecvitem{\large\textbf{Desired employment/ Occupational~field}}{\large\textbf{(Remove if not relevant)}}
\ecvsection{Expérience professionnelle}
\input{fragments/netcentrex}
\input{fragments/atlantide}
\ecvsection{Éducation et formation}
\input{fragments/formation}
\ecvsection{Aptitudes et compétences personnelles}
\ecvmothertongue[5pt]{français}
\ecvitem{\large Autre(s) langue(s)}{}
\ecvlanguageheader{(*)}
\ecvlanguage{Anglais}{\ecvCOne}{\ecvCTwo}{\ecvBTwo}{\ecvCOne}{\ecvCTwo}
\ecvlanguagefooter[10pt]{(*)}
% \ecvitem[10pt]{\large Aptitudes et compétences sociales}{}
% \ecvitem[10pt]{\large Aptitudes et compétences organisationnelles}{}
% \ecvitem[10pt]{\large Aptitudes et compétences techniques}{}
\ecvitem[10pt]{\large Aptitudes et compétences informatiques}{
\begin{itemize}
\item \input{fragments/skills_languages}
\item \input{fragments/skills_protocols}
\item \input{fragments/skills_tools}
\item \input{fragments/skills_systems}
\item \input{fragments/skills_methods}
\end{itemize}
}
\ecvitem[10pt]{\large Aptitudes et compétences artistiques}{
\begin{itemize}
\item pratique de la guitare
\end{itemize}
}
% \ecvitem[10pt]{\large Other skills and competences}{Replace this text by a description of these competences and indicate where they were acquired (remove if not relevant).}
\ecvitem{\large Permis de conduire}{B}
\ecvsection{Additional information}
\ecvitem{}{\textbf{Personal interests}}
\ecvitem{}{\input{fragments/interests}}
\end{europecv}
\end{document}

57
content/cv/2012/experience.tex

@ -0,0 +1,57 @@
\documentclass[10pt,a4paper]{moderncv}
\usepackage{ucs}
\usepackage[utf8x]{inputenc}
\usepackage[frenchb]{babel}
\usepackage{ifthen}
\usepackage{color}
% Type of document
\newboolean{europass}
\setboolean{europass}{false}
\newboolean{cv}
\setboolean{cv}{true}
\newboolean{details}
\setboolean{details}{true}
% Custom style
\addtolength{\textwidth}{2cm}
\addtolength{\hoffset}{-1cm}
\addtolength{\textheight}{1cm}
\addtolength{\voffset}{-1cm}
\definecolor{steel}{rgb}{0.9, 0.9, 1.0}
%% \newcommand*{\cvsubentry}[2]{%
%% \cvline{\small{#1}}{%
%% \newline{}\begin{minipage}[t]{\linewidth}\small#2\end{minipage}}}
\newcommand*{\cvsubentry}[2]{%
\cvline{\tiny{#1}}{%
\begin{minipage}[t]{\linewidth}\small{#2}\end{minipage}}}
\newcommand*{\skills}[1]{%
\vspace{3mm}%
\colorbox{steel}{%
\begin{minipage}{\maincolumnwidth}%
\textit{Environnement technique :} #1\end{minipage}}}
\moderncvtheme[blue]{classic}
\AtBeginDocument{\recomputelengths}
% Personal data
\input{fragments/contact}
\begin{document}
\maketitle
\renewcommand{\labelitemi}{$\triangleright$ }
\section{Expérience professionnelle}
\input{fragments/nexcom}
\input{fragments/netcentrex}
\input{fragments/atlantide}
\section{Formation}
\input{fragments/formation}
\end{document}

169
content/cv/2012/fragments/atlantide.tex

@ -0,0 +1,169 @@
\newcommand{\job}{Ingénieur Consultant}
% The following does not work:
% ! Extra alignment tab has been changed to \cr.
% <template> ...egin \relax \d@llarend \endtemplate
%
% l.35 }{}
\ifthenelse{\boolean{europass}}{
\ecvitem{Dates}{Septembre 2000 $\rightarrow$ Avril 2006}
\ecvitem{Fonction ou poste occupé}{TODO}
\ecvitem{Principales activités et responsabilités}{TODO}
\ecvitem[15pt]{Nom et adresse de l'employeur}{
Atlantide --
Technopôle Brest Iroise - Site du Vernis, 300 rue Pierre Rivoalon,
CS 23866, 29238 Brest Cedex 3 (France)
}
}{}
\ifthenelse{\boolean{cv}}{
\ifthenelse{\boolean{details}}{
\cventry{2004 -- 2006}{\job}{Thales Systèmes Aéroportes}{pour Atlantide Brest}{}{
Le TIS est un \textit{framework} objet développé par Thalès Systèmes
Aéroportés pour le développement et l’exécution des différentes
fonctions de ses systèmes. Le nouveau module de GSM s’appuie sur
CARDAMOM, un produit opensource de SC2 procurant des services
CORBA. Le GSM doit être capable de déployer un système, le
superviser, et lui apporter une tolérance aux pannes logicielles
et matérielles.
\\
\begin{itemize}
\item Prise en main de CARDAMOM et développement d’une maquette
mettant en \oe{}uvre les différentes fonctions du GSM ;
\item spécification, développement et supervision des parties
sous-traitées, mise en place des tests du composant GSM.
\end{itemize}
\skills{Linux (Red Hat W.S. 3.0), C++, CORBA (ACE/TAO), CARDAMOM,
SGBDOO Versant, scripts}
}
\cventry{2000 -- 2004}{\job}{FRANCE TELECOM R\&D}{pour Atlantide Brest}{}{
}
\cvsubentry{2003 -- 2004}{
Dans le cadre de l'évolution d’une plateforme CTI
(\textit{Computer Telephony Interface}) de services
téléphoniques, création pour FT R\&D Caen d’un pilote RFC2217
pour la gestion d’un nouveau type de PRCG (PABX Remote Control
Gateway). La plateforme est constituée de plusieurs serveurs
répartis communiquant par RMI-IIOP et s’appuyant sur le serveur
d’application J2EE JoNAS.
\\
\begin{itemize}
\item Conception et modélisation UML, puis développement du nouveau pilote
en Java, et intégration dans les serveurs existant ;
\item mise à jour des services actuels, de l’interface Web en JSP sur
Tomcat.
\end{itemize}
\skills{Windows et Linux (Red Hat), Java, JSP, Jakarta Commons-Net,
RMI-IIOP, Xerces, scripts}
}
\cvsubentry{2002 -- 2003}{
Développement à FT R\&D Lannion d'un Poste Opérateur via la
protocole XMPP pour un \textit{proxy} H323. Le Poste Opérateur
permet de superviser les appels en cours sur un site
d'entreprise, d'effectuer des transferts, de parquer et
reprendre des interlocuteurs.
\\
\begin{itemize}
\item Conception et modélisation UML ;
\item développement en C++ d'un client Jabber pour émuler les
différents postes téléphoniques. Un serveur Jabber modifié est
utilisé pour le routage des données formatées en XML (Le principe,
dans ce contexte, fait l'objet d'un brevet de la part de FT R\&D
Lannion) ;
\item écriture de scripts de gestion de la plate-forme, de
création des paquetages RPM.
\end{itemize}
\skills{Linux (Mandrake, Sun Cobalt), C++, Jabber, scripts}
}
\cvsubentry{2001 -- 2002}{
Participation au développement pour FT R\&D Issy Les Moulineaux
des plate-formes de service téléphoniques et IM STAR puis eWork.
\\
La plate-forme STAR offre à un utilisateur nomade un bouquet de
services avancés de téléphonie et de messagerie instantanée,
configurables via un accès web. La Plate-forme eWork est une
extension de Star, offrant des services avancés supplémentaires
notamment dans le domaine de la messagerie instantanée : gestion
de la disponibilité et des contacts, partage de fichiers,
réunion et conférence chat ou téléphonique, ainsi qu’un couplage
avec Microsoft Exchange. Ces services restent configurables via
un accès Web mais sont également accessibles à l’aide d’un
client Java.
\\
\begin{itemize}
\item Conception et développement d’un serveur de données distribué
sur CORBA et basé sur le SGBD orienté objet Versant ;
\item gestion de la configuration du serveur à base de composants
XML (utilisation de l’API Xerces du projet APACHE) ;
\item développement de fonctions pour JNI pour des lanceurs
d’applications sous Windows.
\item modification des services existants et ajout de
nouvelles fonctionnalités dans le serveur d’applications et les
IHMs Web ;
\item développement d’un client Java ;
\item connexions à la plate-forme et échanges sécurisés (SSL, HTTPS,
MD5).
\end{itemize}
\skills{Windows NT, Java, JSP, JNI, Javascript, HTML, XML, XmlRpc, Jabber,
JabberBeans, CORBA (Orbacus), SGBDOO Versant, UML}
}
\cventry{2001 -- 2002}{\job}{RFS Lannion}{pour Atlantide Brest}{}{}
\cvsubentry{2002}{
Mise à jour d’un outil de simulation de cartes communiquant via le
port série.
\\
\begin{itemize}
\item Refonte de l’IHM et du modèle du moteur de simulation en C++ ;
\item réécriture des routines C de communication série, mise à
jour du protocole sur port série et augmentation des capacités
du simulateur ;
\item documentation de l’application : Diagramme de classes UML.
\end{itemize}
\skills{C++, Rational Rose.}
}
\cvsubentry{2001}{
Développement d'un logiciel de \textit{monitoring} embarqué sur
antenne GSM pour le projet DUAMCOF. La carte hôte est destinée à
surveiller le comportement des amplificateurs et autres
appareillages proches d’une antenne GSM. Elle communique avec un
serveur par l’intermédiaire d’un bus CAN.
\\
\begin{itemize}
\item Développement de la nouvelle version du logiciel DUAMCOF ;
modification des messages sur bus CAN et introduction d’une
communication par liaison série vers d’autres modules ;
\item développement d’outils annexes en C pour le formatage du
programme et la simulation de communications sur le bus série avec
les modules annexes.
\end{itemize}
\skills{C sur PC et Intel 505CA. Assembleur sur Intel 505CA, Bus CAN, CANAlyser}
}
\cventry{2000}{\job}{GIE SESAM VITALE}{pour Atlantide Brest}{}{
Développement de l'outil SIMPROGI permettant de tester les api
des services SESAM-VITALE.
\\
\begin{itemize}
\item Écriture de fonctions C avec JNI permettant l’utilisation de
l’API des services SESAM-Vitale depuis l’application Java ;
\item mise à jour et portage de nouvelles fonctionnalités de
SIMPROGI sur plate-forme Windows 32 bits ;
\item conception de nombreuses interfaces homme-machine utilisant
les composants SWING.
\end{itemize}
\skills{Java, SWING, JNI}
}
}{
\cventry{sept. 2000 -- avril 2006}{\job}{Atlantide}{Brest}{}{
\begin{itemize}
\item Développement pour FT R\&D d'un poste opérateur à l'aide du
protocole XMPP, d'un pilote RFC2217 pour la gestion d'un PRCG
(\textit{PABX Remote Control Gateway}), des plateformes de
services téléphoniques et de messagerie instantanée STAR, puis
eWork ;
\item développement d'un module de supervision pour le framework
CORBA de Thalès AS.
\end{itemize}
}
}
}

24
content/cv/2012/fragments/contact.tex.in

@ -0,0 +1,24 @@
\ifthenelse{\boolean{europass}}{
\ecvname{\textbf{David Soulayrol}}
\ecvfootername{David Soulayrol}
%\ecvaddress{__EXT_STREET, __EXT_CITY (France)}
%\ecvtelephone[__EXT_MOBILE]{__EXT_PHONE}
\ecvemail{\url{david@soulayrol.name}}
\ecvnationality{Française}
\ecvdateofbirth{11 Mai 1976}
\ecvgender{Masculin}
\ecvfootnote{\url{http://david.soulayrol.name}}
}{
\firstname{David}
\familyname{Soulayrol}
\ifthenelse{\boolean{details}}{
\title{Expériences}
}{
\title{Curriculum Vit\ae}
}
%\address{__EXT_STREET}{__EXT_CITY}
%\mobile{__EXT_MOBILE}
%\phone{__EXT_PHONE}
\email{david@soulayrol.name}
\extrainfo{\url{http://david.soulayrol.name}}
}

52
content/cv/2012/fragments/formation.tex

@ -0,0 +1,52 @@
\ifthenelse{\boolean{europass}}{
\ecvitem{Dates}{Septembre 1994 $\rightarrow$ Juin 2000}
\ecvitem{Intitulé du certificat ou diplôme délivré}{Diplôme Ingénieur ÉNIB.}
\ecvitem{Principales matières/compétences couvertes}{
TODO Enib details}
\ecvitem{Nom et type de l'établissement d'enseignement ou de formation}{
École Nationale d'Ingénieurs de Brest (France)
}
}{}
\ifthenelse{\boolean{cv}}{
\ifthenelse{\boolean{details}}{
\cventry{2000}{Projet de fin d'études}{}{Brest}{}{
Participation au portage d'ARÉVI d'Unix vers Windows. ARÉVI est
un outil de simulation et de navigation au sein d’environnements
virtuels orientés agents. Il est développé en C++ et s'interface
avec plusieurs sortes de périphériques d'immersion.
\\
\begin{itemize}
\item Implantation d’une interface entre le logiciel et des moteurs de
synthèse et de reconnaissance vocale Microsoft.
\item Portage du support d'un gant de données et de capteurs de
positionnement magnétiques (\textit{Flock of Birds}).
\end{itemize}
\skills{AIX, Windows, C++}
}
\cventry{1998 -- 1999}{Stagiaire}{Laboratoire de Physique des Océans, IFREMER}{Brest}{}{
Développement d’un logiciel LabView de navigation en temps réel pour le
positionnement de bouées acoustiques sous-marines.
\\
\begin{itemize}
\item Interfaçage du programme LabView avec les bibliothèques de
fonctions C pour l’accès aux données GPS ;
\item réception et tri des données provenant de l’unité
acoustique BENTHOS DS-7000 à travers un liaison série RS-232 ;
\item intégration de données dans un algorithme de type moindres
carrés.
\item Installation de Linux (SuSE 6.1) sur plusieurs PC.
\end{itemize}
\skills{Linux et Solaris, LabVIEW, Matlab, C, LaTeX}
}
}{
\cventry{1994 -- 2000}{Diplôme d'ingénieur}{École Nationale d'Ingénieurs}{Brest}{}{
Filière Informatique industrielle, modules d’approfondissement :
Systèmes Temps réel, Intelligence artificielle, Interfaces
hommes machines, Réalité virtuelle.
}
\cventry{1994}{Baccalauréat}{Lycée Mas de Tesse}{Montpellier}{}{Série E}
}
}

5
content/cv/2012/fragments/interests.tex

@ -0,0 +1,5 @@
Membre de l'APRIL (\url{http://april.org}).
\newline{}
Participation à des projets libres divers, traduction d’articles et
d’applications libres.

3
content/cv/2012/fragments/leisure.tex

@ -0,0 +1,3 @@
Littérature, musique, jardinage, voyages.
\newline{}
Pratique du tir à l'arc.

38
content/cv/2012/fragments/netcentrex.tex

@ -0,0 +1,38 @@
\newcommand*{\ncxsummary}{
\begin{itemize}
\item Membre de l'équipe de développement du \textit{Session Border
Controller} SIP des solutions logicielles de NetCentrex ;
\item proposition, mise en place et administration d'un
\textit{wiki} pour compléter la gestion documentaire du site ;
\item participation à la mise en place d'un serveur
d'intégration continue pour projets hétérogènes avec
\textit{CruiseControl}.
\end{itemize}
}
\ifthenelse{\boolean{europass}}{
\ecvitem{Dates}{Avril 2006 $\rightarrow$ Novembre 2010}
\ecvitem{Fonction ou poste occupé}{Ingénieur en Recherche et Développement}
\ecvitem{Principales activités et responsabilités}{TODO}
\ecvitem[15pt]{Nom et adresse de l'employeur}{
NetCentrex -- 4 Rue Louis de Broglie, 22300 Lannion (France)}
}{}
\ifthenelse{\boolean{cv}}{
\ifthenelse{\boolean{details}}{
\cventry{2006 -- }{Ingénieur R\&D}{NetCentrex}{Lannion}{}{
La société NetCentrex développe \textit{proxies} SIP, H323 et
solutions pour c\oe{}urs de réseau IMS. Le \textit{proxy} SIP
fonctionne aussi bien seul qu'inséré dans une plate-forme IMS
dans les rôles du P-CSCF ou IBCF.
\\
\ncxsummary
\skills{Linux (CentOS), C++, protocole SIP, scripts}
}
}{
\cventry{avril 2006-- }{Ingénieur R\&D}{NetCentrex}{Lannion}{}{
\ncxsummary
}
}
}{}

22
content/cv/2012/fragments/nexcom.tex

@ -0,0 +1,22 @@
\ifthenelse{\boolean{europass}}{
\ecvitem{Dates}{Décembre 2011 $\rightarrow$}
\ecvitem{Fonction ou poste occupé}{Ingénieur en Recherche et Développement}
\ecvitem{Principales activités et responsabilités}{TODO}
\ecvitem[15pt]{Nom et adresse de l'employeur}{
Nexcom Systems -- 4 Rue Ampère, BP30255, 22303 Lannion (France)}
}{}
\ifthenelse{\boolean{cv}}{
\ifthenelse{\boolean{details}}{
\cventry{2006 -- }{Ingénieur R\&D}{NetCentrex}{Lannion}{}{
NEXCOM Systems est un cabinet d’architecture technique, de
formation et de réalisation logicielle spécialisé dans le
domaine des nouveaux réseaux de télécommunications.
\\
\skills{Linux (Debian), C, Java, protocole SIP, JSR289}
}
}{
\cventry{décembre 2010-- }{Ingénieur R\&D}{Nexcom Systems}{Lannion}{}{}
}
}{}

2
content/cv/2012/fragments/skills_languages.tex

@ -0,0 +1,2 @@
Connaissance approfondie du C, C++, Python, XML. Bonne connaissance de
Java, JavaScript, Lisp, Lua, XHTML, XSLT, Vala et notions de Sed, Awk, PHP.

1
content/cv/2012/fragments/skills_methods.tex

@ -0,0 +1 @@
Pratiques agiles, UML.

1
content/cv/2012/fragments/skills_protocols.tex

@ -0,0 +1 @@
Internet (HTTP, IMAP, SMTP, \ldots), téléphonie (SIP, SDP), XMPP, CORBA.

1
content/cv/2012/fragments/skills_systems.tex

@ -0,0 +1 @@
Connaissance approfondie des environnements GNU/Linux (en particulier Debian).

3
content/cv/2012/fragments/skills_tools.tex

@ -0,0 +1,3 @@
GNU \textit{Autotools} et Make, bibliothèques C GLib, GTK+, oSIP,
bibliothèque standard C++, bibliothèque standard Python et lxml,
Emacs, jQuery, Gestion de version (git, subversion, bazaar) \ldots

38
content/cv/2012/makefile

@ -0,0 +1,38 @@
FRAGMENTS := $(shell ls fragments/*.tex)
SCRIPT := ' \
/__EXT_\w*/ { \
while (match($$0, /__EXT_\w*/, m)) { \
if (!ENVIRON[m[0]]) { \
next \
} \
sub(/__EXT_\w*/, ENVIRON[m[0]]); \
} \
sub(/%/, ""); \
} \
{ print }'
.PHONY: all clean distclean
all:
rm -f fragments/contact.tex
$(MAKE) cv.pdf experience.pdf europass.pdf
clean:
rm -f *.aux *.log *.out
distclean: clean
rm -f *.dvi *.pdf fragments/contact.tex
fragments/contact.tex: fragments/contact.tex.in
awk -v ad_street="$(CV_ADDRESS_STREET)" \
-v ad_city="$(CV_ADDRESS_CITY)" \
-v ph_mobile="$(CV_PHONE_MOBILE)" \
-v ph_home="$(CV_PHONE_HOME)" \
$(SCRIPT) $< > $@
%.dvi: %.tex ${FRAGMENTS} fragments/contact.tex
latex $<
%.pdf: %.dvi
dvipdf $< $@

111
content/cv/2022/2022_cv_dsoulayrol.ms

@ -0,0 +1,111 @@
.fam LM
.\# TODO: Marges
.\#
.\# Définition d'un titre de section
.de SECT
.sp .4
.LP
\s(12\fB\\$1\fP\s10
..
.\#
.TS
expand tab(|);
lp20 lIp10.
David Soulayrol|7 Allée des ajoncs
\^|2200 Lannion
\^|+33 6 62 68 24 22
\^|david@soulayrol.name
_
.TE
.LP
.ps 10
Développeur expérimenté dans le développement d'interfaces structurées et l'usage de protocoles de machine à machine désireux de travailler au plus près de logiciels libres.
.SECT Compétences
.IP •
Expertise sur une palette de langages impératifs ou orientés objet : C, C++, Java, JavaScript, Python. XML.
.IP •
Accoutumé à l'usage d'outils, bibliothèques ou techniques fréquentes : GNU Autotools et Make, GLib, Spring Boot, Maven, NodeJS, PostgreSQL, git
.IP •
Familier des protocoles Internet (HTTP, IMAP, SMTP, . . .), de téléphonie (SIP, SDP).
.IP •
Longue expérience à tous les niveaux de la pile logicielle, depuis l'écriture de logiciel embarqué jusqu'au développement d'un front-end Web.
.IP •
Skilled experience with the various issues and pitfalls of maintaining legacy code and reducing technical debt.
.IP •
Dévoué aux bonnes pratiques d'écriture et à la rédaction de code clair et structuré.
.SECT "Expérience professionnelle"
.IP •
De mai 2014 à aujourd'hui, \fBAthemium / Avidsen (Lannion)\fP
.RS
.IP —
Principal développeur des serveurs d'une solution domotique.
J'ai participé au développement du logiciel permettant la communication avec les réseaux Z-Wave, ZigBee et autres, et à celui du serveur supportant les comptes des utilisateurs et l'utilisation des objets communicants.
J'ai développé une passerelle avec le protocole MQTT et d'autres éléments, et conçu différentes interfaces d'inspiration REST pour la communication entre ces éléments et avec les interfaces.
J'ai également assuré la maintenance des différentes machines déployées.
.IP —
J'ai participé au développement du logiciel permettant la communication avec les réseaux Z-Wave, ZigBee et autres.
.RE
.IP •
De décembre 2010 à mai 2014, \fBNexcom (Lannion)\fP
.RS
.IP —
Participation au développement de solutions de télécommunication basées sur le protocole SIP et au développement du \fIframework\fP Cipango.
.RE
.IP •
D'avril 2006 à novembre 2010, \fBNetCentrex (Lannion)\fP
.RS
.IP —
Membre de l'équipe de développement du Session Border Controller SIP des solutions logicielles de NetCentrex ;
proposition, mise en place et administration d'un wiki pour compléter la gestion documentaire du site ;
participation à la mise en place d'un serveur d'intégration continue pour projets hétérogènes avec CruiseControl.
.RE
.IP •
De septembre 2000 à avril 2006, \fBAtlantide (Brest)\fP
.RS
.IP —
J'ai participé à la spécification, au développement et à l'encadrement de prestataires pour un module de supervision s'inscrivant dans le \fIframework\fP complexe CORBA de Thalès Systèmes Aéroportés.
.IP —
Pour FT R&D Caen, j'ai conçu, modélisé et développé un pilote RFC2217 en Java pour la gestion d’un nouveau type de PRCG (\fIPABX Remote Control Gateway\fP) sur une plateforme constituée de plusieurs serveurs (sur J2EE JoNAS) et communiquant par RMI-IIOP.
.IP —
J'ai développé pour FT R&D Lannion un poste opérateur sur XMPP permettant de superviser les appels (transferts, parquage et reprise des interlocuteurs) sur un site d'entreprise.
.IP —
J'ai conçu et développé un serveur de données distribué sur CORBA et basé sur le SGBD orienté objet Versant pour les plate-formes de services téléphoniques et de messagerie STAR puis eWork de FT R&D Issy Les Moulineaux.
.IP —
J'ai développé un logiciel de supervision embarqué sur antennes GSM permettant le contrôle de cartes communicant sur le bus CAN, et suis intervenu sur un outil C++ de simulation de ces cartes pour RFS Lannion.
.IP —
J'ai participé au développement de l'outil SIMPROGI permettant de tester les interfaces de programmation des services SESAM-VITALE.
.RE
.sp .4
.SECT "Formation"
.IP •
2000, \fIDiplôme d’ingénieur de l'École Nationale d’Ingénieurs de Brest\fP
.br
Filière Informatique industrielle, modules d’approfondissement : Systèmes Temps réel, Intelligence artificielle, Interfaces hommes machines, Réalité virtuelle.
.br
Projet de fin d'étude portant sur le développement de l'outil d'environnement virtuel orienté agents C++ ARÉVI.
.br
Stage au Laboratoire de Physique des Océans de l'IFREMER à Brest portant sur le développement d’un logiciel LabView de navigation en temps réel pour le positionnement de bouées acoustiques sous-marines.
.IP •
1994, \fIBaccalauréat série E\fP au lycée Mas de Tesse, Montpellier
.sp .4
.SECT "Réalisations et savoir-faires"
.IP —
Membre de l'APRIL (http://april.org), j'ai participé au développement ou à la traductions d'articles et de plusieurs logiciels libres depuis 2001.
https://github.com/dsoulayrol
https://apps.ti-nuage.fr/gitea/david
.IP —
Membre et administrateur de Ti Nuage (https://ti-nuage.fr), un fournisseurs de services numériques associatif.
.IP —
Grand lecteur, j'ai co-fondé et tenu le rôle de président de 2014 à 2020 de l'association Scorfel qui organise un festival annuel dédié à l'Imaginaire à Lannion.
Je suis membre actif de l'association NooSFere (https://www.noosfere.org) et du Club Présence d'Esprits (https://presences-d-esprits.com/), dédiées aux lectures de l'imaginaire. Je rédige des chroniques pour l'une et l'autre. (https://www.noosfere.org/livres/auteur.asp?numauteur=2147204009)
.IP —
Je joue du piano et de l'alto.
.IP —
Je parle, lis et écris l'anglais couramment.
.IP —
I maintain a portfolio of personal work at
.CW https://david.soulayrol.name

14
content/cv/2022/README

@ -0,0 +1,14 @@
La génération du document repose sur la police de caractères *Latin Modern* qui peut être télé-chargée depuis l'adresse suivante.
http://www.gust.org.pl/projects/e-foundry/latin-modern
L'installation de la police pour `groff` est grandement facilitée grâce au script `install-font.sh` de Peter Schaffter (merci à lui).
http://www.schaffter.ca/mom/mom-06.html#install-font
Pour l'installation, copier le script dans le répertoire contenant les fichiers de l'archive, et entrer les lignes suivantes avec les droits de l'utilisateur `root`. Le processus est interactif : donner les réponses proposées par défaut aux deux questions. Le drapeau `-s` signifie une installation dans `/usr/share/groff`, alors que `-l` (par défaut) procède à une installation dans `/usr/local/share/groff`.
./install-font.sh -s -F LM -f +R lmroman12-regular.otf
./install-font.sh -s -F LM -f +B lmroman12-bold.otf
./install-font.sh -s -F LM -f +I lmroman12-italic.otf

99
content/documents/hide-long-headers.md

@ -0,0 +1,99 @@
---
title: "How to hide long C headers"
date: 2010-03-29
lang: en
layout: document.njk
---
The problem came out to me because some people or teams embed their
changelog in the source file headers.
---
This gives something like this:
/**
* @file MySource.cpp
* @desc a Foo objects protubazor.
* @date 29/03/2009
*
* MODIFICATIONS:
* 2009-04-02: jsmith: Removed a useless variable.
* 2009-04-03: jsmith: Simplified the protubazor algorithm.
* 2009-06-10: jdoe: Fixed compilation warning.
*/
They will argue that this is the best way to check why a line has
changed in the past for example. I disagree with this. First, there
should be a file dedicated to the whole project history to trace
important updates. In GNU project, this is the **ChangeLog**
file. But above all, sources tracking is the very *raison d'être* of
version control. Every commit should be atomic and provide a
meaningful comment. If commits are correctly described, writing a
changelog inside the source is, at best, duplication of information,
and I *hate* that.
Besides, I think this is a very annoying habit because this
information will grow with time and eventually become as large as the
useful part of your source file. At last, working on these files will
involve lots of scrolling just to find the beginning of the code.
Anyway, there are those situations where I have no choice but to obey,
or to adapt myself. The solution I found is to hide these annoying
lines until I get forced to edit them (and then quickly hide them
again). To achieve this, I've written a function to customize the
**[hideshow minor mode][HS]** from **[emacs][EMACS]** behaviour on
file headers. It can be loaded this way for example:
(load-library "hideshow")
(add-hook 'c++-mode-hook 'hs-minor-mode)
(add-hook 'c-mode-hook 'hs-minor-mode)
**[hideshow][HS]** allows you to hide blocks of code. The meaning of
*blocks* depends on the language you are editing, I mean the current
major-mode. When hidden, the block is replaced by an ellipsis by
default, but the `hs-set-up-overlay` function can be used to customize
what is drawn inside a hidden block.
In the following implementation, I tweak the hideshow overlay so as to
indicate the number of missing lines in hidden blocks. If I detect
that the given block is a kind of comment and is at the beginning of
the file, I also search for the **MODIFICATIONS:** token, which is used to
introduced those damn changelogs. If I found it, I don't really hide
the block, but display its content minus everything following the
token (which I replace with the count of hidden lines).
(setq hs-set-up-overlay
(defun ds-lib-hs-overlay (ov)
(let ((content (format " [%d lines]..."
(count-lines (overlay-start ov)
(overlay-end ov)))))
(when (and (< (overlay-start ov) 80) (eq 'comment (overlay-get ov 'hs)))
(goto-char (point-min))
(goto-char (point-min))
(when (search-forward " MODIFICATIONS:" (overlay-end ov) t)
(setq content (format "%s [%d lines]...\n */ "
(buffer-substring (overlay-start ov) (point))
(- (count-lines (point) (overlay-end ov)) 2)))))
(overlay-put ov 'display content))))
(add-hook 'c++-mode-hook 'hs-hide-block t)
(add-hook 'c-mode-hook 'hs-hide-block t)
Thus, the sample given in the beginning would be displayed this way:
/**
* @file MySource.cpp
* @desc a Foo objects protubazor.
* @date 29/03/2009
*
* MODIFICATIONS: [3 lines]...
*/
Note that even if it seems to be displayed because I draw a large part
of it, the block is actually in an hidden state. That means that it
must be showed again before it can be edited at all.
[EMACS]: http://www.gnu.org/software/emacs/
[HS]: http://www.gnu.org/software/emacs/manual/html_node/emacs/Hideshow.html

108
content/documents/identifying-contexts-in-logs.md

@ -0,0 +1,108 @@
---
title: Identifying logical contexts in logs
date: 2012-05-05
lang: en
layout: document.njk
---
Some months ago, I had to track a bug for which appeared on one SIP
call, in a pre-production environment. So I had to dig a very lengthy
log file, with lots of information about many mixed calls.
This situation is not really a problem if you know exactly the call
you are tracking, thanks to its Call-ID or indirectly with a From or
To tag for example. Hopefully, your program already offers interesting
logs to address the problem, or you can provide a modified program to
gather more information. If not, you know the rest of the week will be
a pain.
---
In this case, I was lucky enough to have the opportunity to provide a
new binary with lots of logs in the area which caused the bug, but I
still had to search through thousand of lines to identify the path
which lead one call to trigger the error.
So I came up with a simple **[python](http://python.org)** script which
parsed the file for me and built a map from the logs I was interested
in. Each entry of the map was identified by an ID which was unique to
a call, and contained all the logs for this call in order of
appearance in the file. To achieve this, the script relied on a
regular expression which identified the logs I had added. At last, the
script dumped those contexts, which were far easier to read than the
initial file.
Then I got a new job, and I forgot this...
Until this week, when I had to identify in a very long file some
sixteen calls out of more than one thousand which were behaving
differently. So I wrote the following script in the vein of the
previous one. It can be quite easily adapted to other problems by
modifying the `PATTERN` constant. It can read multiple log files, and
it can output the number of contexts found, the number of lines read
for each one of these contexts, and dump them. I think it is self
explanatory, and it comes with inline help.
#!/usr/bin/env python
# argparse means Python 2.7 is required.
import argparse
import re
# The pattern can be customized to adapt the program behaviour to the
# kind of logs to be analysed. It must provide a group named `key'
# which will be used to identify the logs belonging to a same context.
PATTERN = '.+ \[INFO\] .* with Call-ID = (?P<key>[a-zA-Z0-9@\.-]+)'
def build_contexts(filenames):
contexts = {}
for n in filenames:
with open(n) as f:
e = re.compile(PATTERN)
while True:
l = f.readline()
if '' == l:
break
m = e.match(l)
if not m is None:
k = m.group('key')
if not k in contexts:
contexts[k] = []
contexts[k].append(l.strip())
return contexts
def display_context(contexts, key, cmd):
print '%s: %s' % (key, str(len(contexts[key])) + ' lines.' if cmd.summary else '')
if cmd.list:
for l in contexts[key]:
print '\t', l
def handle_contexts(contexts, cmd):
if not cmd.key is None:
if cmd.key in contexts:
display_context(contexts, cmd.key, cmd)
elif cmd.list or cmd.summary:
for key in contexts:
display_context(contexts, key, cmd)
print 'Total:', len(contexts), 'contexts'
# Main
parser = argparse.ArgumentParser(
description='Correlates log lines.',
epilog='See the PATTERN variable in the code to suit your needs')
parser.add_argument('files', metavar='file', type=str, nargs='+',
help='the file to inspect')
parser.add_argument('--get', action='store', dest='key',
help='search only the context with this key')
parser.add_argument('--list', action='store_true',
help='dump the contexts content')
parser.add_argument('--summary', action='store_true',
help='print a summary for each context found')
args = parser.parse_args()
handle_contexts(build_contexts(args.files), args)

298
content/documents/using-firefox-micro-summaries.md

@ -0,0 +1,298 @@
---
title: Using Firefox Micro-Summaries
date: 2007-04-29
lang: en
layout: document.njk
---
What are you doing when you're a geek and a nice girl is crying for
her own refurbed Apple laptop ? Yes, you find a way to monitor the
Store so as to be the first to be ready to buy next time.
---
## When geeks can be useful too
Karine recently decided that she wanted a laptop. I cannot remember
why, but she also decided that a MacBook would be definitively
cool. So we went to town and had a look at the hardware. Karine took
the time to search for benchmarks and tests to be comforted in her
choice. We started to track [eBay][] and Apple
*Refurb*. In the end, she realized that the *Refurb* offered the
warranties that she was looking for, with an interesting price saving.
Once the choice was made, began the time of the [Apple Store][] *Page
Refresh Syndrom*. The drama occured the day she was having a break,
and then the *one-click* susbscription refused to work before all the
nice MacBook had found new happy owners.
## Remember your greatest quality is laziness
There are many ways to monitor a page and to be notified when it is
updated. The easiest solution is to rely on what you can
find. Remember: *never reinvent the wheel* (or only if it's fun).
We first tried to find a plugin for *Firefox* that would show up a
notification when a page is updated and we installed [Notify][]. But
the plugin was sending far too false positive notifications (and
actually, it continues to do so while I'm writing this). I don't
pretend it does not work, but it didn't the job we wanted out of the
box, so we tried to find something else.
I could have written some Python script to crawl the *Refurb* for us
and provide us some summary of the available laptops. The most
difficult part of this solution would have been to handle the
notification: Karine was mainly using MS Windows both at work and at
home, and I didn't want to search for a graphical solution on this
platform. The notification could have been sent by mail, but I didn't
enjoy this solution at the moment, thinking it was too slow for our
need (I am not sure I have the same opinion today).
Then Karine found a short description about the *Live Titles*, or
*Micro Summaries* of *Firefox*. After some search, I found out that
this was in fact a way to define a dynamic bookmark label. I first
found [some samples](http://userstyles.org/livetitle) and later some
documentation to start with. I decided that I wanted to know more
about it.
You could say (will you ?) that this kind of notification is a very
shy one, and we have to check frequently the *Firefox* window to see
it some good news happened. And you would be right. But please
consider that for someone using a lot its computer and the web
browser, it's more interesting to have a quick glance at a label on
the windows than to have to refresh a page from a somewhat loaded
server. And *that* was what scratched my itch at this very moment,
nothing else.
## Time to write some code
### Micro Summaries... What's this?
Micro summaries simply consist of one XSL stylesheet which will be
associated to all bookmarked pages matching a given pattern. When you
bookmark a page whose URL matches a micro summary definition, the *Add
Bookmark* dialog provides you a combo box to define the title instead
of a text field, thus giving you the choice to set a static label or
to use the existing dynamic one.
[This page](http://wiki.mozilla.org/Microsummaries) introduces the
*Firefox* *micro summaries*, but
[this one](http://developer.mozilla.org/en/docs/Creating_a_Microsummary)
is far more interesting when it comes to the moment you have to write
your own.
At first, I was worried by the fact that all the provided samples were
very simple. They were often composed of one or two labels and some
values easely extracted from the bookmarked page. Then I realized that
they were XSLT documents after all, and that I probably could use all
the power of XSL transformations to build the label I wanted.
### Let's dive into it
First, micro summaries are XML documents, and they make use of XML
namespaces. It is very important to know about namespaces because a
micro summary document contains at least tags from two distinct ones:
`microsummaries`, and `XSL` of course.
A micro summary definition needs very few information. The root tag is
`generator`, from the `microsummaries` namespace, and has a name
attribute. The root tag has at least two children.
- `transform` holds the XSL sheet. The XSL namespace
must be present here.
- `pages` provides one or more `include` tags, each one
holding a regular expression that will be used to match a page URL
for which the micro summary can be used.
An additional `update` tag which specifies that the Summary will have
to be refreshed every five minutes. The update involves retrieving the
data from the website of course. You will find some other tags in
documentation which I confess I didn't try to study. All I needed was
there.
::XML
<?xml version="1.0" encoding="UTF-8"?>
<generator xmlns="http://www.mozilla.org/microsummaries/0.1" name="Applestore">
<template>
<transform xmlns="http://www.w3.org/1999/XSL/Transform" version="1.0">
<!-- All XSLT code goes here -->
</transform>
</template>
<pages>
<include>http://store\.apple\.com/Apple/WebObjects/francestore\.woa/.*</include>
</pages>
<update interval="5" />
</generator>
### Now, the AppleStore application
What I tried to retrieve first was some value to determine if MacBook
laptops were available. This could be done by searching the lines
announcing the refurbed products and looking for the one displaying
MacBook. So, I sit down and managed to remember the syntax of XPath
expressions to produce something like this:
/html/body//form/table[@id='rep']/tbody/tr/td/b
Which gave me the following result.
![Firefox displaying the result of the first XPath expression][screenshot-1]
**Caution:** Note that the XPath expressions given here rely on the
french refurb pages. They shall be adapted to get something
operational in other languages.
Of course, in the end, I would have kept only the text and get rid of
pictures (but it was cool to display this for the screenshot, and it
helps to understand what I have extracted from the page).
From there I thought I only had to search the lines where I could find
the string MacBook. But I realized that I needed to differentiate
MacBook and MacBook Pro. And I didn't know how to write some condition
with these inputs to distinguish both of them.
So I tried to gather another source of information in the page.
Meanwhile, I also decided to not only detect if MacBook laptops were
available but also to count how many there were. Finally, I wrote the
following expression.
/html/body//form/table[@id='rep']/tbody/tr/td/span/b[contains(normalize-space(.), 'Refurb')]
And this time, I got:
![Firefox displaying the result of the final XPath expression][screenshot-2]
From these strings, all I had to do was to select the ones related to
MacBooks and to count them. To extract these lines, I chose to use the
*White* and *Black* words, which only appeared in lines concerning
MacBooks.
To make sure the method was correct, I also decided to count the lines
related to MacBook Pro, and then even the ones for iMacs. In these
cases, I simply had to search for *MacBook Pro* and *iMac* terms on
the lines.
Counting the lines is a bit tricky because XLST does not provide
*lvalues*. There is no way to define anything else than constants. So
computing values can be achieved using recursivity only. In the
following template, `nodes` is the list of gathered strings, `item` is
the pattern we are looking for. The inner variable `count` is used to
carry the temporary value of the result count through iterative calls.
::XML
<template name="count">
<param name="nodes" />
<param name="item" />
<choose>
<when test="$nodes">
<variable name="node" select="$nodes[1]" />
<variable name="count">
<call-template name="count">
<with-param name="nodes" select="$nodes[position() != 1]" />
<with-param name="item" select="$item" />
</call-template>
</variable>
<choose>
<when test="contains($node, $item)">
<value-of select="$count + 1" />
</when>
<otherwise>
<value-of select="$count" />
</otherwise>
</choose>
</when>
<otherwise>0</otherwise>
</choose>
</template>
### Building the label
Counting lines containing a given item is only a matter of calling the
previous template with the list of lines and the wanted pattern. The
result of the call gives the count value. Here is an excerpt of the
code showing how is displayed the count of white MacBook laptops. Note
the `text` element to display some text around the value computed.
::XML
<text>MacBooks: </text>
<variable name="count-macbooks-w">
<call-template name="count">
<with-param name="nodes" select="$entries" />
<with-param name="item" select="string('White')" />
</call-template>
</variable>
<value-of select="$count-macbooks-w" />
<text>w </text>
### Registering the micro summary
If no micro summary is registered in your browser, or if the `pages`
directives do not match the page you are currently watching, then
trying to bookmark will raise the following dialog.
![The default Add bookmark dialog][screenshot-3]
Micro summaries can be registered using a simple script. Its main job
will be to check that the browser can register the sheet, and then a
simple line will suffice.
::HTML
<script>
const warning = "Sorry, you need a microsummary-enabled browser like Firefox 2.0";
function addGenerator(url) {
if (typeof window.sidebar == "object" &&
typeof window.sidebar.addMicrosummaryGenerator == "function")
window.sidebar.addMicrosummaryGenerator(url);
else
alert(warning);
}
</script>
<button onclick="addGenerator('http://10.165.16.164/applestore.xml')">
Install the Apple Store MacBook microsummary!</button>
Again, there is more than one way to do this. But remember it was only
a quick hack to monitor the store and a nice way have an overview of
the technology.
Now, if you used the previous script, and are trying to bookmark a
page, then your *Add Bookmark* dialog is updated so that you can
choose the *live title* instead of typing a static one. Hey Karine,
there are laptops available!
![The updated Add bookmark dialog][screenshot-4]
The complete micro summary code for the Apple store can be downloaded
[here](/objects/files/micro_summaries). Note that the short script I
used to register it needs its complete location.
## Waiting for kisses
As said before, micro summaries are a very tiny way to notify
something to the user. If the content of the title is rather
important, the best use is probably to store it on your personal
toolbar.
![The micro summary in action][screenshot-5]
To conclude, I shall add that I discovered quite recently that micro
summaries were stored in your Firefox profile under the
`microsummary-generators` directory (I am using Firefox under Debian
to do this). It is very easy to remove a generator simply by deleting
the XML file stored there.
For the record, a week later the Apple Store offered many refurbed
laptops and Karine bought her MacBook. And after that, she still tells
I'm staying too much in front of my computer!
[Apple Store]: <http://store.apple.com>
[eBay]: <http://www.ebay.fr>
[Notify]: <https://addons.mozilla.org/en-US/firefox/addon/3149>
[screenshot-1]: <screenshot-xpath-1.png>
[screenshot-2]: <screenshot-xpath-2.png>
[screenshot-3]: <screenshot-live_titles-1.png>
[screenshot-4]: <screenshot-live_titles-2.png>
[screenshot-5]: <screenshot-live_titles-3.png>

BIN
content/documents/using-firefox-micro-summaries/screenshot-live_titles-1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

BIN
content/documents/using-firefox-micro-summaries/screenshot-live_titles-2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

BIN
content/documents/using-firefox-micro-summaries/screenshot-live_titles-3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
content/documents/using-firefox-micro-summaries/screenshot-xpath-1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
content/documents/using-firefox-micro-summaries/screenshot-xpath-2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

1267
content/documents/wonderful-26.md

File diff suppressed because it is too large

53
content/index.md

@ -0,0 +1,53 @@
---
title: "Accueil"
permalink: false
---
Je suis ingénieur diplômé de l'[École Nationale d'Ingénieurs de Brest][ENIB]. Je travaille actuellement dans le domaine de la domotique, à [Lannion][LANNION].
Je suis passionné d'informatique, de littérature et de musique. Je suis adhérent à l'[April][APRIL], [nooSFere][NOOSFERE] et au [Club Présences d'Esprits][CPE]. Je suis le président de l'association [Pérégrine][PEREGRINE] à Lannion et membre du bureau de l'hébergeur alternatif et solidaire [Ti Nuage][TINUAGE].
Dans une autre vie, j'ai vécu à [Montpellier][Montpellier], [Brest][BREST] ou près de [Blois](https://fr.wikipedia.org/wiki/Blois). J'ai pratiqué la danse sur glace et le tir à l'arc. Plus récemment, j'ai été co-fondateur et président de l'association [Scorfel][SCORFEL].
## Curriculum Vitae
Mon parcours professionel est détaillé à [cette adresse](cv/2022/2022_cv_dsoulayrol.pdf) ([sources](cv/2022) pour [groff](https://www.gnu.org/software/groff/)).
Des itérations passées sont toujours disponibles :
- à la sortie de l'école en [2000](cv/2000_cv_dsoulayrol.txt)
- au moment où je m'apprête à quitter Atlantide pour Lannion, [fin 2005](cv/20051010_cv_dsoulayrol.pdf)
- En 2012, lorsque je suis chez Nexcom, j'expérimente différents modèles avec [LaTeX](https://www.latex-project.org/) et je produis un [CV](cv/2012/2012_cv.pdf), un document détaillant mes [expériences professionnelle](cv/2012/2012_experiences.pdf), et un « [europass](cv/2012/2012_europass.pdf) » ([sources](cv/2012)).
## Contact
Je peux facilement être joint aux adresses suivantes.
* <a href="mailto:david@soulayrol.name">david@soulayrol.name</a>
* <a href="xmpp:david@ti-nuage.fr">david@ti-nuage.fr</a> sur XMPP.
* <a href="https://pouet.chapril.org/@ds">@ds@pouet.chapril.org</a> sur Mastodon.
Le code que je produis de nos jours est stocké chez l'hébergeur alternatif Ti Nuage, et de temps en temps par nécessité chez Github.
* [Ti-Nuage](https://apps.ti-nuage.fr/gitea/david)
* [Github](https://github.com/dsoulayrol)
## Archives
Les documents que j'ai conservés, ou que j'exhume à l'occasion de mon disque dur...
* [La traduction](documents/le-monde-merveilleux-de-linux-2.6) du document [Wonderful World of Linux 2.6](http://www.kniggit.net/wwol26.html), Copyright 2003, Joseph Pranevich (jpranevich AT kniggit.net).
* [Un article sur l'utilisation des *micro-summaries* dans Firefox en 2007](documents/using-firefox-micro-summaries), en anglais.
* [Un script Python pour isoler des blocs dans un long fichier de *logs* ](documents/identifying-logical-contexts-in-logs), en anglais.
* [Une astuce pour masquer les longs entêtes d'un fichier source dans Emacs](documents/how-to-hide-long-c-headers) en anglais.
[APRIL]: <https://april.org>
[BREST]: <https://fr.wikipedia.org/wiki/Brest>
[CPE]: <http://www.presences-d-esprits.com>
[ENIB]: <http://www.enib.fr>
[LANNION]: <http://fr.wikipedia.org/wiki/Lannion>
[MONTPELLIER]: <https://fr.wikipedia.org/wiki/Montpellier>
[NOOSFERE]: <https://noosfere.org>
[PEREGRINE]: <https://www.associations.lannion.bzh/index.php?option=com_content&view=article&id=135:peregrine>
[SCORFEL]: <httsp://scorfel.fr>
[TINUAGE]: <https://ti-nuage.fr>

24
layouts/default.njk

@ -0,0 +1,24 @@
<!DOCTYPE HTML>
{% import "footer.njk" as footer %}
{% if lang == undefined %}{% set lang = 'fr' %}{% endif %}
{% set lang = moment.locale(lang) %}
<html lang="{{ lang }}">
<head>
<title>{{ site.title }} | {{ title }}</title>
<meta charset="utf-8">
<meta name="author" content="David Soulayrol">
<meta name="generator" content="Metalsmith" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/css/simple.min.css">
<link rel="stylesheet" href="/css/ds.css">
</head>
<body>
{% block content %}
{{ contents | safe }}
{% endblock %}
<footer>
{{ footer.mentions(lang) }}
{{ footer.generated(lang) }}
</footer>
</body>
</html>

14
layouts/document.njk

@ -0,0 +1,14 @@
{% extends "default.njk" %}
{% block content %}
<article>
<header>
<h1>{{ title }}</h1>
<p>{% if date %}
{% if lang == 'en' %}Published:{% else %}Publié le :{% endif %}
<time datetime="{{ moment(date).format() }}">{{ moment(date).format('LL') }}</time>
{% endif %}</p>
</header>
{{ contents | safe }}
</article>
{% endblock %}

17
layouts/footer.njk

@ -0,0 +1,17 @@
{% macro mentions(lang) %}
{% if lang == 'en' %}
<p>Unless stated otherwise, all this website content belongs to its author and can be redistributed using the <a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA 2.0</a> license.</p>
<p>Style is based on <a href="https://simplecss.org">SimpleCSS</a>. Titles font is <a href="https://www.fontspace.com/colombia-font-f45636">Colombia by Sandylukee</a>.
{% else %}
<p>Sauf mentions contraires, le contenu de ce site appartient à l'auteur et peut être distribué sous licence <a href="https://creativecommons.org/licenses/by-sa/2.0/fr/">CC-BY-SA 2.0</a>.</p>
<p>Le style repose sur <a href="https://simplecss.org">SimpleCSS</a>. La police des inter-titres est <a href="https://www.fontspace.com/colombia-font-f45636">Colombia par Sandylukee</a>.
{% endif %}
{% endmacro %}
{% macro generated(lang) %}
{% if lang == 'en' %}
<p>Generated with <a href="https://metalsmith.io">Metalsmith</a> (<a href="https://apps.ti-nuage.fr/gitea/david/david.soulayrol.name">Sources</a>).</p>
{% else %}
<p>Généré avec <a href="https://metalsmith.io">Metalsmith</a> (<a href="https://apps.ti-nuage.fr/gitea/david/david.soulayrol.name">Sources</a>).</p>
{% endif %}
{% endmacro %}

14575
package-lock.json

File diff suppressed because it is too large

62
package.json

@ -0,0 +1,62 @@
{
"name": "david.soulayrol.name",
"version": "2022.06",
"private": true,
"description": "The sources for <http://david.soulayrol.name>",
"main": "",
"scripts": {
"build": "DEBUG=metalsmith* npm run clean && npm run build:metalsmith",
"build:prod": "NODE_ENV=production npm run build",
"build:metalsmith": "node scripts/run.js build",
"clean": "rimraf dist",
"dev": "npm run build && DEBUG=metalsmith* nodemon scripts/run.js serve",
"server": "npm run build && http-server dist",
"lint": "npm run lint:js && npm run lint:css",
"lint:js": "eslint scripts",
"lint:css": "stylelint assets/**/*.css",
"test": "npm run lint && npm run build"
},
"author": "David Soulayrol <david@soulayrol.name>",
"devDependencies": {
"@metalsmith/layouts": "2.4.0",
"@metalsmith/permalinks": "^2.4.0",
"browser-sync": "^2.27.5",
"bs-fullscreen-message": "^1.1.0",
"clean-css": "^5.1.5",
"cli-table2": "^0.2.0",
"debug": "^4.3.2",
"eslint": "^8.18.0",
"eslint-config-standard": "^17.0.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-n": "^15.2.3",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^6.0.0",
"eslint-plugin-standard": "4.1.0",
"filesize": "^8.0.0",
"http-server": "^13.0.1",
"jstransformer-nunjucks": "^1.0.0",
"metalsmith": "^2.4.0",
"metalsmith-assets": "^0.1.0",
"metalsmith-clean-css": "^6.1.3",
"metalsmith-groff": "^0.3.0",
"metalsmith-markdownit": "^0.5.0",
"metalsmith-rename": "^1.0.0",
"metalsmith-sitemap": "^1.2.2",
"moment": "^2.29.1",
"nodemon": "^2.0.12",
"rimraf": "^3.0.2",
"slug": "^5.1.0",
"stylelint": "^13.13.1",
"stylelint-config-standard": "^22.0.0"
},
"nodemonConfig": {
"delay": 2500,
"ignore": [
"test/*",
"docs/*"
],
"watch": [
"scripts"
]
}
}

20
scripts/config.js

@ -0,0 +1,20 @@
const { resolve, join } = require('path')
const hostname = 'https://david.soulayrol.name'
const projectRoot = resolve(__dirname, '..')
const distribution = join(projectRoot, 'dist')
module.exports = {
hostname,
paths: {
projectRoot,
/* Nodes */
nodeModules: join(projectRoot, 'node_modules'),
/* Metalsmith */
metalsmithSource: 'content',
metalsmithDestination: distribution,
/* Server */
serverRoot: distribution
}
}

108
scripts/metalsmith-helpers.js

@ -0,0 +1,108 @@
const path = require('path')
const Table = require('cli-table2')
const filesize = require('filesize')
function generateFileMap (files) {
return Object.keys(files).reduce((map, filename) => {
const file = files[filename]
const parsedFilename = path.parse(filename)
const ext = parsedFilename.ext.substr(1)
const extFiles = map[ext] || []
return {
...map,
[ext]: [
...extFiles,
{
file,
filename
}
]
}
}, {})
}
export function StatisticsPlugin (options) {
return (files, metalsmith, done) => {
const fileMap = generateFileMap(files)
const fileTypes = Object.keys(fileMap)
// File overview table
fileTypes.forEach((filetype) => {
const fileTypeFiles = fileMap[filetype]
const count = fileTypeFiles.length
const size = fileTypeFiles.reduce((totalsize, entry) => {
// Some plugins (eg. metalsmith-data-markdown) replace the Buffer by a string
if (typeof entry.file.contents === 'string') {
return totalsize + entry.file.contents.length
} else {
return totalsize + entry.file.contents.byteLength
}
}, 0)
const filenamesTable = new Table({
head: [`${count} ${filetype}-${count > 1 ? 'files' : 'file'} with total ${filesize(size)}`, 'File size'],
wordWrap: true,
colWidths: [process.stdout.columns - 16, 12]
})
fileTypeFiles.forEach((entry) => {
let size = 0
// Some plugins (eg. metalsmith-data-markdown) replace the Buffer by a string
if (typeof entry.file.contents === 'string') {
size = entry.file.contents.length
} else {
size = entry.file.contents.byteLength
}
filenamesTable.push([entry.filename, size])
})
console.log(filenamesTable.toString())
})
done()
}
}
export function DebugPlugin (options) {
function sanitizeTableContent (content) {
const length = content.length
content = content.replace(/\s+/g, ' ').slice(0, config.maxContentLength)
if (length > config.maxContentLength) {
content = content.trim() + '...'
}
return content
}
const defaultOptions = {
maxContentLength: 1000
}
const config = {
...defaultOptions,
...options
}
return (files, metalsmith, done) => {
const fileMap = generateFileMap(files)
const fileTypes = Object.keys(fileMap)
fileTypes.forEach((filetype) => {
const fileTypeFiles = fileMap[filetype]
fileTypeFiles.forEach((entry) => {
const content = sanitizeTableContent(entry.file.contents.toString())
const size = filesize(entry.file.contents.byteLength)
const metadata = {
...entry.file
}
delete metadata.contents
const fileTable = new Table({
head: [`${entry.filename} @ ${size}`],
wordWrap: true,