Blog

Où l’on se débarrasse des popups de confirmation

Dans toute interface web, il y a ce que l’on pourrait appeler des « figures imposées ». La liste d’éléments avec son duo de boutons « Éditer » et « Supprimer » en est le parfait exemple.

Si en termes de logique côté serveur, la suppression est de loin l’opération la moins compliquée à implémenter, elle impose en revanche une petite subtilité du côté de l’interface : la demande de confirmation. On ne peut en effet décemment pas supprimer des données sans être sûr qu’il ne s’agit pas d’un clic malheureux ou que l’utilisateur a bien compris les implications de cette action.

Généralement, cette confirmation est demandée sous forme de modal, variante de la vénérable popup qui s’affiche en surcouche de la page courante, contenant l’insipide phrase « Êtes-vous sûr de vouloir supprimer cet élément ? » précédant deux boutons « Annuler » et « OK ». Exemple :

L’effet est assez ennuyeux et intrusif : un nouvel élément visuel apparaît au-dessus d’une interface déjà probablement chargée et oblige l’utilisateur a lire une phrase sans intérêt et à déplacer sa souris pour cliquer sur le bouton idoine. Pire, s’il s’agit d’un clic non intentionnel, l’utilisateur voyant réagir l’application aussi violemment peut s’inquiéter d’avoir « fait une bêtise ».

Comment alors demander une confirmation de manière discrète, tout en restant clair sur la marche à suivre ? Voici ce que je propose :

Comme on le voit, c’est le bouton d’action lui-même qui se transforme en bouton de confirmation. En cliquant une seconde fois, l’action est exécutée. Si on attend un peu, le bouton revient à son état d’origine. En réutilisant le même bouton, on évite de surcharger l’interface avec un élément supplémentaire et, si ce n’est pas ce que l’utilisateur souhaite faire, il lui suffit d’ignorer le bouton et de passer à la suite, sans se préoccuper des conséquences de son erreur.

ng-really, une directive AngularJS

Pour disposer de ce comportement, j’ai développé une directive AngularJS 1, ng-really. Très simple, elle se compose de moins de 50 lignes de code. Et pour l’utiliser, c’est encore plus simple, il suffit d’ajouter trois attributs sur l’élément sur lequel ajouter votre confirmation (généralement, un bouton) :

<button type="button" class="btn btn-danger" ng-really ng-really-confirm-label="Really?" ng-really-confirmed-action="confirmedAction()" ng-really-timeout="1000">Delete</button>

Je vous la propose sous licence open-source MIT (oui, je suis un développeur sympa ????). Utilisez-là, contribuez, forkez et débarrassez le monde des modals ????

Air de cour : intérêt pour la Music Information Retrieval

En 2013,  lors de ma première année de Master Machine Learning and Data Mining, j’ai suivi un cours très intéressant sur la Music Information Retrieval ; un domaine à la croisée de la musicologie, de la physique et de l’apprentissage automatique qui cherche à extraire de l’information depuis des données musicales.

On nous avait alors demandé de rédiger un court rapport sur un genre musical de notre choix et de détailler l’intérêt qu’il pourrait avoir pour la recherche dans ce domaine.

Mon intérêt pour l’Histoire m’a alors poussé à travailler sur un genre oublié, l’air de cour, musique très en vogue à la cour et dans les salons parisiens du XVIIe siècle, essentiellement vocale et parfois accompagnée d’un luth.

Voici donc ce rapport, rédigé en anglais, excavé du fin fond d’un de mes dossiers, qui, je crois, n’est pas dénué d’intérêt.

Un air de cour, brillamment interprété par l’Ensemble Faenza, pour se mettre dans l’ambiance ????

Abstract

In this report, we will study a specific musical genre, who were very popular in France at the royal court, between the late 16th century and early 17th, the « Air de cour ». Nearly forgotten today, we will see its features and the difficulties one may encounter to read and process these old compositions, melting scores in mensural notations, lyrics in old-fashioned French and lute tablatures.

Introduction

At the end of the 16th century, France is marked by the wars of religions between Catholics and Protestants. At the end of the Renaissance, period where Europe changed completely its vision of the world, we see the emergence of a new artistic movement, trying to show the exuberance and the grandeur, the Baroque, through all the arts, and of course in music. It is in this context that appear the « Airs de cour », a very specific musical genre, nearly forgotten today.

Air de cour

Adrian le Roy (c. 1520-1598), a french musician of the Renaissance, was the first to use the term « Air de cour » with the publication of his collection of songs « Airs de cour miz sur le luth »1 in 1571.2 This genre were very popular in France at the royal court, and more widely with the Parisian aristocracy and the « salons » until the mid-17th, making « Air de cour » a musical style placed at the border between Renaissance and Baroque periods.

« Air de cour » is essentially a vocal music genre. With time, it successively passed from solo voice to multiple voices, and again solo. It could come with no accompaniment but, usually, it is accompanied by a lute ; therefore, composers write them with the vocal melody, the lyrics in French and the lute accompaniment, as we will see.

Many composers from the late 16th century to early 17th, such as Étienne Moulinié or Bénigne de Bacilly, composed some « airs de cour ».

Figure 1: Charles Mouton, a famous luth player, by Gérard Edelinck, 1692

Musical approach

An « air de cour » is composed of several stanzas, each one sung on the same melody and split in two parts, the second one being repeated once more, playing the role of a chorus. The metric is quite unusual and may appear irregular for us today. Indeed, « airs de cour » were heavily influenced by the principle of « musique mesurée »3, a style trying to adapt the rhythm of the melody to the verse ; longer syllabes set to longer notes and shorter syllabes to shorter notes.

There is today few artists who recorded these musical pieces. We can however mention the work of Suzie Le Blanc4 on Moulinié’s compositions or that of Claudine Ansermet5 on Bacilly’s work. While listening, we clearly hear the two influences of the Renaissance, with the light lute accompaniment, and the Baroque, with the way of declamating the lyrics that will influence the french opera later, especially the french lyric tragedy of Lully.

Study of musical scores

As few studies were lead on this particular style, the best way to understand it is to study in more detail some scores of this time. Fortunately, some of this scores are digitized and freely available to download on the International Music Score Library Project (IMSLP), a project who tries to scan old scores on public domain and publish them to the web. We chose here to focus on the « Airs de cour miz sur le luth » by Adrien le Roy6 and on the first book of « Airs de cour » by Étienne Moulinié7.

Structure

The presentation and structure of a piece is quite similar in both books. We find the three essential elements : the melody score, the lyrics and the lute part. It is important to notice that the lute is written in the form of a tablature and not with a pitch representation. We don’t really know why, apart from the fact that this representation is quite usual for string instruments like the lute or the guitar.
Concerning the lyrics, we can say that, even if they are not in what we call usually « Old French », they are in a old-fashioned French and with some typographic particularities ; but they are still understandable without particular knowledge.

Musical notation

As we stated before, « airs de cour » are at the edge of the Renaissance and the Baroque periods. This is why, in Le Roy’s book, we have a mensural notation8 whereas in Moulinié’s one, we already have a form of our modern notation, as we can see in Figure 2a and Figure 2b.

Figure 2a: Extract of a score from Adrien Le Roy (1571)

Figure 2b: Extract of a score from Étienne Moulinié (1624)

We say « a form » because, as you can see in Moulinié’s score, it is still melted with old-fashioned notations. The G clef, for instance, is quite different from its modern form.

Moreover, it seems that, in both books, metric is written with the mensural notation. As we can see in Figure 3 and Figure 4, they use unusual signs. This needs some explanations. This system is much more complex than the modern one. Indeed, it allowed to define different divisions for two following note types. For example, the division of a Breve into a Semibreve (our modern Whole), called Tempus, could be different from the division of a Semibreve into Minims (our modern Half), called Prolatio. Furthermore, each of these levels could be divided in three (« Perfect » or « Maior » ) or in two (« Imperfect » or « Minor » ). Finally, another notation, a vertical stroke through the previous signs, represents a division by two of all temporal values.

Figure 3: Detail on a metric notation from Adrien Le Roy (1571)

Figure 4: Detail on a metric notation from Étienne Moulinié (1624)

So, as we can see in Figure 4, we can say that, in this score, a Breve is divided in two Semibreves and Semibreves in two Minims. This corresponds roughly to a meter of 2/4 in our modern notation.

But this doesn’t explain the « 3 » that we see in Figure 3, and that we find throughout the two books. In this scores, the metric could be changed during the composition : either by inserting one of the previous signs we saw, or by inserting a numerical value, like this « 3 » that means that the length of the notes must be divided by three.

Research interest

The « airs de cour » seems to have had little attention from the scientific community. The reasons are multiples: complete desuetude of the genre, very specific in its form (only vocal with one instrument accompanying), lack of reputation of its principal composers, lack of scores… However, thanks to the International Music Score Library Project, we can find some of this scores freely in PDF format, of variable quality though.

Today’s Music Information Retrieval’s system could help to fully digitize all this compositions and save them from a complete oblivion: technologies like Optical Music Recognition (OMR) could be used to detect and transcribe the scores. A research project could try to establish a system solving all the challenging issues we would encounter with « airs de cour » scores :

  • Recognize mensural notation, or worse, semi-modern notations like Moulinié’s one ;
  • Transcribe such recognized mensural notation in modern system ;
  • Process the lute tablature ;
  • Recognize and process the lyrics in an old-fashioned French with all its grammatical and typographical issues ; involving Optical Character Recognition technologies, and maybe even Machine Translation’s ones.

Améliorer l’expérience utilisateur… Avec de bons vieux e-mails

Chez Nereo, nous envoyons beaucoup d’e-mails automatiques à nos utilisateurs : chaque demande de congés donne lieu à un message pour le manager le prévenant qu’il a une nouvelle demande d’un de ses collaborateurs à passer en revue. S’il y a deux niveaux de validation, le supérieur hiérarchique recevra lui aussi un e-mail. Et lorsque la décision est prise, le demandeur reçoit à son tour un message le notifiant de la décision prise. Tous ces e-mails sont également démultipliés si l’une ou l’autre des parties ajoutent des commentaires à la demande.

Le contenu du message reprend les grandes lignes de la demande de congés (dates, type de congés…) mais, jusqu’à il y a peu, il fallait nécessairement cliquer sur le lien proposé afin d’aller sur Nereo et réaliser une action (accepter, refuser ou commenter).

Conscients de l’impact (nécessaire) de cette charge supplémentaire sur ces boîtes mails déjà saturées, nous nous sommes posés une question simple : comment rendre ces e-mails plus utiles et leur donner une véritable valeur ajoutée ?

La réponse est finalement simple : mettre l’e-mail au centre du processus et pas seulement le borner à un rôle de notifications. Car si une boîte mail sait recevoir des messages, elle sait aussi en envoyer. L’idée est donc de donner la possibilité à nos utilisateurs de prendre une décision simplement en répondant à l’e-mail reçu, comme ils le feraient pour répondre à un collègue ou un client.

Un serveur qui lit des e-mails

Généralement, quand on envoie un e-mail, le destinataire est un autre être humain qui va lire (et en principe comprendre) ce que vous avez écrit. Comme vous le voyez ici, c’est bel et bien une machine qui va recevoir cet e-mail et devoir comprendre son contenu.

Trois principaux challenges techniques sont à résoudre :

  1. Faire parvenir le contenu du message au serveur ;
  2. Identifier l’utilisateur de manière sécurisée ;
  3. Traiter le contenu du message.

1. Recevoir des e-mails, façon 2017

Les serveurs savent déjà recevoir des e-mails. En fait, c’est même grâce à eux que les e-mails existent : quand vous envoyez un e-mail, le serveur e-mail de votre fournisseur (par exemple Gmail) va entrer en communication avec le serveur e-mail du fournisseur de votre destinataire (par exemple Free). Les machines vont alors s’échanger les données représentant votre message. C’est le protocole SMTP.

« OK, donc c’est facile alors ? Il suffit de configurer un serveur SMTP sur Nereo ? »

Hum, oui, on aurait pu. Mais en fait, non, c’est trop compliqué. L’envoi et la réception des e-mails est devenue tellement critique (notamment à cause du spam) que c’est devenu un métier à part entière et qu’il est plutôt déconseillé d’improviser un serveur d’e-mail. De nombreuses sociétés sérieuses sont sur ce créneau, à l’instar de Mailchimp/Mandrill, et proposent de gérer l’envoi de vos e-mails automatiques pour des sommes très modiques. Chez Nereo, nous faisons confiance au français (????????????) Mailjet.

Ce type de services est surtout pensé pour envoyer. Mais Mailjet propose aussi l’inverse : recevoir des e-mails à votre place et vous renvoyer les données bien propres à votre application. Car oui, il faut bien voir qu’un e-mail brut, ça ressemble à ça :

Message-Id: <[email protected]iljet.com>
MIME-Version: 1.0
From: =?iso-8859-1?q?Fran=E7ois?= Voron <[email protected]>
Reply-To: [email protected]
To: [email protected]
Subject: Leave request from 06/05/2017 to 06/07/2017
Date: Tue, 30 May 2017 09:39:56 +0000
X-CSA-Complaints: [email protected]
X-MJ-GUID: 647b47e0-4b2a-4269-b4e7-2d6327132c11
X-MJ-Mid: AEEALJLMDvAAAAAAAAAAAGwlMZgAARpdZB8AAAAAAAed_ABZLT3sZHtH4EsqQmm05y1jJxMsEQAHQU0
Content-Type: multipart/alternative; boundary="=-WHbP6PSo9wmwf1AijZsB"
X-Original-Sender: [email protected]
X-Original-Authentication-Results: mx.google.com;       dkim=pass
 [email protected];       spf=pass (google.com: domain of
 [email protected]c3.mailjet.com
 designates 87.253.233.110 as permitted sender) smtp.mailfro[email protected]bnc3.mailjet.com

--=-WHbP6PSo9wmwf1AijZsB
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
Le contenu du message est ici !

Mailjet, lui, va nous renvoyer quelque chose comme ça :

{
    "Sender":"[email protected]",
    "Recipient":"[email protected]",
    "Date":"20150410T160638",
    "From":"Pilot <[email protected]>",
    "Subject":"Hey! It's Friday!",
    "Text-part":"Le contenu du message est ici !",
}

Ça ne parle peut-être pas aux non-initiés, mais ce format en JSON est infiniment plus exploitable que le pâté de texte qu’il y a plus haut.

1.1 Parlons technique

Cette partie de l’article va rentrer davantage dans les détails techniques. Si ce n’est pas votre tasse de thé, vous pouvez passer directement au chapitre suivant.

Curieusement, Mailjet ne met pas du tout en avant cette fonctionnalité sur son site, ni même ne propose de la gérer depuis l’interface. Seul un chapitre de leur documentation technique nous explique comment faire, et il faut obligatoirement passer par l’API pour configurer notre webhook.

Qu’à cela ne tienne, un simple POST sur l’endpoint /parseroute va nous configurer une adresse e-mail prête à recevoir des emails. J’ai l’habitude d’utiliser HTTPie (plus haut niveau que cURL) pour faire des appels API sans prise de tête depuis la ligne de commande :

http -a $MJ_APIKEY_PUBLIC:$MJ_APIKEY_PRIVATE POST https://api.mailjet.com/v3/REST/parseroute Url=https://monappli.com/mailjet-webhook/

Mailjet va alors nous filer une adresse e-mail du type [email protected] . C’est à cette adresse qu’on enverra les e-mails. Il est possible de configurer une adresse e-mail personnalisée, soit avec un simple transfert, soit en configurant carrément les enregistrements DNS MX vers ceux de Mailjet. J’ai opté pour cette solution avec Nereo, mais en utilisant un sous-domaine emails.nereo.com  car notre domaine racine a évidemment déjà des enregistrements MX pour traiter nos e-mails « standards ».

2. Identifier l’utilisateur de manière sécurisée

Très bien ! Notre serveur est désormais en mesure de recevoir des e-mails envoyés par nos utilisateurs. Problème : comment savoir à quel utilisateur et quelle demande de congés cet utilisateur correspond ? Sur une application, c’est facile, il faut entrer son identifiant et son mot de passe avant d’y accéder. Mais dans le cas présent, tout le monde peut potentiellement envoyer un e-mail à notre adresse.

« On peut peut-être se fier à l’adresse e-mail de l’expéditeur ? »

Malheureusement, non. Le protocole SMTP est fait de telle manière qu’il est possible d’utiliser n’importe quelle adresse d’expéditeur, même une ne vous appartenant pas. Il existe heureusement des mécanismes vérifiant qu’un expéditeur est bien celui qu’il prétend être ; mais ça ne me paraissait pas approprié pour notre cas.

Là encore, Mailjet va nous venir en aide. Il est en effet possible au moment de l’envoi d’e-mail automatique de notifications (celui qui prévient le manager que le salarié a fait une demande) d’ajouter des données annexes, la payload,  qui n’apparaitront nul part dans l’e-mail mais que Mailjet va garder dans un coin de sa tête (enfin, de son disque dur). Lors de cet envoi, Nereo connaît parfaitement le destinataire et la demande d’absence qu’on est en train de traiter : on va donc les ajouter dans la payload.

La magie se produit au moment où le manager répond à l’e-mail : à partir de l’identifiant de l’e-mail automatique, Mailjet va l’associer à cette réponse et ajouter la payload dans les données qu’il renvoie à notre serveur ! On peut donc parfaitement associer une réponse avec un utilisateur et une demande d’absence.

2.1 Est-ce vraiment sécurisé ?

Cette partie de l’article va rentrer davantage dans les détails techniques. Si ce n’est pas votre tasse de thé, vous pouvez passer directement au chapitre suivant.

En principe, oui, car la payload n’apparaît pas du tout dans les données de l’e-mail et qu’il n’est possible d’en ajouter que depuis l’API de Mailjet (qui par définition ne peut être utilisée que par Nereo).

Néanmoins, pour être vraiment safe, la payload est signée selon le processus cryptographique de Django ; le même qui est utilisé pour crypter le cookie de maintien de session.

3. Où on apprend à lire à une machine

Nous savons maintenant qui veut nous parler et à propos de quelle demande de congés. Il est temps maintenant d’analyser le contenu du message.

Alors, malgré le titre un peu racoleur, non, nous n’avons pas développé d’algorithme capable de comprendre l’intention de l’utilisateur dans un texte qu’il aurait écrit librement. C’est techniquement possible, les recherches récentes ont des résultats bluffants, mais ce n’est pas encore parfaitement fiable (coucou Siri !) ; et ce n’était surtout pas nécessaire pour la fonctionnalité que nous voulions.

Dans notre cas, on demande à l’utilisateur d’écrire « Je valide » s’il souhaite accepter la demande de congés ou « Je refuse » pour la refuser. Tout autre texte est ajouté en commentaire.

Toutefois, il y a quand même quelques problèmes à prendre en compte : la plupart des professionnels utilisent une signature à la fin de leur e-mail rappelant leur nom, leurs coordonnées ainsi que celles de leur entreprise. Il y a également tout le texte du message original (puisque c’est une réponse) surmonté d’une ligne du type « Le 2 juin 2017, Nereo a écrit :  » .

Ces informations ne nous sont pas utiles et il faut donc les ignorer. Cependant, comme il n’y a pas de format standard à la fois pour les signatures et l’entête du message précédent, ce n’est pas forcément facile de les détecter.

Heureusement, la communauté du logiciel libre est là pour nous aider. Mailgun, un concurrent de Mailjet (ironiquement), a laissé à l’usage libre de tous les développeurs de la planète son programme pour extraire le texte pertinent dans les e-mails. L’entreprise l’a développé pour proposer un système de réception d’e-mails similaire à Mailjet, avec un traitement beaucoup plus poussé. L’expertise de Mailgun et la maturité du programme leur permet de prendre en compte un nombre incroyable de cas différents. Une précision qu’il aurait été difficile d’atteindre si nous avions développé notre propre algorithme. En informatique, c’est le fameux principe de ne jamais réinventer la roue.

Ce programme nous permet donc de passer de ça :

Je valide

--
François Voron
CTO


Nereo
59 rue Marengo
42000 Saint-Étienne

--
De : Rémi Cournil <[email protected]>
Date : 30 mai 2017 à 13:37 +0200
À : [email protected]
Sujet : Demande d'absence du 9 juin 2017 au 12 juin 2017

Nereo
Demande d'absence de Rémi Cournil du 9 juin 2017 au 12 juin 2017

Rémi Cournil souhaite poser une absence du 9 juin 2017 matin inclus au 12 juin 2017 après-midi inclus.

Commentaires

Pas de commentaire
-


Voir la demande sur Nereo
ou répondez directement à cet e-mail !

Écrivez "Je valide" pour valider

Écrivez "Je refuse" pour refuser

ou écrivez n'importe quel autre message pour commenter

En savoir plus

 
Logiciel de gestion de congés

À ça :

Je valide

Beaucoup mieux ! On peut donc vérifier si le message correspond soit à « Je valide » , soit à « Je refuse » . Pour être tout à fait complet, nous transformons le texte de façon à ce que les majuscules, les espaces et tout ce qui n’est pas des lettres soient ignorés. On peut donc écrire indifféremment : « je valide » , « JE VALIDE » ou même « Je             VaLiDE! » .

Il suffit ensuite d’appliquer l’opération correspondante, exactement comme si l’utilisateur avait cliqué sur le bouton sur Nereo.

Quand l’interface s’efface

Nos utilisateurs peuvent désormais traiter des demandes de congés sans quitter leur boite mail. Cette fonctionnalité s’inscrit totalement dans la tendance des chatbots : on ne veut plus avoir à jongler avec chaque application pour bénéficier de son service mais au contraire disposer d’un seul point d’entrée pour tous nos outils : Slack, Facebook Messenger ou les assistants personnels comme Siri. En leur dictant des commandes simples, ils sont capables d’exécuter des actions qui auraient nécessité de nombreux clics et plusieurs temps de chargement si elles avaient du être exécutées manuellement.

L’originalité de notre approche réside dans le fait que la star ici n’est pas un chatbot hype ????, mais bel et bien ces bons vieux e-mails qui, loin d’avoir dit leur dernier mot, sont encore capables de nous rendre bien des services.

Installer un child theme WordPress nesté dans un repository Git

Quand on veut personnaliser un thème WordPress, la bonne pratique est d’utiliser un child theme. On peut ainsi ajouter nos propres fichiers CSS, JavaScript ou même overrider des fichiers PHP du thème parent sans pour autant tout perdre lors d’une mise à jour de celui-ci.

Une autre bonne pratique pour tout développeur qui se respecte, c’est évidemment de versionner les fichiers de notre child theme avec Git. On peut ainsi faire toutes les modifications qu’on veut en local, commiter et faire un simple git pull sur le serveur WordPress pour récupérer la dernière version du code.

C’est bien, mais cela implique d’avoir les fichiers du child theme à la racine du repository : s’il est caché au fond d’une arborescence, WordPress ne trouvera pas les fichiers style.css et functions.php nécessaires à son activation.

Dans mon cas, j’ai par exemple à la racine de mon repository Git un fichier docker-compose.yml pour pouvoir lancer rapidement un serveur en local, un répertoire qui contient des images d’illustration et enfin le répertoire du child theme :

- nereo-website/
    - graphics/
    - theme-child/
    - .gitignore
    - docker-compose.yml

Comment faire donc pour pouvoir installer notre child theme dans le répertoire des thèmes de WordPress tout en pouvant mettre à jour le code en faisant un git pull ? L’astuce consiste à cloner le repository dans un dossier quelconque, par exemple le répertoire home, et à monter le répertoire du child theme dans le répertoire thèmes de WordPress :

mkdir /var/www/html/wp-content/themes/theme-child # Le point de montage doit être déjà créé
mount --bind ~/nereo-website/theme-child /var/www/html/wp-content/themes/theme-child # À adapter bien évidemment avec le chemin de votre WordPress

Et voilà ! Maintenant, il suffira de faire un git pull dans le repository et votre child theme WordPress sera automatiquement mis à jour. Ça marche aussi en sens inverse : si vous faites des modifications depuis l’éditeur de WordPress, Git va le détecter et vous pourrez commiter ces changements.