David Madore's WebLog: Web technologies

Vous êtes sur le blog de David Madore, qui, comme le reste de ce site web, parle de tout et de n'importe quoi (surtout de n'importe quoi, en fait), des maths à la moto et ma vie quotidienne, en passant par les langues, la politique, la philo de comptoir, la géographie, et beaucoup de râleries sur le fait que les ordinateurs ne marchent pas, ainsi que d'occasionnels rappels du fait que je préfère les garçons, et des petites fictions volontairement fragmentaires que je publie sous le nom collectif de fragments littéraires gratuits. • Ce blog eut été bilingue à ses débuts (certaines entrées étaient en anglais, d'autres en français, et quelques unes traduites dans les deux langues) ; il est maintenant presque exclusivement en français, mais je ne m'interdis pas d'écrire en anglais à l'occasion. • Pour naviguer, sachez que les entrées sont listées par ordre chronologique inverse (i.e., celle écrite en dernier est en haut). Certaines de mes entrées sont rangées dans une ou plusieurs « catégories » (indiqués à la fin de l'entrée elle-même), mais ce système de rangement n'est pas très cohérent. Cette page-ci rassemble les entrées de la catégorie technologies Web : il y a une liste de toutes les catégories à la fin de cette page, et un index de toutes les entrées. Le permalien de chaque entrée est dans la date, et il est aussi rappelé avant et après le texte de l'entrée elle-même.

You are on David Madore's blog which, like the rest of this web site, is about everything and anything (mostly anything, really), from math to motorcycling and my daily life, but also languages, politics, amateur(ish) philosophy, geography, lots of ranting about the fact that computers don't work, occasional reminders of the fact that I prefer men, and some voluntarily fragmentary fictions that I publish under the collective name of gratuitous literary fragments. • This blog used to be bilingual at its beginning (some entries were in English, others in French, and a few translated in both languages); it is now almost exclusively in French, but I'm not ruling out writing English blog entries in the future. • To navigate, note that the entries are listed in reverse chronological order (i.e., the latest written is on top). Some entries are classified into one or more “categories” (indicated at the end of the entry itself), but this organization isn't very coherent. This page lists entries in category Web technologies: there is a list of all categories at the end of this page, and an index of all entries. The permalink of each entry is in its date, and it is also reproduced before and after the text of the entry itself.

[Index of all entries / Index de toutes les entréesLatest entries / Dernières entréesXML (RSS 1.0) • Recent comments / Commentaires récents]

Entries with category Web technologies / Entrées de la catégorie technologies Web:

↓Entry #2777 [older| permalink|newer] / ↓Entrée #2777 [précédente| permalien|suivante] ↓

(lundi)

J'essaie d'ajouter la possibilité de régler la taille du texte sur ce site

Un des principes complètement stupides et insupportables du Web (j'en parlais notamment dans ce billet il y a quelques mois) est que c'est l'auteur d'une page (ou site) Web qui choisit tous les détails de l'apparence de celle-ci. L'habitude qu'on a de ce principe peut faire oublier son absurdité, mais je ne sais vraiment pas quel sens ça peut avoir que ce soit moi, auteur de ce blog, qui décide la couleur de fond de la page, ou la police de caractère avec laquelle vous lisez ces mots : ces choix stylistiques m'ont surtout valu des critiques pour mes goûts de merde, mais c'est tout le principe qui est idiot — si on va critiquer ces choix, autant que ce soit le lecteur lui-même qui les fasse. Ce n'est pas à moi de décider quelle police vous semble la plus agréable pour lire du texte, ni la couleur qui offre le meilleur contraste, ni la taille qui convient le mieux à vos yeux peut-être myopes ou presbytes ou que sais-je encore : indépendamment du fait que j'ai (paraît-il) mauvais goût, je n'ai tout simplement pas les informations nécessaires pour prendre ces décisions.

Alors certes il y a des éléments d'apparence qu'il est normal que l'auteur du site choisisse. Par exemple si j'écris un texte sur les foobars et que j'avertis pour aider le lecteur à s'y retrouver, je vais indiquer les noms des foobars en les soulignant deux fois, en bleu pour les foobars bleutés et en rouge pour les foobars orangés, il faut que je puisse souligner deux fois et choisir la couleur. On comprend que ça puisse poser des problèmes d'interaction si le lecteur peut faire des choix d'apparence et que l'auteur peut en faire d'autres, et qu'il faut donc gérer des conflits éventuels ou des dépendances (du style : si le lecteur a choisi un thème sombre je vais plutôt utiliser un bleu et un rouge sombres, tandis que si le lecteur a choisi un thème clair je vais prendre des couleurs vives).

Reste que la situation actuelle, malgré de bonnes intentions de divers bouts des standards Web (comme CSS) laisse fort peu de pouvoirs entre les mains de l'utilisateur. (Enfin, en principe il a tous les pouvoirs : il peut ouvrir l'outil « inspecteur » de son navigateur et s'en servir pour modifier comme il veut la page qu'il consulte, ajouter des éléments de style, changer les tailles, les polices, etc., et d'ailleurs même le texte lui-même si ça lui chante. Mais en pratique, l'utilisateur moyen ne sait pas se servir de l'inspecteur de son navigateur, et même l'utilisateur expérimenté trouvera pénible de refaire ça à chaque visite, ou de devoir écrire un script Greasemonkey pour le faire automatiquement.)

La seule chose que les navigateurs Web ont fini par se décider à proposer de façon vraiment accessible, c'est un moyen de changer la taille en zoomant (ça se fait typiquement avec les touches contrôle-plus et contrôle-moins) ; Firefox propose même deux types de zoom : un zoom qui change texte et images, et un zoom qui ne change que le texte (mais comme le second — qui me semble préférable a priori — est peu utilisé donc mal testé, il souffre de divers problèmes et bugs, par exemple ça casse les capture d'écran). Pour une raison que je ne comprends pas du tout[#], cette fonction de zoom n'est pas proposée sous Firefox mobile (on peut certes zoomer par gestures sur l'écran, mais c'est un zoom qui ne réajuste pas la longueur des lignes à la taille de l'écran/fenêtre comme sur fixe ; tout est compliqué parce qu'il y a au moins trois types de zoom différents qu'on peut vouloir : cf. ce commentaire pour une explication plutôt correcte). Quoi qu'il en soit, ces mécanismes de zoom sont complètement spéciaux, c'est-à-dire qu'ils ne passent pas par le contrôle normal des déclarations de style CSS (ou alors ils interagissent bizarrement avec elles).

[#] Il faut dire aussi que je ne comprends pas grand-chose à la manière dont interagissent les différentes tailles dans un navigateur mobile : voir ce billet passé à ce sujet, à propos de l'ajout de la déclaration <meta content="width=device-width, initial-scale=1" name="viewport" /> à mon HTML dont j'avoue que je ne comprends pas vraiment ce qu'elle fait.

Il commence aussi à y avoir des mécanismes de sélection de thèmes sombre/clair, parce que beaucoup de gens veulent ça pour leur webapplications. Mais ça passe par un mécanisme ad hoc qui ne permet que de choisir un « thème » (voire un thème parmi deux) et certainement pas plein de propriétés orthogonales (police, taille du texte, longueur des lignes, couleurs). Donc un deuxième mécanisme de personnalisation différent, extrêmement limité dans sa portée.

Pour n'importe quoi d'autre que le zoom spécial proposé par le navigateur et la sélection d'un thème sombre/clair, le site Web doit proposer son propre mécanisme de personnalisation, et évidemment rien n'est standardisé pour aider à ce que l'utilisateur s'y retrouve facilement entre les sites ou puisse facilement faire les mêmes choix partout (ou au moins, soit sûr de ce que ces choix recouvrent). Il n'y a même pas de « pratiques recommandées » sur la manière de nommer les préférences, de les présenter à l'utilisateur, de les ordonner, ce genre de choses.

Bref, c'est le bordel.

Ces râleries générales étant dites, on m'a demandé (dans un commentaire posté sur le tout premier billet de ce blog, ce qui est raisonnable vu que je n'offre pas de moyen de faire un commentaire sur l'ensemble du site) de proposer un moyen de régler la taille du texte.

J'ai donc essayé (en m'inspirant du code qu'on m'a proposé, et en l'empirant à ma sauce) de faire quelque chose de ce genre. Forcément, ça passe par du JavaScript, mais comme ça ne rend pas le site inutilisable sans JavaScript (on ne verra juste pas cette fonction et tout marchera comme avant) ça me semble un usage parfaitement légitime de JavaScript. Pour les >99.9% d'utilisateurs qui ont JavaScript activé dans leur navigateur, vous devriez donc voir en bas de la page, juste au-dessus de la signature finale, des boutons permettant choisir la taille du texte que vous préférez. [Modification () : Pour éviter de trop encombrer l'espace, il faut d'abord cliquer sur le bouton ‘⚙’ pour faire apparaître les autres boutons.] Ce réglage est censé être persistant et s'appliquer à l'ensemble des pages de ce site (enfin, sauf quelques pages antédiluviennes qui sont dans un style complètement différent).

Reste que je ne suis pas très content de ce que j'ai fait, pour diverses raisons. Certaines raisons de mon mécontentement sont de la faute de mon incompétence, d'autres sont de la faute de choix (possiblement malheureux) que j'ai faits par le passé, d'autres sont la faute des technologies du Web, et encore d'autres je ne sais pas bien.

Les technologies Web c'est toujours le même truc : tous les chemins sont jonchés de petites crottes de ragondin, et à chaque fois qu'on veut faire un truc on n'arrête pas de marcher dessus. Il y a toujours plein de choses qui font presque ou à peu près ce qu'on veut, mais à chaque fois on découvre des limitations à la con qui empêchent de s'en servir comme on voudrait.

D'abord, il y a une question toute bête d'interface utilisateur ; sous quelle forme proposer à l'utilisateur de changer la taille du texte ? J'ai choisi de mettre ça en bas de la page, avec des boutons à cliquer pour choisir diverses tailles entre 8 pixels et 20 pixels (enfin, j'écris pixels mais il faut considérer que c'est une unité un peu arbitraire, notamment sur mobile, donc je montre un échantillon de chaque taille après le bouton). Je ne sais pas si cette interface est terrible : peut-être qu'un menu déroulant aurait été mieux ? Peut-être vaudrait-il mieux mettre ça en tête de page ? (Je n'aime pas trop l'idée de mettre en tête de page quelque chose qu'on ne va pas toucher souvent, mais d'un autre côté si on veut essayer plusieurs tailles et que c'est en fin de page, on risque de devoir rescroller jusqu'à la fin.) Bref, concevoir des interfaces utilisateurs est un métier, ce n'est pas le mien, je suis profondément incompétent là-dessus, et ça devrait faire partie des standards du Web, pas quelque chose qu'on me demande d'improviser.

D'ailleurs est-ce que j'aurais dû proposer une liste de tailles espacées logarithmiquement plutôt que linéairement ? Je n'en sais rien. Mais bon, ça je pense que ça n'a vraiment pas d'importance.

Question interface, il y a aussi le choix de la langue : j'ai mis le texte invitant à changer la taille (change site font size) en anglais, par simplicité, mais si j'avais été motivé au point de l'écrire en plusieurs langues, je ne sais pas très bien comment j'aurais dû choisir la langue (en fonction de la langue préférée du navigateur ? en fonction de la langue de la page où le choix s'insère ?).

Ensuite, il y a un problème de ce que signifie la taille par défaut : parce que avant de rajouter ce réglage, j'avais déjà fait un choix par défaut, à savoir une taille de 12px si la largeur de fenêtre est ≤640px, 14px si elle est ≤720px, et 16px au-delà (cf. ce billet passé). En fait, je ne sais même pas bien ce que la taille de fenêtre signifie exactement ici, mais ce choix par défaut est le résultat d'un compromis laborieux. (Si on met une seule taille, il est juste impossible d'avoir un truc utilisable à la fois sur un navigateur mobile et sur un fixe.) Du coup, si la taille par défaut dépend de la largeur, ce n'est pas clair comment je dois présenter à l'utilisateur le choix de revenir à la taille par défaut ! Ce n'est même pas très clair pour moi comment je peux, en JavaScript, lire la taille par défaut[#2]. Bon, bref, j'ai mis un bouton pour revenir au défaut (c'est-à-dire à la taille choisie en fonction de fenêtre), mais ça peut sembler confus d'avoir un bouton reset en plus du bouton de la même taille.

[#2] Oui, rien que lire la taille par défaut n'est pas évident : si j'ai du CSS qui dit quelque chose comme @media (max-width: 640px) { body { font-size: 12px; } } @media (min-width: 641px) and (max-width: 780px) { body { font-size: 14px; } } @media (min-width: 781px) { body { font-size: 16px; } et que je veux récupérer la valeur de font-size de l'élément body, ben… ça n'a pas l'air facile. L'idée naturelle serait d'appeler getComputedStyle(), mais il s'avère que quand Firefox est en mode zoom où il ne zoome que le texte (et pas les images), la valeur de font-size renvoyée par getComputedStyle() tient compte de ce zoom (alors que si on cherche à modifier la propriété, ben le zoom s'applique dessus, donc si on lit et qu'on réécrit ce n'est pas idempotent !). C'est vraiment l'exemple de petite crotte de ragondin qui parsème n'importe quelle tentative de faire n'importe quoi avec CSS et JavaScript.

Encore un autre problème est de savoir comment stocker la préférence de l'utilisateur. Il y a la possibilité de positionner un cookie pour ça : je n'aime pas trop les cookies, parce que d'abord c'est plein de bizarreries incompréhensibles (notamment qu'on reçoit la chaîne de tous les cookies positionnés et qu'il faut ensuite analyser soi-même), et puis il n'y a pas de raison que la préférence soit communiquée à mon serveur dans la requête HTTP (je n'ai pas à savoir quelles tailles mes utilisateurs ont choisies), ce qui serait le cas avec un cookie. Donc j'ai plutôt opté pour une variable en local storage, ce qui est plus propre et plus moderne, mais je ne sais pas si j'ai bien fait (ça peut passer pour un cookie « sous le radar », et des gens n'aiment pas).

Il y a un point sur lequel je me suis moi-même un peu tiré une balle dans le pied, c'est que le JavaScript de ce site (comme le CSS) n'est pas inclus par référence, depuis un fichier JavaScript qui serait chargé en plus du HTML, il est incorporé directement dans le HTML. (Ma motivation était que j'aime que les fichiers HTML soient autonomes : on peut prendre le HTML d'un billet de mon blog et, tant qu'il n'y a pas d'images dedans, le sauvegarder dans un fichier et le lire tel quel sans avoir à ajouter un machin point js et un bidule point css à côté[#3].) J'ai une infrastructure Java sur le serveur qui inclut un fichier JavaScript commun dans chaque HTML du site (soit généré statiquement pour la plupart des pages, soit généré dynamiquement par Tomcat pour les entrées individuelles du blog). Comme je viens de le dire, ça peut présenter un intérêt ; mais pour tester du JavaScript et le modifier, ça devient vite un calvaire, parce que ça demande de régénérer la page pour chaque essai.

[#3] Raison principale pour laquelle je refuse d'utiliser des trucs comme jQuery ou analogue : ça me semble indispensable qu'on puisse sauvegarder un fichier HTML comme un simple fichier et le lire ensuite n'importe où avec une adresse en file:/// si besoin. Ce qui interdit l'appel à n'importe quel truc JavaScript externe, et notamment jQuery (lequel est beaucoup trop gros pour qu'il soit sérieusement envisageable de l'incorporer directement). C'est là encore une des crottes de ragondin — enfin, plutôt une merde de mammouth pour le coup — qui pollue le Web, qu'il n'y a aucun moyen simple, fiable et robuste de sauvegarder une page Web, avec toutes ses dépendances, et pouvoir la relire ensuite localement.

Mais il y a surtout une chose qui m'est insupportable, c'est si le changement de taille de texte n'est pas transparent mais apparaît après que la page a chargé ; autrement dit, si on voit d'abord la page s'afficher à la taille par défaut, pour ensuite changer et prendre celle qui a été choisie comme préférence. Non seulement c'est visuellement horripilant et très déstabilisant à la lecture, mais en plus ça risque de casser complètement les liens internes (si le navigateur positionne la vue d'après l'ancre qu'on lui a donnée puis change la taille du texte, on risque de voir un autre bout du texte que celui que pointait le lien qu'on a suivi).

J'ai cherché à éviter ce problème en réglant la taille de la police par une fonction JavaScript exécutée dès que l'élément <body> est créé (en gros j'appelle une fonction JavaScript onEarly() depuis le HTML immédiatement après avoir ouvert l'élément <body> de manière à pouvoir régler document.body.style.fontSize dedans, et cette fonction ne fait quasiment que ça pour ne pas retarder le chargement de la page). Cette solution semble marcher sous Firefox mais pas sous Chrome (enfin, sous le Chromium que j'ai pour tester). Je ne sais pas pourquoi : sous Firefox tout marche comme je voudrais, mais sous Chrome je vois d'abord la page s'afficher à la taille par défaut et ensuite changer de taille sous mes yeux — précisément ce que je voulais éviter. À vrai dire je ne comprends pas vraiment (← ceci est un euphémisme pour pas du tout) le synchronisme du JavaScript : à quel moment le code est exécuté, à quel moment on a accès au DOM, à quel moment on peut ajouter du CSS, etc. Donc je ne sais pas à quel moment il faut se positionner pour pouvoir exécuter du JavaScript qui puisse modifier le style de l'élément <body> en ayant la garantie que rien n'a encore été affiché à l'écran : si quelqu'un comprend ce qui se passe avec Chrome et pourquoi il ne se comporte pas comme Firefox à cet égard, qu'il me le dise. Correction : Juste après avoir écrit ça, je reteste et je m'aperçois que ça semble marcher comme je veux, aussi bien sous Chrome que sous Firefox ; je ne sais pas ce qui s'est passé, j'ai dû brièvement passer dans un univers parallèle, ou peut-être que je me suis fait avoir par un mécanisme de cache quelconque.

Toujours est-il que j'ai fait un truc. Je ne suis pas très content de ce truc, mais il marchouille. Si vous avez des suggestions pour le rendre plus élégant, plus robuste, plus intuitif, je suis preneur, mais comme je commence à en avoir sacrément marre à ce stade, toute modification qui requiert des efforts de ma part au-delà du simple copier-coller d'un code qu'on me donnerait va sans doute juste être ignorée.

Ajout : Puisque la longueur des lignes est aussi une râlerie fréquente concernant le style de ce site, j'ai aussi ajouté un jeu de boutons permettant de le régler (entre 50 et 150 caractères par ligne).

Nouvel ajout () : Pour éviter de trop encombrer l'espace visuel, j'ai caché les boutons de réglage de la taille du texte et de la longueur des lignes derrière un bouton ‘⚙’ qui fait apparaître les autres réglages. J'ai aussi ajouté des scrollIntoView() pour que les boutons restent en vue quand on les utilise.

Néanmoins, si mon truc donne grosso modo satisfaction, je verrai si je peux le mettre aussi sur les pages de commentaires du blog (qui sont gérées de façon complètement différentes, par un script Perl antédiluvien auquel je préfère toucher le moins possible, donc j'attends d'être sûr d'avoir le bon JavaScript avant de le recopier).

↑Entry #2777 [older| permalink|newer] / ↑Entrée #2777 [précédente| permalien|suivante] ↑

↓Entry #2755 [older| permalink|newer] / ↓Entrée #2755 [précédente| permalien|suivante] ↓

(mardi)

Vulgarisation informatique : comment fonctionne le Web ?

Avant-propos

Pour changer un peu des entrées portant sur des maths incompréhensibles, j'ai voulu essayer de faire de la vulgarisation informatique et à un niveau — j'espère ! — compréhensible par tout le monde, pour expliquer les principes de base de comment fonctionne le World Wide Web (ce que la plupart des gens appellent Internet, mais ci-dessous je vais expliquer entre autres choses la différence entre ces termes).

Enfin, du moins, c'était mon idée initiale en commençant à écrire ce billet, mais il a, comme d'habitude, enflé bien au-delà de ce que j'imaginais possible, m'a demandé un temps totalement déraisonnable, et qui s'est plutôt transformé en un tas d'explications disparates (parfois à la limite du rant) sur divers sujets pas reliés de façon très cohérente les uns aux autres (et si certains sont, je l'espère, effectivement compréhensibles par tout le monde, il est clair qu'à d'autres endroits j'ai raté mon pari). Et j'avoue franchement que le plan de ce billet est complètement incohérent (par exemple, ce passage ne devrait pas être relégué à une sous-sous-sous-partie). La bonne nouvelle, c'est que tous ces petits bouts sont assez largement indépendants les uns des autres, donc on doit pouvoir lire ce pavé en sautant — ou en lisant en diagonale — les passages qu'on trouve inintéressants ou incompréhensibles, ou en picorant les passages potentiellement intéressants. Pour essayer d'aider le lecteur à lire en diagonale, j'ai fait précéder les parties et sous-parties d'un bref résumé de ce qui s'y dit (signalé par le signe ‘❖’).

Bon, j'avoue aussi ma crainte d'avoir essentiellement perdu mon temps à déployer des efforts pédagogiques mais que, au final, les gens qui me lisent savent déjà tout et n'apprendront rien, tandis que ceux qui ne savent pas déjà tout se diront que ce sont des questions hautement techniques qui ne les intéressent pas du tout et n'auront pas envie de me lire. Mais je pense que les gens qui se disent que ce sont des questions hautement techniques se trompent, et je pense que l'essentiel de ce que je vais raconter ci-dessous constitue des connaissances extrêmement basiques que tout le monde devrait avoir avant d'ouvrir un navigateur Web, histoire de ne pas risquer de tomber dans le premier hameçonnage venu (ah ben j'ai suivi le lien dans le mail, ça ressemblait bien au site de ma banque, donc j'ai donné mon mot de passe), du coup je fais l'effort de me dire que ça vaut la peine que je prenne la peine de l'écrire, au risque de pisser très longuement dans un violon.

Si au moins quelqu'un apprend quelque chose, n'hésitez pas à dire quoi en commentaire (ou d'ailleurs, à l'inverse, si vous trouvez que c'est trop technique et que ça n'a aucun intérêt, dites moi surtout à quel point vous avez laissé tomber), ça m'intéresse aussi d'en faire une sorte de petit sondage pour savoir si écrire ce genre de billet de vulgarisation a un sens.

Je vais faire beaucoup d'efforts pour garder mes explications au niveau le plus bas possible (et encore une fois, là où je n'y arrive pas, faites-le moi savoir, mon but est aussi d'apprendre à expliquer !). Du coup, fatalement, je vais parfois dire des choses qui sont un peu approximatives ou simplifiées (mais j'espère jamais complètement fausses, et je vais essayer de toujours dire que je simplifie) : je précise ça parce que je soupçonne que beaucoup de gens qui me liront seront, en fait, des gens déjà parfaitement compétents et qui vont plutôt avoir tendance à me chercher des poux. (Ceci vaut pour toute tentative de vulgarisation, bien sûr, mais particulièrement ici parce que je tâche de rester bien plus compréhensible que ce que je raconte d'ordinaire.)

Ce qui a déclenché mon envie d'écrire tout ça, ce n'est pas vraiment des questions de sécurité et de hameçonnage, c'est plutôt que Twitter et Reddit ont, à peu près au même moment, décidé de fermer leur API publique et gratuite, je trouve cette évolution très préoccupante (même si elle n'est pas du tout surprenante de la part du douchebro qui a repris Twitter), et je pense que ça a un sens d'expliquer de quoi il est question (c'est quoi, une API publique ?) et d'essayer de donner du contexte sur les enjeux d'ouverture du web. En plus de ça, pendant que j'étais en train d'écrire ce billet, je suis tombé sur cet article de Ars Technica sur la Web Integrity de Google, et j'ai inséré quelque chose à ce sujet.

Mais ces questions-là viendront à la fin : commençons plutôt par le début, c'est-à-dire par les définitions de base de ce que sont Internet et le Web et les très grandes lignes de leur fonctionnement.

Table des matières

Liste des termes définis dans le texte

(Liste donnée dans l'ordre dans lequel les termes sont définis ou évoqués pour la première fois. Chacun est un lien vers cette première définition ou évocation. Le terme apparaît en gras dans le texte à l'endroit lié.)

C'est quoi Internet ? C'est quoi le Web ? Et c'est quoi la différence ?

Dans cette section, je définis l'Internet (réseau d'ordinateurs interconnectés) et le Web (réseau d'information sous forme de pages hypertexte et reliées les unes aux autres par des hyperliens). J'évoque le fonctionnement « client-serveur » du Web et le protocole HTTP (au-dessus d'Internet) central à son fonctionnement, ainsi que le format HTML dans lequel sont écrites les pages hypertexte.

Je dois d'abord définir ce qu'est le Web et quelques termes en rapport avec lui, et contraster avec Internet.

Alors d'abord, le Web n'est pas pareil qu'Internet. Internet c'est un réseau d'ordinateurs interconnectés (en gros, de nos jours, tous les ordinateurs du monde) qui leur permet de s'échanger des informations. (Cela se fait au moyen d'un jeu de protocoles de communication appelé TCP/IP, qu'on peut donc considérer pour simplifier comme synonyme d'Internet, et qui a été inventé entre le milieu des années 1970 et le début des années 1980, essentiellement dans le cadre de recherches financées par le Département de la Défense américain, je ne rentre pas dans plus de détails, voyez Wikipédia si vous voulez en savoir plus. Mais ça vaut la peine de mentionner au moins deux noms de gens qui ont joué un rôle central dans la création de ces protocoles : Vinton Cerf et Bob Kahn, souvent considérés comme les pères d'Internet.)

Le but de ce billet n'est pas d'expliquer comment fonctionne Internet. Ce serait éventuellement pour une autre fois, mais je vais tenir Internet pour acquis.

Le (World Wide) Web, abrégé WWW, i.e. la Toile mondiale, c'est (ou au moins c'était, à l'origine) une manière d'utiliser Internet pour mettre à disposition des informations sous forme de pages Web. Une page Web peut contenir du texte, des images, des sons, des vidéos ou autres animations (et maintenant des programmes complets, je vais y revenir), et surtout, elle peut contenir des hyperliens, ou simplement liens, qui pointent vers d'autres pages Web (permettant à l'utilisateur de passer facilement de l'une à l'autre), l'ensemble de tout ça étant appelé de l'hypertexte. Enfin, je suppose que vous savez ça, parce que si vous lisez ces mots, a priori (sauf si par exemple vous êtes une personne du futur en train de lire une archive de quelques textes ayant miraculeusement survécu à l'apocalypse — auquel cas, coucou, et content de avoir que des bouts de mon blog en font partie), vous savez au moins un peu ce qu'est une page Web puisque vous êtes en train d'en lire une.

Le Web fonctionne au-dessus d'Internet (c'est-à-dire qu'il dépend d'Internet pour fonctionner), selon un mécanisme dit client-serveur : d'un côté il y a l'ordinateur de la personne qui veut lire une page Web, qu'on appelle client : il utilise un programme spécial, appelé navigateur Web, pour consulter le Web et afficher les pages hypertexte : ce programme côté client va contacter la machine qui met la page à disposition, et qu'on appelle le serveur (et qui fait tourner lui aussi un programme spécial, appelé serveur Web — parfois ce terme désigne la machine, parfois le programme, ce n'est pas toujours clair, et souvent pas très important) pour lui demander. La communication a lieu via Internet, c'est-à-dire que le client et le serveur doivent déjà faire partie d'Internet (avoir un accès Internet) pour espérer communiquer. Elle a lieu, plus précisément, par un protocole appelé HTTP (ou sa variante chiffrée, HTTPS dont je parlerai plus bas) qui se place au-dessus des protocoles TCP/IP : imaginez que TCP/IP est comme la poste qui achemine des lettres, alors que HTTP est un formulaire que vous envoyez pour recevoir un livre. Quant au format dans lequel les pages Web sont écrites s'appelle HTML (bon, là je simplifie excessivement, et je vais y revenir), qui est en gros une façon de décrire le contenu (là il y a le texte suivant, là il y a un hyperlien vers telle adresse, là il y a une image dont voici l'adresse).

Le Web a été inventé en gros une décennie après Internet, entre la fin des années 1980 et le début des années 1990, essentiellement au CERN (le Centre européen pour la recherche nucléaire, basé en Suisse), là aussi je renvoie à Wikipédia pour plus de détails, mais il y a un nom qui revient généralement comme le père du Web : Tim Berners-Lee (avec, comme dans le cas d'Internet, le caveat important qu'une invention de ce genre n'est jamais le fruit d'une seule personne et que c'est toujours réducteur de donner un seul nom ou même deux). Il y avait d'autres mécanismes utilisant Internet pour diffuser de l'information générale inventés avant ou à peu près au même moment (par exemple Gopher, qui est maintenant presque mais pas complètement mort, plus simple, utilisant une structure organisée en menus hiérarchiques ; ou FTP, qui joue un rôle un peu différent, puisque c'est plutôt pour échanger des fichiers entre ordinateurs qu'à destination d'un humain, mais il est lui aussi quasiment remplacé par HTTP(S) de nos jours), mais le Web a eu tellement de succès qu'il est devenu quasiment synonyme d'Internet.

Ce n'est pas qu'une confusion du grand public de traiter ces deux termes (Web et Internet) comme presque interchangeables, c'est de plus en plus vrai que beaucoup de systèmes d'échanges de données, même ceux qui concerne pas des pages hypertexte ou même qui ne sont pas des données à afficher directement à un humain dans un navigateur, tendent à utiliser le protocole HTTP(S) initialement prévu pour le Web, et que du coup les contours de ce dernier deviennent un peu flous. Mais c'est aussi et surtout le cas que le navigateur Web devient de plus en plus une sorte d'« application universelle », c'est-à-dire que toutes sortes de services de toutes sortes (communication, bureautique, jeux, etc.) tournent optionnellement ou même exclusivement à l'intérieur d'un navigateur Web, ce qui entretient la confusion non seulement entre le Web et l'Internet mais même entre le navigateur Web et l'ensemble du système d'exploitation (je veux dire que beaucoup de gens ne font sans doute pas une distinction claire entre une « Web application » qui tourne à l'intérieur de leur navigateur web, et un programme distinct du navigateur qui tourne sur leur ordinateur, et c'est encore pire sur les téléphones mobiles ; je reparlerai des Web applications plus bas pour essayer de dissiper cette confusion).

Malgré cette tendance à confondre Web et Internet, il continue à exister un grand nombre de protocoles Internet, plus ou moins spécialisés, qui ne peuvent pas vraiment être considérés comme faisant partie du Web. (Y compris des protocoles utilisés par le grand public : à titre d'exemple, BitTorrent, un protocole de partage de fichiers décentralisé et pair-à-pair, c'est-à-dire que tout le monde s'échange des petits bouts de fichier sans que personne n'ait une copie autoritative, notamment souvent utilisé pour partager des vidéos dites « pirates », c'est-à-dire échangées en contravention du droit d'auteur, est basé sur Internet mais s'oppose radicalement à l'organisation client-serveur du Web. De même, les applications de vidéoconférence comme Zoom ou Skype utilisent leurs propres protocoles propriétaires au-dessus d'Internet, même s'il y a souvent une passerelle Web permettant de les utiliser depuis un navigateur Web.)

En revanche, tous les réseaux sociaux (Facebook, Twitter, Instagram, Reddit, StackExchange, TikTok, etc.) peuvent être décrits comme faisant partie du Web ou construits au-dessus de lui : même s'ils disposent d'une application spécialisée permettant d'éviter de passer par un navigateur Web généraliste, ils restent toujours consultables via un navigateur Web, i.e., ils ont toujours au moins une interface Web en plus d'éventuelles interface mobile (essentiellement Android et iOS) vers le même contenu (je ne sais pas pourquoi, ça semble être uniquement sur mobile qu'on propose ces applications spécialisée, alors qu'il n'y a pas vraiment de raison technique pour laquelle on ne pourrait pas avoir une appli spécialisée pour ordinateur pour accéder à chacun de ces réseaux sociaux — l'explication relève plus de considérations historiques ou sociologiques que techniques).

Le fonctionnement de base du Web à papa

Dans cette section, j'évoque les idées essentielles fonctionnement du Web des années 1990–2000, en parcourant les composantes d'une adresse Web ou URL : nom d'hôte puis nom de chemin.

Comme je le dis ci-dessus, le Web est devenu quelque chose d'assez protéiforme, non seulement presque synonyme d'Internet mais englobant même presque tout ce qui se fait sur un ordinateur, et je pense que cela contribue à la confusion que le grand public peut ressentir. Pour dissiper cette confusion, je pense qu'il vaut mieux commencer par décrire le « Web à papa », c'est-à-dire le Web des années 1990–2000 (en gros), quand il s'agissait vraiment de consulter des pages de texte avec des hyperliens et quelques images et pas de faire essentiellement tout et n'importe quoi jusqu'à ne plus savoir ce qui est sur notre ordinateur et ce qui est dans un cloud vaporeux.

Remontons le temps et replaçons-nous donc dans cette époque où les choses étaient un peu plus simples. Vous voulez consulter une page Web (ou un ensemble de pages Web apparentées : un site Web). D'abord, vous lancez un programme spécial, le navigateur Web. Je vais revenir sur les navigateurs Web et leur histoire, mais tenons-les pour acquis pour le moment. Dedans, vous tapez, dans la barre d'adresse (parce qu'à l'époque il n'y a pas vraiment de moteur de recherche), l'adresse de la page que vous voulez consulter : on parle aussi d'URL ou URI pour cette adresse (il y a une petite différence entre ces deux termes, les URI étant plus générales que les URL, mais ignorons cette subtilité byzantine : les adresses de type HTTP sont bien des URL et donc aussi des URI). Cette adresse peut ressembler à quelque chose comme :

http://www.example.tld/some/where.html

Ceci signifie approximativement : se connecter (au moyen du protocole HTTP) à l'ordinateur serveur ayant le nom www.example.tld sur Internet, et lui demander le fichier ayant pour nom /some/where.html.

Mais donnons quelques explications un peu plus précises à ce sujet.

↑Entry #2755 [older| permalink|newer] / ↑Entrée #2755 [précédente| permalien|suivante] ↑

↓Entry #2521 [older| permalink|newer] / ↓Entrée #2521 [précédente| permalien|suivante] ↓

(mercredi)

J'ai déjà dit que je haïssais le CSS ?

(Ah oui, je l'ai déjà dit. Mais ça ne fera pas de mal de le redire. C'est donc parti pour un nouvel épisode de la saga Ruxor se plaint de combien le monde informatique est merdique et mal conçu.)

À chaque fois que je suis obligé de toucher à CSS, j'en ressors horrifié : aussi bien par la complexité de toutes ces règles byzantines que par le génie avec lequel ce langage semble toujours résoudre 90% de votre problème et vous narguer en rendant impossible de résoudre les 10% restants malgré son nombre invraisemblable de features mutantes.

Bon, la dernière fois que je m'en étais plaint, c'était à propos du scaling des images. Quand je mets une image dans mon blog j'écris typiquement une balise <img>, quelque chose comme :

<img src="blueish-foobar.png" width="400" height="300" alt="[Photo d'un foobar bleuté]" style="float: right; clear: right; margin-left: 1em; margin-bottom: 1em" />

(Enfin, le style= est en fait dans une classe CSS, mais peu importe.)

Dans cet exemple, le fichier PNG ferait 400×300. La raison de préciser la largeur et la hauteur de l'image dans les attributs est de permettre au navigateur de préparer la taille même si l'image ne se charge pas immédiatement, et de ne pas avoir à faire un reflow quand elle se charge (parce qu'il ne découvrirait la taille qu'à ce moment-là).

Je mets typiquement des images de taille de l'ordre de 400 pixels, et je fais normalement un lien vers une version plus grande. Éventuellement, si l'image est très grosse et vraiment centrale à la discussion, je vais la centrer au lieu de la flotter à gauche ou à droite. Enfin, peu importe.

Sur un mobile, ça ne marche pas du tout, parce que les pixels utilisés par CSS sont pipo (pour que le texte ne soit pas trop petit) et du coup l'image devient beaucoup trop grande par rapport aux lignes de texte. Quand je m'en suis plaint la dernière fois (dans cette entrée), je ne connaissais pas la solution. J'ai enfin fini par apprendre que (1) on peut mettre un max-width qui va overrider le width même si les deux existent (c'est utile mais très contre-intuitif), et (2) la valeur magique auto qui fait tout même le café (mais on ne comprend rien à ce qu'elle fait exactement) permet de demander que la hauteur de l'image soit ajustée pour rester proportionnelle à la largeur. D'où la solution :

<img src="blueish-foobar.png" width="400" height="300" alt="[Photo d'un foobar bleuté]" style="max-width: 60%; height: auto; float: right; clear: right; margin-left: 1em; margin-bottom: 1em" />

Comme ça l'image fait 400×300 (la taille du fichier, i.e., sa taille « naturelle »), sauf si ça va dépasser 60% de la largeur du contenant, auquel cas la largeur de l'image est limitée à cette valeur et sa hauteur est ajustée pour garder l'aspect ratio 4/3. C'est parfait.

Ajout : Comme un long commentaire me fait prendre conscience que je n'ai pas du tout été clair, j'explique mon intention : mon but est que l'image fasse sa taille naturelle (400×300), sauf si la fenêtre (ou l'écran du mobile) est tellement petit qu'on ne puisse pas mettre cette largeur de 400 pixels dans 60% de la taille disponible, auquel cas je veux limiter la taille de l'image à ces 60%. En effet, il s'agit d'images qui, typiquement, illustrent un paragraphe de texte, donc je veux laisser à côté de l'image un peu de place (les 40% restants, donc) pour que le texte s'inscrive à côté de l'image. (Laisser trop peu ou pas du tout de place pour le texte fait que l'image interrompt le texte, et ce n'est pas plaisant.) En revanche, dans le cas où je mets une image centrée (j'aurais sans doute dû prendre cet exemple-là, mais il est moins fréquent sur mon blog), je vais bien sur écrire max-width: 100% à la place.

C'est parfait, mais enfin, c'est extrêmement peu intuitif, moi j'aurais préféré une syntaxe beaucoup plus explicite du genre width: min(0.6*widthof(parent), 400px); height: (300/400)*widthof(this) (j'invente complètement, mais vous voyez l'idée), ce qui aurait précisé très clairement et très intuitivement ce que je veux, plutôt qu'un auto complètement magique dont on ne sait pas ce qu'il va faire (sur d'autres types d'élément, auto demande d'ajuster à la taille du contenu : quel est le rapport entre ces deux sens du mot ?).

Enfin, j'étais quand même vachement content d'apprendre ça. Mais maintenant il y a la complication du SVG. Parce que mes images sont parfois en SVG inlinées dans le HTML lui-même. Ce qui est censé être mieux (image vectorielle, pas de besoin de requête HTTP supplémentaire), mais présente aussi des inconvénients (Google Images ne semble pas assez malin pour récupérer les images SVG, par exemple, et a fortiori quand elles sont inlinées). Typiquement mon SVG ressemble à quelque chose comme ceci :

<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="400" height="300" style="float: right; clear: right; margin-left: 1em; margin-bottom: 1em; stroke-linecap: round; stroke-linejoin: round"><!-- Insert vector of a blueish foobar *here* --></svg>

Si on fait pareil qu'avant, c'est-à-dire ajouter max-width: 60%; height: auto dans le style, ça ne va pas marcher, parce que l'élément <svg> va certes être redimensionné, mais l'image qu'il contient va simplement être coupée, pas redimensionnée. La solution est d'utiliser l'attribut viewBox qui définit un système de coordonnées dans le SVG, donc quelque chose comme viewBox="0 0 400 300" pour demander au navigateur que, que même si l'élément <svg> est redimensionné, les coordonnées à l'intérieur aillent quand même de 0 à 400 et de 0 à 300. On en arrive à ceci :

<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 400 300" width="400" height="300" style="max-width: 60%; height: auto; float: right; clear: right; margin-left: 1em; margin-bottom: 1em; stroke-linecap: round; stroke-linejoin: round"><!-- Insert vector of a blueish foobar *here* --></svg>

Enfin, ça c'est par imitation de ce que je fais pour un <img> : ce n'est pas clair que ce soit la meilleure chose à faire : je pourrais retirer height="300" et/ou remplacer width="400" par un width:400px dans le style. Sur Firefox ça semble marcher correctement, et sur la version de Chrome que j'ai sous la main aussi. Malheureusement, cet article (qui est intéressant mais un peu confus dans sa formulation) met en garde que :

Many browsers—IE, Safari, and versions of Opera and Chrome released prior to summer 2014—will not auto-size inline SVG. If you don't specify both height and width, these browsers will apply their usual default sizes, which as mentioned previously will be different for different browsers. The image will scale to fit inside that height or width, again leaving extra whitespace around it. Again, there are also inconsistencies in what happens if you leave both height and width auto.

À la place, ils proposent un hack absolument ignoble faisant intervenir padding-bottom. Il est hors de question que j'utilise un truc pareil (j'ai déjà assez de mal avec le CSS et peur de tout casser dès que je change quelque chose, si je commence à utiliser des hacks pareils je n'y comprendrai vraiment plus rien ; et surtout, j'ai peur que ça soit très peu robuste). Mais il y a des choses qui restent tout à fait obscures pour moi :

  • Est-ce que ce problème est encore d'actualité (l'article date de début 2015, peut-être que les choses ont changé depuis) ?
  • Qu'est-ce qui va se passer, au juste, sur les navigateurs qui will not auto-size inline SVG ? Comment comprennent-ils height:auto ou qu'en font-ils au juste ?
  • Est-ce qu'il est possible d'extraire du foutoir des normes une compréhension quelconque de ce qu'un navigateur est censé faire ? (Comme je le disais plus haut, auto a l'air complètement magique.) Bon, c'est impossible de savoir quelle est la spécification CSS parce qu'il y a un zillion de documents avec des numéros de version pas clairs (la version 2.1 de la spécification a l'air plus récente que la version 3, what the fuck?), mais je lis sur cette page que if ‘height’ has a computed value of ‘auto’, ‘width’ has some other computed value, and the element has an intrinsic ratio; then the used value of ‘height’ is: (used width) / (intrinsic ratio) ; mais j'ai essayé de comprendre ce qu'est un intrinsic ratio et si le SVG inliné en a, et j'ai abandonné.

Bon, ne sachant pas quoi en penser, je vais juste ignorer le problème et jouer moi aussi au petit jeu con de si ça marche sous Firefox et Chrome, c'est bon.

Mais ça m'amène à un problème lié : supposons que ce que je veux dimensionner n'est pas une image (<img> ni <svg>) mais un élément bloc différent, disons un <div> (pensez par exemple à celui qui contient des images dans cette entrée-ci). Mon <div> n'a pas d'intrinsic aspect ratio, mais supposons que je veux lui en spécifier un. Autrement dit, mon problème est :

Comment dimensionner un élément bloc, en CSS (sans JavaScript), en précisant sa largeur et son aspect ratio (ou bien sa hauteur et son aspect ratio) ?

Dans la syntaxe que j'ai pipoté plus haut, je pourrais vouloir écrire width: min(0.6*widthof(parent), 400px); height: (300/400)*widthof(this) exactement comme pour l'image : c'est-à-dire, imposer que la largeur soit le plus petit entre 400 pixels et 60% de la largeur de l'élément parent, et que le hauteur soit 3/4 de cette valeur. Ou dans une syntaxe plus proche du CSS réel, on pourrait imaginer d'écrire width:400px; max-width:60%; aspect-ratio:4/3; height: auto. Mais tout ça n'existe pas.

Dans le monde réel, est-ce possible, oui ou merde ? cette page semble penser que non, puisque toutes les réponses sont complètement pourries (la réponse approuvée propose le hack absolument ignoble à base de padding-bottom, qui d'ailleurs ne marcherait pas si c'était la hauteur qui était fixée et la largeur à en déduire ; l'unité vw est intéressante mais d'usage extrêmement limité ; d'autres hacks à base d'images sont tout aussi répugnants[#] que celui à base de padding-bottom ; et certains ne lisent pas la question et proposent du JavaScript). C'est tout de même hallucinant qu'un langage aussi complexe, malgré toutes les extensions comme calc() et les variables CSS (à quoi c'est censé servir, alors), ne permette toujours pas de faire quelque chose d'aussi simple (sans passer par un hack à vomir) !

Voilà, donc comme je le disais, un exemple parfait où le CSS résout 90% de votre problème et vous nargue en rendant impossible de résoudre les 10% restants malgré son nombre invraisemblable de features mutantes.

[#] En fait, parmi les différents hacks proposés, celui qui me semble finalement le moins ignoble est celui basé sur du SVG justement :

<div style="position: relative; width: 400px; max-width: 60%">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
    viewBox="0 0 4 3" style="width: 100%" />
<div style="position: absolute; top: 0; left: 0; bottom: 0; right: 0; overflow: auto">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit…</p>
</div>
</div>

Cela devrait faire à peu près ce que je demandais (fixer une largeur de <div> de 400px ou 60% du contenant, la plus petite des deux valeurs, tout en imposant un aspect ratio de 4:3), et on peut presque défendre l'idée que c'est une solution propre (en un certain sens, conceptuellement, on se sert de SVG pour « dessiner » un rectangle vide dans lequel on inscrit ensuite le texte ; en tout cas, c'est moins moche qu'avec le padding-bottom qui n'a rien à foutre là). Mais ce qui n'est pas clair, c'est sur quels navigateurs ça fonctionnera, ni à quel point la dégradation sera gracieuse si ça ne fonctionne pas. C'est justement mon problème initial sur le SVG.

Au passage : des choses que je ne sais pas dire en bon français : une feature, le scaling des images, l'aspect ratio, du SVG inliné dans du HTML, un hack. Je ferais sans doute mieux d'écrire ce genre d'entrées entièrement en anglais.

↑Entry #2521 [older| permalink|newer] / ↑Entrée #2521 [précédente| permalien|suivante] ↑

↓Entry #2513 [older| permalink|newer] / ↓Entrée #2513 [précédente| permalien|suivante] ↓

(jeudi)

Le JavaScript, le DOM et les petites crottes de ragondins

J'ai écrit dans l'entrée précédente un petit bout de code en JavaScript permettant de générer de jolies images de pavages quasipériodiques. Forcément, c'est le genre de choses qui donne envie d'ajouter une fonctionnalité, puis une autre, puis encore une autre : choix du jeu de couleurs, choix de l'échelle, ce genre de choses. Au fur et à mesure, le code tend à se compliquer et à devenir un peu illisible (surtout que je suis parti de quelque chose d'un peu ancien dont je ne me rappelais plus exactement comment il fonctionnait — raison pour laquelle mes explications dans l'entrée en question étaient un peu confuses).

Là, je viens d'ajouter une fonctionnalité permettant de déplacer la région qu'on voit (il faut cliquer quelque part, déplacer la souris en gardant le bouton appuyé, et relâcher le clic). C'était assez naturel de souhaiter ça : après tout, l'image représente un bout d'un pavage infini du plan, on a envie de pouvoir explorer ce qui se passe quand on s'éloigne de l'origine. Double difficulté, la première étant due au fait que je n'avais pas du tout prévu ça dans mon code initial — là je ne peux m'en prendre qu'à moi-même —, la seconde étant qu'en JavaScript+DOM, tout est toujours plus compliqué que prévu.

Notamment, à chaque fois que le navigateur fournit une information, par exemple sur un événement (clic de souris, ce genre de choses), il vous fournit quantité de choses qui vont avec, mais on a l'impression que ces choses ont été savamment choisies pour donner l'impression d'être utiles mais être, au final, vraiment pénibles à utiliser.

Un exemple qui me semble frappant : je crée mon image dans un <canvas> HTML (c'est-à-dire une région prévue, justement, pour qu'on puisse dessiner dessus en JavaScript). Le <canvas> en question a une certaine taille, dans mon cas j'ai choisi 1024×768 pixels. (Enfin, pixel, il faut le dire vite, parce que la notion de pixel sur le web est un vrai chaos et c'est devenu une unité de mesure comme une autre. Mais disons que je peux faire comme si j'avais une image de 1024×768 pixels sur laquelle je peux travailler.) Sauf que comme l'image peut vite devenir trop grande sur un mobile, j'ai utilisé une incantation CSS style="max-width: 100%; height: auto" sur mon <canvas> pour demander au navigateur que, si l'image est trop grande pour tenir dans l'élément enveloppant, il la réduise à la taille appropriée (et ce, de façon proportionnée) ; je ne suis pas sûr de comprendre les subtilités, d'ailleurs, mais bon, ça a l'air de marcher. Maintenant, quand le navigateur transmet une information concernant un clic de souris (disons), il donne plusieurs copies des coordonnées du clic : par rapport à l'écran (screenX et screenY), par rapport à la page complète (pageX et pageY), par rapport au contenu effectivement affiché de la page (clientX et clientY), par rapport à on ne sait pas bien quel bord de l'élément lui-même (offsetX et offsetY), et par rapport à un truc que personne ne semble comprendre (layerX et layerY). On s'y perd complètement ! Mais ce qui est vraiment hallucinant, c'est qu'aucune de ces nombreuses coordonnées n'est celles qu'on veut vraiment, c'est-à-dire celles par rapport au <canvas> dans son système de coordonnées par défaut ! (Autrement dit, quelque chose qui renverrait un nombre entre 0 et la largeur/hauteur en pixels telle que précisée dans l'attribut width ou height de l'élément. Ou éventuellement, dans son système de coordonnées transformé par les opérations de translations, rotations et d'échelles qu'on a pu appliquer ultérieurement.) Et, pire, il n'existe aucun mécanisme simple pour faire la conversion : en m'inspirant d'informations glanées çà et là sur le Web, je me suis retrouvé à écrire l'horreur suivante :

function undoCSSFuckery(e) {
    // Compute event x and y relative to canvas which may be scaled by
    // CSS (***sigh!***).
    "use strict";
    var x,y;
    var rect = e.target.getBoundingClientRect();
    var clX = typeof(e.changedTouches)=="undefined" ? e.clientX : e.changedTouches[0].clientX;
    var clY = typeof(e.changedTouches)=="undefined" ? e.clientY : e.changedTouches[0].clientY;
    x = clX - rect.left;
    y = clY - rect.top;
    var width = rect.right - rect.left;
    var height = rect.bottom - rect.top;
    if ( e.target.width != width || e.target.height != height ) {
        x *= (e.target.width/width);
        y *= (e.target.height/height);
    }
    return [x,y];
}

— qui n'est certainement pas robuste parce que, par exemple, si le <canvas> a des marges ça ne va probablement pas marcher. Ah oui, il y a moyen d'interroger CSS pour connaître toutes sortes de choses, mais il faut prononcer un nombre impressionnant d'incantations propitiatoires pour le faire, et le résultat est souvent encore à déchiffrer derrière : par exemple, il va souvent renvoyer des informations en pixels sous forme de chaînes du type "1024px", et on ne sait jamais si ce suffixe px est garanti être là, ou comment on doit se débrouiller si une autre unité devait être retournée (le navigateur n'expose évidemment pas au JavaScript tous les mécanismes de conversions d'unités qu'il a forcément en lui-même !).

On a vraiment l'impression que tout est fait pour mettre des bâtons dans les roues du programmeur : lui donner douze fois la même information de douze façons subtilement différentes pour l'embrouiller, et pour qu'il ne puisse pas savoir ce qui va marcher sur quel navigateur, mais surtout ne pas lui donner l'information qu'il veut vraiment, et le forcer à la calculer en utilisant, du coup, encore d'autres informations dont on ne sait pas ce qu'elles valent.

Le support du mouvement de la souris est du même acabit : je réagis aux événements "mousedown" et "mouseup" pour la souris, et aussi "touchstart" et "touchend" pour les interfaces tactiles, mais j'ai cru comprendre que les interfaces tactiles généraient typiquement ausis du "mousedown" et "mouseup", et qu'en utilisant e.preventDefault() j'allais éviter ça — mais je ne sais pas si j'ai fait ce que j'aurais dû. Et il n'y a évidemment aucun moyen fiable de s'assurer qu'on est en train de bien associer le bon événement "mouseup" au bon "mousedown" au cas où des événements se seraient perdus en route (il n'y a pas, par exemple, moyen de sauvegarder une information au moment du "mouseup" qui serait garantie être retournée par le "mousedown" correspondant). Quelle horreur !

Dans ces conditions, il n'est pas surprenant que fleurissent toutes sortes de bibliothèques et frameworks JavaScript (du style jQuery), qui facilitent certaines tâches mais augmentent la lourdeur du code et son temps de chargement, et ajoutent leur propre complexité à la moussaka en surchargeant des choses qui existent déjà et en rendant plus complexe la recherche de solutions en ligne (notamment pour distinguer les solutions en pur JavaScript et celles en jQuery ou équivalent). D'ailleurs, que je sache, jQuery ne fournit pas l'équivalent de ma fonction undoCSSFuckery() ci-dessus, ce qui est quand même impressionnant pour une bibliothèque censée tout faire même le café.

Bref, mon code pour déplacer dans les images de l'entrée précédente marche peut-être. Parfois. Certains jours. Sur certains navigateurs. Si vous voyez comment faire plus propre, n'hésitez-pas à me le dire.

↑Entry #2513 [older| permalink|newer] / ↑Entrée #2513 [précédente| permalien|suivante] ↑

↓Entry #2453 [older| permalink|newer] / ↓Entrée #2453 [précédente| permalien|suivante] ↓

(mardi)

Pourquoi je continue à penser du mal de HTTPS

Je dois régulièrement expliquer à plein de gens pourquoi mon site n'est pas accessible en HTTPS et pourquoi je continue à ne pas aimer HTTPS : j'avais déjà écrit une entrée à ce sujet, mais d'une part je la trouve mal écrite, et d'autre part il y a beaucoup de choses à y changer maintenant, surtout du fait de l'existence de Let's Encrypt — car à chaque fois que je dis du mal de HTTPS on me répond oui mais Let's Encrypt. Alors oui, l'existence de ce machin est un énorme progrès dans le système mafieux du HTTPS, suffisant pour que j'envisage de m'en servir. Mais il reste que c'est un progrès sur un système aux principes plutôt pourris, au fonctionnement mafieux, aux buts mal définis, à l'architecture mal conçue, et auquel on attribue des vertus qu'il n'a pas. Je veux donc récapituler mes principales objections, qui ne sont pas forcément rédhibitoires (même mises toutes ensembles), mais suffisantes pour me faire juger que ça n'en vaut peut-être pas la peine en tout cas pour un site comme le mien (qui ne suis pas une banque).

J'insiste sur le fait que tout ceci n'est qu'une récapitulation (voire un brain dump), pas un argumentaire bien-formé. Chacun des points ci-dessous mériterait d'être examiné ou documenté soigneusement et, franchement, je n'ai pas le temps de m'en occuper. Il y a donc sans doute beaucoup de préjugés et de choses dont je ne suis pas du tout sûr (du coup, sans doute pas mal d'erreurs), je ne me suis renseigné que minimalement, mais je n'ai vraiment pas le temps d'essayer de me plonger dans ce merdier : normalement je n'aurais pas publié tout ça parce que je n'aime pas publier des choses où je n'ai pris que très peu de temps de vérifier mes renseignements, mais je commence à en avoir marre d'entendre les gens me chanter des variations sur le thème de maintenant que Let's Encrypt existe, il est temps que tu rendes ton blog accessible en HTTPS, souvent avec un ton de reproche.

Je ne vais pas chercher à ordonner les catégories le HTTPS est mal conçu, le HTTPS pose des problèmes, le HTTPS a des limitations et le HTTPS est relié à d'autres choses qui posent elles-mêmes des problèmes (catégories pas forcément exclusives), je fais confiance au lecteur pour retrouver dans quelle boîte ranger chacune des sections qui suit. Je vais sans doute me répéter, aussi, ou séparer des reproches en plusieurs morceaux : ça fait partie du puzzle à rassembler.

Les autorités de certification sont toujours un système mafieux

Par système mafieux je veux dire un système où un site Web doit se mettre sous l'autorité d'un parrain (autorité racine) pour bénéficier de sa protection, le parrain vous faisant payer selon le niveau de sécurité dont vous voulez bénéficier. Tout est absurde dans ce système : il n'est pas possible de se mettre sous la protection de plusieurs parrains (l'allégeance est exclusive) ni pour l'utilisateur d'accorder une valeur différente (si ce n'est tout ou rien) à différents parrains, ni de cumuler plusieurs sources de confiance (comme le fait d'avoir déjà visité le site) ; tous les parrains ne font pas les mêmes efforts de vérification, et par conséquent la protection réellement assurée est, en fait, le minimum de toutes — il suffit qu'un des parrains soit un traître ou un incompétent et tout le système s'effondre jusqu'à ce qu'on trouve moyen de le contenir.

Le nouveau venu Let's Encrypt est un parrain moins rapace que les autres, il distribue sa protection de façon pas trop regardante, mais évidemment, cette protection est minimale : il accorde le certificat à celui qui semble contrôler le domaine de différents points de vérification, ce qui est une vérification faible contre les attaques du type man-in-the-middle. C'est mieux que rien, mais ce n'est pas beaucoup. Tout le HTTPS (ou en tout cas, tout ce qui ne bénéficie pas d'un certificat à « validation étendue », mais ça sert à tout autre chose) est donc aligné sur ce minimum.

Reste qu'en participant à la manie de tout passer en HTTPS, on aide au développement de ce système mafieux qui, même si un des parrains est moins mauvais que les autres, reste un système mafieux. (Comparer avec DANE.)

↑Entry #2453 [older| permalink|newer] / ↑Entrée #2453 [précédente| permalien|suivante] ↑

↓Entry #2322 [older| permalink|newer] / ↓Entrée #2322 [précédente| permalien|suivante] ↓

(dimanche)

Je hais le CSS

Pour ceux qui ne connaissent pas le jargon des technologies du Web, CSS est le langage de « feuilles de style » définissant l'apparence des pages HTML, c'est-à-dire la manière dont la structure — censément sémantique — des éléments de la page va s'afficher graphiquement, c'est-à-dire, quelles en seront les couleurs, les polices, les tailles, les emplacements, et les autres effets. Si on veut se faire une idée d'à quoi un site ressemble sans CSS, on peut, dans Firefox, sélectionner dans les menus View → Page Style → No Style, et on aura la version HTML brute — j'imagine que les autres navigateurs permettent quelque chose de semblable. En principe, d'ailleurs, CSS ne concerne pas que les affichages mais aussi, par exemple, le rendu sur les synthétiseurs vocaux, et permet de dire quand tel élément est rendu par un synthétiseur vocal, il doit être prononcé avec une voix féminine, mais je ne sais pas si c'est purement théorique ou s'il y a vraiment des situations où ça marche, alors qu'au moins, pour l'affichage graphique, ça marchouille.

Ce langage est donc devenu quelque chose d'incontournable pour un site Web (si on veut faire le moindre changement par rapport à l'affichage totalement basique du HTML). Et le problème, c'est que ce langage est profondément merdique.

Je ne parle même pas des choses que CSS ne permet pas de faire : on ne peut pas, par exemple, choisir un peu finement la manière dont les lignes seront coupées (par exemple demander l'algorithme de Knuth-Plass de 1981 — on ne peut pas dire que ce soit une technologie ultra-récente ; bon, il est vrai que des gens l'ont implémenté en JavaScript) ; on ne peut même pas faire quelque chose d'aussi idiot que de flotter une image sur le côté en fixant la position verticale de l'image par rapport à son bord inférieur ; on ne peut pas vraiment mettre en page un texte en vers où on reprend une ligne interrompue à l'emplacement horizontale où la ligne précédente s'était finie (bon, peut-être que maintenant on peut, ça fait longtemps que j'avais voulu faire ça et que j'avais dû abandonner) ; on ne peut pas ajuster la taille d'une <iframe> automatiquement à son contenu ; on ne peut pas demander à une classe d'hériter une propriété d'autre chose que son parent immédiat (par exemple si j'ai une classe texte-vert et que je veux une classe que j'utiliserai dans celle-ci qui reprend la couleur normale extérieure à texte-vert sans avoir à faire d'hypothèse sur ce qu'est cette couleur). La liste est infiniment plus longue, mais je dis juste ce qui me passe par la tête. Pour chacune de ces choses, il y a des façons atrocement sales de contourner le problème avec du JavaScript dégueulasse qui va casser tout le temps et poser plein de problèmes pour plein de gens, donc on est tenté de faire semblant qu'il n'y a pas de problème.

Mais même pour des choses que CSS permet de faire, ce langage est atroce : on est devant un bricolage de propriétés dont on comprend mal l'interaction, et dont les règles précises sont extrêmement complexes (rien que la définition du bloc contenant est à s'arracher les cheveux : en mettant un html { position: relative; } dans une feuille de style, qui logiquement ne devrait rien faire du tout, on change la signification d'un <div style="position: absolute; top: 0px; bottom: 0px; width: 100%; height: 100%"> à cause de ces règles à la complexité byzantine). Et tout est à l'avenant : à chaque fois que je me plonge dans ce truc, j'en ressors dégoûté, et bien souvent j'abandonne ce que je voulais essayer de faire.

Mais le problème qui me paraît le plus insoluble, c'est celui du réglage des tailles. Je veux dire : la taille des polices texte, la longueur des lignes (relativement à cette taille et/ou relativement à la taille de l'écran), et les choses de ce genre comme la taille des images. Le problème est devenu d'autant plus aigu en cette dernière décennie que les navigateurs mobiles sont partout, donnant naissance à une profusion de combinaisons entre largeurs d'écran et résolutions.

La raison pour laquelle le problème est insoluble, c'est que c'est avant tout une question de préférence utilisateur : ce n'est pas à moi de décider la taille de caractères avec laquelle afficher mon site Web, ou la largeur des lignes — moi, ce que je veux pouvoir décider, c'est si une image est flottée à gauche ou à droite ou centrée, si tel texte doit s'afficher dans une couleur différente, etc. (et de fait, ça, CSS le permet relativement bien).

Fondamentalement, la difficulté est que CSS est prévu pour les cas où on contrôle tous les paramètres (i.e., la feuille de style spécifie tout : taille des polices, taille des lignes, etc.), dès qu'on commence à laisser des choses non-spécifiées (parce qu'on ne veut pas préjuger de ce que l'internaute lecteur préfère), le langage est foncièrement inadapté.

Concernant la longueur des lignes, le problème est vraiment grave : énormément de sites Web ont des bandeaux sur les côtés (une habitude que je trouve horripilante, même si c'est un moindre mal par rapport aux bandeaux « sticky » — c'est-à-dire non défilants — collés en haut de fenêtre), du coup beaucoup d'internautes prennent l'habitude d'avoir des fenêtres très larges pour pouvoir s'accommoder de ces bandeaux sans réduire les lignes de texte utile à une largeur ridicule ; mais du coup, s'ils vont voir un site sans bandeaux latéraux, comme le mien, ils risquent de trouver les lignes trop longues et d'en être gênés ou d'être agacés de devoir changer la taille de leur fenêtre : que puis-je y faire ? inventer des bandeaux sur le côté, peut-être vierges, juste pour me conformer à cette habitude crétine d'en mettre partout ? Je ne sais pas quoi faire. Pour l'instant, mon attitude est donc de ne pas spécifier quoi que ce soit sur la longueur des lignes dans la feuille de style.

Un problème relativement semblable se pose pour la taille des caractères : personnellement, comme j'ai une mauvaise vue (mon ophtalmo prétend que j'ai 10/10 aux deux yeux après correction, mais je crois que soit il ment, soit 10/10 est vraiment un minimum et qu'on ne peut trouver qu'on ne voit bien que si on a au moins 14/10), j'ai sans arrêt envie d'augmenter la taille des polices des sites Web que je visite. (Une subtilité est que je n'ai généralement pas envie d'augmenter la taille des images : heureusement, Firefox permet, dans View → Zoom → Zoom Text Only, de choisir si le zoom augmente uniquement la taille du texte ou tout sur la page ; malheureusement, certains sites se comportent assez mal quand on zoome le texte et pas les images, et CSS est un peu responsable de ce désastre.) Je ne peux pas vraiment en vouloir aux sites Web que je visite de ne pas avoir prévu une taille plus grosse, parce que j'imagine que beaucoup d'internautes préfèrent plus petit que ce que je mets, mais le problème est quand même que rien n'a été prévu pour tenir compte de ces différences de goût. Question accessibilité aux malvoyants, c'est nul.

Et sur un navigateur mobile, c'est encore pire : il n'y a généralement pas vraiment moyen de changer la taille du texte. On peut certes zoomer, mais le zoom se fait en gardant un rapport constant taille de ligne sur taille des caractères (contrairement à ce qui se passe quand on zoome dans un navigateur sur ordinateur fixe), du coup on ne voit plus des lignes complètes et c'est essentiellement impossible de lire un site comme ça. (Il y a là un vrai défi pour les concepteurs des interfaces utilisateur des navigateurs : il y a trois types de zoom différents — le zoom du texte seul, le zoom du texte plus image mais pas de la largeur totale de la page, et le zoom de tout, et il faudrait fournir un moyen intuitif de faire tout ça séparément, alors même que les utilisateurs n'arriveront souvent pas à comprendre la différence.) J'arrive donc à la situation absurde que je n'arrive pas à lire mon propre site sur mon propre téléphone mobile, parce que les caractères sont trop petits, et je ne sais pas vraiment régler le programme.

Un navigateur mobile fonctionne en faisant semblant qu'il a une résolution généralement plus grande que ce qu'il a : par exemple, il peut rendre la page à une résolution de 900 pixels de large (i.e., comme un navigateur sur ordinateur fixe le ferait avec une fenêtre d'une telle largeur) et ensuite appliquer le niveau de zoom qui fait tenir cette largeur dans la largeur du téléphone ou de la tablette. Ce nombre de 900 (dans mon exemple) est tiré de l'élément <meta name="viewport"> que l'auteur de la page Web peut choisir d'utiliser. Ce même élément permet aussi de demander de rendre à la taille naturelle (i.e., la vraie résolution) de l'appareil mobile. Malheureusement, le mécanisme est complètement con (le fait qu'il ait été inventé par Apple n'y est sans doute pas étranger) : on peut spécifier soit un nombre exact, du genre 900, soit le nombre naturel (qu'on ne contrôle pas du tout), mais on ne peut pas spécifier un multiple du nombre naturel ; par exemple, on ne peut pas demander à afficher la page sur une largeur qui serait égale à 1.5 fois le vrai nombre de pixels de la largeur du mobile (on peut spécifier un niveau de zoom, mais ce n'est pas du tout pareil, parce que ça ne change pas la largeur sur laquelle la page sera rendue). Or spécifier un nombre exact est généralement très con : ça veut dire avoir le même rendu sur tous les mobiles et toutes les tablettes quelle que soit leur taille (et l'orientation dans laquelle on les tient). Mais demander le vrai nombre de pixels est aussi problématique : si un site Web s'affiche sur un écran de téléphone de 320 pixels de large sans aucun dézoom, il va vraiment falloir changer la feuille de style, et c'est là que CSS repointe le bout de son nez hideux. De mon point de vue, afficher mon site Web sur une largeur égale à 1.5 fois la résolution du mobile serait à peu près l'idéal, mais non, ce n'est pas possible.

CSS devrait permettre de faire des choses intelligentes si le nombre de pixels de large est trop petit, par exemple, diminuer la taille des polices : il y a toutes sortes de mécanismes pour faire des tests sur la résolution ou d'autres attributs de l'affichage. Mais ensuite, on ne peut pas vraiment en faire quoi que ce soit d'utile. Changer la taille des polices, ça va. Mais changer la taille des images ? Pour autant que je sache, ce n'est pas possible, si une image est déclarée <img width="666" height="444"> dans le HTML (et on est bien obligé de déclarer largeur et hauteur si on veut que le navigateur laisse le bon espace tant que l'image n'est pas encore chargée), de faire du CSS pour qu'elle s'affiche, disons, à 50% ou 75% de sa taille déclarée — voilà vraiment une limitation idiote. (On pourrait peut-être s'en sortir en utilisant des variables CSS, ou la fonction attr, mais rien de tout ça n'est supporté par un nombre non-négligeable, voire non-nul, de navigateurs. On peut aussi sans doute s'en sortir avec du JavaScript immonde, mais ça voudra dire que la page sera modifiée avant affichage et donc probablement mal affichée dans plein de situations.)

Bref, j'ai fait ce que j'ai pu en ajoutant à mes pages une balise <meta content="width=device-width, initial-scale=1" name="viewport" /> (pour afficher à taille naturelle sur mobile), et à ma feuille de style les règles ad hoc suivantes (pour diminuer la taille du texte et certaines marges quand la largeur est très petite)

@media (max-width: 640px) {
  body { font-size: 12px; }
  .weblog-entry { padding: .5em; }
  .pic { margin-right: .5em; margin-bottom: .5em; }
  .pic-right { margin-left: .5em; margin-bottom: .5em; }
  .pic-embed { margin-right: .5em; margin-bottom: .5em; margin-top: .5em; }
  .pic-embed-right { margin-left: .5em; margin-bottom: .5em; margin-top: .5em; }
}
@media (min-width: 641px) and (max-width: 780px) {
  body { font-size: 14px; }
}
@media (min-width: 781px) {
  body { font-size: 16px; }
}

— mais peut-être que j'ai empiré les choses plus qu'autre chose. Si des gens ont des idées sur comment contourner les limitations insupportables du CSS, surtout, faites-moi part de vos idées.

Ajout : J'oubliais d'ajouter une précision à propos du redimensionnement des images (voir aussi ce lien, dont aucune des réponses ne convient vraiment) : on peut presque le faire en utilisant les transformations CSS, spécifiquement, en écrivant img { transform: scale(0.5,0.5); } sauf que… l'espace occupé par l'image reste quand même identique (bon, je comprends qu'il y a une difficulté à calculer la bounding box si on autorise n'importe quelle transformation, mais quand même, ils auraient pu prévoir une variante de scale pour laquelle la boîte est transformée aussi !).

↑Entry #2322 [older| permalink|newer] / ↑Entrée #2322 [précédente| permalien|suivante] ↑

↓Entry #2246 [older| permalink|newer] / ↓Entrée #2246 [précédente| permalien|suivante] ↓

(lundi)

Comment travailler sur du XML en conservant le formatage ?

Je ne suis certainement pas le premier à me poser cette question, et ça m'étonnerait un peu qu'il n'y ait pas déjà une solution, mais je ne trouve pas — il faut dire que je ne sais pas bien quoi chercher comme mots-clés.

Voici mon problème :

J'ai des fichiers XML que je voudrais traiter avec des outils XML, par exemple appliquer une feuille de style XSLT (qui laissera la grande majorité du document inchangé, se contentant d'ajouter des attributs ici ou là, ou peut-être quelques balises). Néanmoins, je voudrais préserver, dans la mesure du raisonnable, le formatage du document d'origine : par formatage dans cette phrase, je veux dire la manière dont les balises et les attributs sont écrits/sérialisés (par exemple, <foo color="blueish" price="expensive" /> et <foo price='expensive' color='blueish'/> sont deux formatages différents de la même balise, de même que des changements possibles du whitespace, et plus généralement tout ce qui conduit au même XML canonique — on peut d'ailleurs considérer ça comme la définition du formatage : deux documents XML diffèrent uniquement par le formatage lorsqu'ils ont le même XML canonique). Concrètement, je veux que le diff de mon document après traitement (par une feuille de style XSLT qui ne change que quelques attributs ou balises) soit en gros aussi faible que possible avec celui avant traitement (parmi tous les formatages possibles de la sortie XML du traitement).

Éclaircissement/redite : Comme je semble avoir été mal compris, je vais essayer de redire différemment ce que je cherche à faire. Je ne cherche pas à reformater du XML, au contraire, je cherche à le modifier sans le reformater : je cherche à traiter du XML par des outils XML en changeant le moins possible le XML en sortie (et notamment, sans changer le formatage des balises qui n'auront pas du tout été modifiées). Concrètement, j'ai du XML écrit à la main, je veux faire des changements automatisés dessus tout en préservant les idiosyncrasies du formatage à la main (notamment : l'ordre des attributs, le whitespace dans les balises ouvrantes et fermantes, les sections CDATA, les entités, ou le fait d'écrire parfois certains caractères Unicode sous forme de références de caractères).

Y a-t-il des outils pour réaliser ça ?

Je pensais à l'idée suivante : inventer un namespace ad hoc qui sert à refléter le formatage XML. Autrement dit, partant d'un document XML sous un certain format texte, on aurait des outils qui ajoutent des attributs et balises de ce namespace servant à stocker tous les détails du formatage (l'ordre des attributs, le type de guillemets les représentant, le whitespace partout où il n'est pas significatif, etc.), et capables, inversement, d'interpréter (et retirer) ces attributs et balises pour recréer le document exactement tel qu'il était, même s'il a été reformaté entre temps (par exemple remplacé par son XML canonique). On pourrait alors travailler en trois étapes : ajouter les attributs et balises représentant le formatage, travailler avec XSLT sur le document ainsi enrichi (la feuille de style XSLT ignorerait typiquement les éléments de formatage), puis réappliquer le formatage sauvegardé dans les attributs et balises spécifiques (dans certains cas l'information de formatage serait incomplète ou non directement applicable, bien sûr, vu que des attributs ou balises ont pu être ajoutés, supprimés ou changés par le XSLT, mais le reformateur ferait « au mieux » dans un sens pas très important).

Ça ne doit pas être horriblement compliqué d'écrire des outils comme ça de sauvegarde/sérialisation et restauration/désérialisation du formatage, mais ça m'arrangerait de ne pas être celui qui invente la roue surtout si quelqu'un l'a fait avant moi. Quelqu'un connaît-il des choses dans ce sens ?

Ajout () : J'envisage essentiellement trois pistes pour résoudre mon problème :

  • La méthode générale exposée ci-dessus pourrait ressember à ceci : un premier outil transformerait le XML fourni en entrée en ajoutant des entités et éléments représentant sa syntaxe concrète. Par exemple <foo color='blueish' price='expensive'/> serait transformé en lui ajoutant un attribut ws:emptytag="&lt;foo color='blueish' price='expensive'/&gt;" servant à représenter la syntaxe concrète de la totalité de la balise sur une balise vide. Puis ce XML enrichi serait transformé par le XSLT. Enfin, un autre outil tenterait de réappliquer la syntaxe concrète, en vérifiant qu'elle correspond toujours à l'arbre XML (et en la supprimant dans le cas contraire) : du coup, par exemple, le XML canonique <foo color="blueish" price="expensive" ws:emptytag="&lt;foo color='blueish' price='expensive'/>"></foo> serait retransformé en <foo color='blueish' price='expensive'/> (grâce à la valeur de l'attribut ws:emptytag) tandis que s'il a été transformé, disons, en <foo color="blueish" price="inexpensive" ws:emptytag="&lt;foo color='blueish' price='expensive'/>"></foo> (par changement d'un attribut) alors il deviendrait simplement <foo color="blueish" price="expensive"></foo> (en supprimant purement et simplement l'attribut ws:emptytag qui n'a plus la bonne valeur).
  • Une deuxième approche consisterait à essayer simplement de faire des modifications avec perl, mais en ayant marqué les emplacements à modifier avec des outils XML. Voici donc une question plus simple que ma question générale ci-dessus : y a-t-il des outils qui permettent, donné un fichier XML et une expression XPath, de retourner le numéro de ligne (et éventuellement le numéro de colonne dans la ligne) où commence (la syntaxe concrète de) l'élément désigné par le XPath ? (Il y a une question apparentée par exemple ici. Je suppose que je dois pouvoir m'en sortir en construisant l'arbre DOM avec un parseur SAX et en annotant chaque élément par son numéro de ligne.)
  • Une troisième approche, qui est certainement la plus simple, mais évidemment aussi la moins générale : canoniser mon document XML, appliquer la transformation XSLT sur le document canonisé (et canoniser la sortie), faire le diff entre les deux, et essayer d'appliquer ce patch au fichier XML de départ, en priant pour qu'il s'applique sans mal (ce qui, pour ce que je veux faire, est tout de même hautement probable).

J'avais réfléchi à plusieurs occasions à ce problème et à des questions adjacentes, et je m'étais dit qu'il faudrait développer une petite théorie formelle des encodages, réencodages et transcodages de l'information : notamment, je pense que le théorème de Cantor-Schröder-Bernstein a son mot à dire dans l'histoire du round-trip encoding (je rappelle qu'il s'agit du théorème qui affirme que si on a une injection f:AB et une injection g:BA dans des sens opposés entre deux ensembles, alors on a une bijection entre A et B), et que sa démonstration (constructive !) pourrait fournir des conventions en la matière. (Je ne prétends pas qu'il s'agisse du même problème que celui évoqué ci-dessus, mais qu'il s'agit de problématiques du même genre ; on pourra par exemple réfléchir à la question suivante : si j'appelle f la fonction qui envoie tout arbre (DOM) XML abstrait sur son XML canonique, et g la fonction qui envoie un document texte sur l'arbre DOM XML qui a une unique balise text contenant tout le texte, alors à quoi ressemble la bijection entre fichiers texte et arbres XML que produit une démonstration constructive standard du théorème de Cantor-Schröder-Bernstein à partir de ces deux injections ? Même question si on remplace g par une injection des documents XML bien-formés dans les arbres DOM XML obtenue en ajoutant des balises de formatage comme je le suggère ci-dessus.)

↑Entry #2246 [older| permalink|newer] / ↑Entrée #2246 [précédente| permalien|suivante] ↑

↓Entry #2122 [older| permalink|newer] / ↓Entrée #2122 [précédente| permalien|suivante] ↓

(dimanche)

Polices, et partages des ressources par haché

☞Commençons par le contexte.

Je me suis dit que j'aimerais changer la police avec laquelle ce blog s'affiche. Pour le moment, celle-ci doit varier énormément d'une personne à l'autre : actuellement, dans le CSS, je précise pour la police principale : font-family: Optima, "Zapf Humanist", Palatino, "Palatino Linotype", serif; — c'est-à-dire que le navigateur ira chercher, par ordre de préférence décroissante, des polices appelées Optima ou Zapf Humanist (c'est essentiellement la même), puis Palatino ou sa version Linotype (c'est quasiment impossible de savoir quels noms différents une police donnée peut prendre, malheureusement), ou, faute de quoi, la police sérif par défaut.

J'aime énormément la police Optima pour son compromis subtil entre sérif et sans-sérif, entre humanisme et modernité, entre sobriété et audace ; elle est malheureusement rarement disponible sur les PC, sauf sans doute sur les Mac ; à défaut, Palatino, du même concepteur, doit être beaucoup plus souvent installée puisque c'est une des polices PostScript standard, donc forcément distribuée (ou au moins un de ses clones comme URW Palladio L ou TeX Gyre Pagella — mais en fait je ne sais pas si les mécanismes de recherche de police vont automatiquement les sélectionner) sur essentiellement tous les systèmes du monde.

Maintenant, comme je fais un usage assez immodéré de caractères Unicode non-latin, il serait bien de trouver une police qui les contienne (il y a bien un Optima avec du cyrillique, mais essentiellement personne ne doit l'avoir). Histoire que СССР et CCCP apparaissent comme identiques. Par chance, il existe une police libre de bonne qualité, tout à fait dans le même esprit qu'Optima, et qui contient un répertoire passablement étendu de caractères Unicode (latin, phonétique, grec, cyrillique…) : il s'agit de la police Linux Biolinum (le nom est assez ridicule, il faut dire, et le mot Linux — un simple hommage — peut prêter à confusion et laisser croire à tort qu'elle ne fonctionne que sous ce système d'exploitation, mais à part ça c'est une très bonne police). Elle est la petite sœur de la police Linux Libertine, qui s'inspire, pour sa part, plutôt de la police Times de Stanley Morrison (mais de nouveau en couvrant une région d'Unicode beaucoup plus importante), et qui est très connue au moins pour une chose : c'est celle qui sert à écrire le logo de Wikipédia (voir ici pour plus d'informations).

Je pourrais juste modifier le CSS pour mettre "Linux Biolinum O" avant Optima. Ça changerait la police pour la plupart des utilisateurs de Linux, ou tous ceux qui ont installé Linux Biolinum sur leur ordi. Mais ce n'est pas furieusement intéressant : le but d'une police libre est tout de même que tout le monde puisse l'avoir !

Je pourrais bien sûr aussi distribuer la police au format WOFF, qui sert exactement à ça. Le tracas, c'est que cette police n'est pas toute petite (c'est le revers de la médaille du fait qu'elle couvre beaucoup de caractères Unicode) : si je dois servir, pour quasiment chaque personne qui consulte ma page, 374ko pour la police en caractères droits, plus encore à peu près autant pour les italiques, et encore autant pour le gras (et évidemment je vais vouloir changer aussi les autres polices de la page, pas juste la principale), ça commence à devenir lourd : pour le serveur d'une part, et pour l'utilisateur aussi (j'aime que mes pages Web restent assez légères et sans fioritures inutiles).

Pour certaines polices, Google fournit un service, les Google web fonts, par lequel ils servent eux-mêmes les polices et n'importe quelle page Web peut les utiliser (à condition d'accepter de rediriger tous leurs utilisateurs sur les serveurs de Google pour cette requête…), et surtout, les ressources sont ainsi partagées (un navigateur ne téléchargera qu'une fois chaque police, pas une fois par page qui les utilise). Malheureusement, beaucoup de ces polices sont de mauvaise qualité, et en tout cas, ni Linux Libertine ni Linux Biolinum n'y figurent.

☞J'en viens au point essentiel.

Pour ce genre de ressource partagées que plusieurs pages Web pourraient vouloir utiliser, il me semble que la solution serait non pas d'avoir un serveur commun comme Google web fonts (ou la Open Font Library ou que sais-je encore), mais plutôt de les partager par haché. Autrement dit, j'utiliserais un type d'URL spécial qui indiquerait au navigateur client : je dispose d'une ressource LinBiolinum_R.woff dont le sha256 est df706b9a3c8d79781684ea1bc348f63513f61e6121633625e8581b0d38339a07, et elle est disponible à telle adresse ; le navigateur vérifierait s'il possède déjà cette ressource (en utilisant le haché fourni) et, sinon, la récupérerait à l'adresse que je lui fournis, et vérifierait que le haché est le bon, après quoi il l'enregistrerait comme ressource partagée pour ce haché : si une autre page Web prétend utiliser une ressource de même haché, il n'y aura plus besoin de la télécharger de nouveau (bien sûr, le navigateur gérerait l'expiration des ressources selon ses propres règles, vraisemblablement en faisant des stats sur l'utilisation passée de chaque haché). L'intérêt de spécifier le haché est que ça n'a pas d'importance quelle page Web a fourni la ressource : si elle a le bon haché, c'est forcément la bonne.

Ce mécanisme semblerait extrêmement utile pour tout ce qui peut être une ressource partagée entre pages Web : j'ai pris l'exemple d'une police, mais ça pourrait aussi être une version de telle ou telle bibliothèque JavaScript (au pif, celle-ci), et peut-être même certaines icônes particulièrement courantes. Ce mécanisme évite que les pages Web aient à se concerter, ou à utiliser une ressource centrale, pour partager des données. Tout ce qu'il demande, c'est de créer un nouveau schéma d'URL qui préciserait simplement le haché puis une (voire plusieurs) adresses où on peut obtenir le contenu. (Évidemment, deux versions différentes de la même ressource ne seraient pas partagées, mais ce serait déjà un mécanisme de cache très précieux.)

En plus, la compatibilité ascendante avec les navigateurs ne disposant pas de ce mécanisme pourrait se faire avec un peu de code en JavaScript grâce à registerProtocolHandler() (que tous les navigateurs doivent supporter puisque ça fait partie du standard HTML, n'est-ce pas ? /air naïf).

Cela semble tellement évident et tellement utile que j'ai du mal à croire que ça n'existe pas déjà ! Qu'il n'y ait pas au moins un projet du W3C ou dans le cadre du HTML5 pour standardiser quelque chose du genre. Et pourtant, je ne trouve pas. (Le plus proche que je vois, ce sont les URL magnet, mais c'est vraiment pour faire du BitTorrent, ce n'est pas typiquement le genre de choses qu'on s'attend à ce qu'un navigateur gère spontanément.) Est-ce que je n'ai pas les yeux en face des trous ?

[Comme je m'attends certainement à ce qu'on me dise : ah, mais ça existe, et ça s'appelle <truc>, attendez-vous à ce que cette entrée soit mise à jour en conséquence.]

↑Entry #2122 [older| permalink|newer] / ↑Entrée #2122 [précédente| permalien|suivante] ↑

↓Entry #2019 [older| permalink|newer] / ↓Entrée #2019 [précédente| permalien|suivante] ↓

(mercredi)

Personne n'a fait un TeX en JavaScript ?

On fait tellement de trucs impressionnants en JavaScript de nos jours que ça finit par ne même plus être drôle : là je viens de voir passer SQLite en JavaScript, ce n'est pas tellement impressionnant, en fait, vu qu'ils utilisent Emscripten ; je suis plus impressionné par cet afficheur de PDF écrit par l'équipe Mozilla et qui devrait idéalement permettre de voir des PDF sans plugin, et bien sûr il y a le célèbre JSLinux de l'inénarrable et génial Fabrice Bellard, qui fait tourner un Linux dans votre navigateur. J'attends le jour où quelqu'un portera Firefox ou Chrome en JavaScript qui tourne dans tous les navigateurs, ce qui permettra de dire ah, vous avez un vieux navigateur ? c'est pas grave, on va faire tourner un navigateur moderne dans votre navigateur. [Ajout () : Tiens, badass JS en a fait son poisson d'avril.]

Mais une chose qui m'étonne est que personne n'a apparemment passé TeX (ou LuaTeX) à la moulinette Emscripten pour produire un TeX-en-JavaScript (le plus proche de ça est JSMath [ajout : ou MathJax, avec lequel je confondais], qui comprend certes un bon bout de la syntaxe de TeX, mais qui n'est pas, et ne prétend pas être, un TeX complet). Outre que ce serait, comme les geeks normaliens aiment dire, grassouille (synonyme approximatif de badass dans badass JavaScript), je peux imaginer différentes raisons pour lesquelles ce serait potentiellement utile.

↑Entry #2019 [older| permalink|newer] / ↑Entrée #2019 [précédente| permalien|suivante] ↑

↓Entry #2011 [older| permalink|newer] / ↓Entrée #2011 [précédente| permalien|suivante] ↓

(mercredi)

Chrome m'inquiète

Chrome, je veux parler du navigateur Web. Et il m'inquiète non pas parce qu'il a une apparence beaucoup moins sympathique que ma peluche Mozilla. Pas non plus parce que l'omniprésence Google est un peu lassante. Mais simplement parce que je pense qu'il est mauvais pour l'écosystème Web qu'un seul navigateur se mette à dominer complètement le marché. Et malheureusement, c'est visiblement ce que le Web a beaucoup de mal à faire : admettre qu'il existe plusieurs navigateurs différents sans que l'un domine complètement les autres. Ça a longtemps été IE, avec des résultats catastrophiques ; puis ça a failli être Firefox ; et maintenant, c'est Chrome qui est parti pour rafler tout le marché : youhou, ce n'est pas possible d'avoir un peu de variété ?

(Oui, je sais, c'est bizarre : la part de marché de Firefox est encore tout à fait comparable à celle de Chrome, et celle d'IE est encore supérieure, mais la dynamique de ces parts de marché, ainsi que la domination de Webkit sur le web mobile, fait que Chrome, ou du moins Webkit, a déjà acquis une hégémonie écrasante et que ça ne va pas s'arranger.)

Évidemment, je suis concerné : parce que Chrome ne convient pas du tout à mes attentes. Il y a deux principales raisons pour lesquelles je ne l'aime pas : d'abord parce qu'il lui manque des standards du Web que je trouve très importants et que j'ai envie d'utiliser, notamment MathML et des gros bouts de SVG (le clipping et masking ont l'air d'être complètement cassés) ; mais surtout, parce qu'il n'est quasiment pas configurable, même un truc aussi simple que d'afficher le http:// au début des URL (ils ont décidé de l'omettre, ce qui se défend si c'est une option ou même le comportement par défaut, mais ce qui est assez fasciste si c'est imposé aux utilisateurs) n'est pas réglable sans recompiler le machin. Au contraire, Firefox, et c'est sa qualité principale à mes yeux, a un milliard d'options de configuration (tapez about:config dans la barre d'adresse si vous ne connaissez pas) qui permettent de régler très finement les préférences de chaque utilisateur : je prends ça comme l'exemple canonique pour prouver qu'un programme peut très bien être utilisable par n'importe quel neuneu et pourtant très finement réglable par les power-users (parce que beaucoup de gens prétendent que c'est impossible).

Mais bon, peu importent les raisons pour lesquelles moi personnellement je n'aime pas Chrome. Je conçois très bien qu'on le préfère parce qu'il est plus rapide que Firefox. Je n'ai aucune envie de faire de l'évangélisme de Firefox (sauf peut-être en montrant la peluche). Je n'ai rien contre le fait que Chrome invente plein de technologies dont l'intérêt me semble souvent assez douteux (SPDY, Dart, nativeclient, Pepper…) : en fait, quand je dis Chrome, généralement je veux dire Webkit, qui est le moteur partagé par Chrome et Safari (et plusieurs autres moins connus).

Ce qui me gêne, c'est la façon dont les gens développent ou testent des sites Web : si on passe d'un monde où on fait tout pour IE (et où les fonctionnalités des autres navigateurs ne servent pas à grand-chose, parce que personne n'ose s'en servir) à un monde où on prétend faire du HTML5 mais en fait le HTML5 en question ne marche correctement que sur Webkit, on n'a pas vraiment progressé. Voici le genre d'annonce qui me fait peur (le plugin Flash sous Linux ne sera à l'avenir disponible que pour Chrome, ben voyons), et voici un appel de Daniel Glazman (un des chefs du groupe CSS du W3C) dans le sens n'oubliez pas qu'il existe autre chose que Webkit.

D'un autre côté, je considère les différents groupes de standardisation comme partiellement responsables du problème. Le HTML5 est en travail depuis je ne sais pas combien d'années, et ils en sont encore à changer d'avis tous les trois jours sur des choses vraiment basiques dans leur standard (je vous ai parlé de <time> ? ah oui, je radote). Ça ne donne pas trop envie de s'appuyer sur le standard, ce genre de choses.

Et un autre truc que je ne comprends pas, c'est la manie qui a pris tout le monde de mettre des préfixes devant toutes les fonctionnalités un peu récentes : maintenant, pour utiliser une propriété CSS foobar un peu récente, il faut écrire non seulement foobar: blah, mais aussi -moz-foobar: blah pour que ça marche sous Mozilla/Firefox, -webkit-foobar: blah pour que ça marche sous Webkit/Chrome/Safari, -ms-foobar: blah pour que ça marche (peut-être) sous IE, et je ne sais pas quoi pour Opera. Et tout ça ne sert rigoureusement à rien à part faire des lignes de code en plus : le problème est (je crois !) que des gens ont peur qu'il y ait un changement epsilonesque entre la spécification et l'implémentation temporaire, mais si de toute façon toutes les pages Web utilisant cette fonctionnalité vont écrire toutes les variantes -préfixe-foobar: blah plus la variante sans préfixe (et on est bien obligé de faire ça pour que ça marche partout), ben je ne vois absolument pas quel problème on aura réglé. Or c'est le genre de manie qui fait que les gens vont juste écrire -webkit-foobar: blah et tant pis pour les autres navigateurs. Ben la faute en est à l'idée stupide de mettre des préfixes partout, alors faut pas s'étonner après.

↑Entry #2011 [older| permalink|newer] / ↑Entrée #2011 [précédente| permalien|suivante] ↑

↓Entry #1970 [older| permalink|newer] / ↓Entrée #1970 [précédente| permalien|suivante] ↓

(samedi)

Validation du HTML5, et énervement

Le HTML a toujours eu une relation de haine-amour avec les validateurs. Les validateurs, ce sont des programmes censés vérifier que le HTML qu'on écrit est (au moins dans une certaine mesure) conforme à la spécification. Par exemple, si on écrit <A HREF="http://example.tld/foobar/">cliquez <B>ici</A></B> le validateur va se plaindre que les balises A et B ne sont pas correctement emboîtées.

Cette relation de haine-amour a eu plusieurs phases.

Il y a eu une phase où le HTML (≤4) était formellement et ostensiblement basé sur une technologie complètement imbitable (i.e., un standard ISO) appelée le SGML : la spécification se présentait comme une extension de ce standard, les les validateurs utilisaient un parseur SGML pour vérifier le HTML. Les navigateurs, eux, fonctionnaient avec un parseur complètement différent, qu'on appelle vulgairement soupe de tags, et qui essaie de se débrouiller du mieux qu'il peut de la merde que les auteurs écrivent. Cette incompréhension fondamentale donnait des choses assez comiques : par exemple si vous faites valider à un validateur HTML4 un truc tel que <P><A HREF=http://example.tld/foobar/>cliquez ici</P> (à mettre au bon endroit à l'intérieur d'un document HTML, bien sûr) il vous dira que c'est correct alors qu'en apparence la balise A n'a pas été refermée — la raison étant qu'à cause des arcanes du SGML (et spécifiquement de la fonctionnalité SHORTTAG), il comprend le code précédent exactement comme <P><A HREF="http:"></A>example.tld/foobar/>cliquez ici</P> ce qui est bizarre mais formellement correct. Naturellement, ce n'est pas du tout ce que comprendront les navigateurs, puisque eux voient une soupe de tags, ils devinent qu'il faut fermer la balise A avant le P et comprennent donc <P><A HREF=http://example.tld/foobar/>cliquez ici</A></P> comme ce que l'auteur voulait (probablement) écrire : on a donc une situation assez paradoxale où le validateur comprend un truc complètement différent de ce qu'on voulait faire, le déclare comme correct, le navigateur, lui, comprend ce qu'on voulait en réparant l'erreur, et du coup on ne remarque pas qu'elle est là.

Puis on a inventé le XML, qui est incroyablement plus simple que le SGML (c'est-à-dire seulement très compliqué), et on s'est mis à tout réinventer à la sauce XML. Le XML a deux niveaux de conformité : un document peut être bien-formé (le niveau minimal : s'il n'est même pas bien-formé, ce n'est pas du XML du tout, et en principe un outil qui cherche à l'analyser a le devoir de le rejeter), et éventuellement valide de surcroît (c'est-à-dire conforme à une certaine déclation sur l'usage des balises, à l'origine il s'agissait de DTD, mais on a inventé différentes autres sortes de mécanismes de validation et du coup le mot valide est assez surchargé). Il y a toutes sortes d'outils pour reconnaître la bien-formitude du XML, et éventuellement la validité selon tel ou tel mécanisme de validité. Pour plein de choses, le XML a eu du succès, mais le HTML a résisté : quasiment personne n'écrit de HTML-sur-XML, ce qu'on appelle XHTML (si le XHTML1 a eu un relatif succès, le 1.1 a été très peu utilisé, et le 2 a été avorté). La raison est sans doute entre autres parce que le XML oblige un navigateur qui détecterait une erreur de non-bien-formitude dans une page XHTML à ne rien afficher du tout sauf le message d'erreur (et de fait, c'est ce que fait Firefox). Mais la raison principale est surtout qu'Internet Explorer ne supporte (supportait ?) pas le XHTML (application/xhtml+xml) : je ne comprends pas vraiment pourquoi, vu qu'il comprend le XML et qu'il comprend le HTML, c'était si difficile de gérer l'un sur l'autre, mais je ne cherche pas à savoir. Comme les deux standards sont de toute façon plus ou moins interopérables (il est possible d'écrire du XHTML valide et de le faire manger à un parseur soupe-de-tags), on peut du moins écrire du XHTML, le valider comme tel, mais le présenter comme du HTML (text/html) ; c'est ce que je faisais moi-même sur ce site Web jusqu'à récemment. L'inconvénient, c'est qu'en faisant ça on s'interdit d'utiliser des technologies comme SVG ou MathML qui ne pouvaient marcher que sur XML.

L'acte III de mon psychodrame concerne l'apparition du HTML5. Le HTML5 propose un nouveau mode de parsage du HTML, qui n'est ni basé sur SGML ni sur XML, ni vraiment le mode soupe-de-tags traditionnel des navigateurs, mais plutôt un nouveau mode soupe-de-tags, décrit de façon complètement formelle, et qui essaie de trouver un compromis entre la robustesse et la reproductibilité ; de plus, ce nouveau parseur rend utilisables certaines des technologies XML (le SVG et le MathML) dans le HTML. Bref, on a maintenant quatre modes de parsage (sur SGML, sur XML, par le nouveau mode HTML5, et l'ancien mode soupe-de-tags, ou plutôt les anciens car il y en a un différent par navigateur). Le HTML5 est aussi prévu pour pouvoir exister sur XML, auquel cas on l'appelle XHTML5, et comme ils ont fait attention à la façon dont le nouveau parseur fonctionne, il est même possible, au prix de quelques efforts, de faire des documents « polyglottes » HTML5/XHTML5, c'est-à-dire qu'ils peuvent se parser aussi bien avec le nouveau parseur HTML5 qu'avec un parseur XML, et si possible avec le même sens (ou des différences négligeables qui n'apparaîtront pas à celui qui lit la page). Les nouvelles pages de ce sites Web sont écrites dans ce style « polyglotte » : je les produis avec des outils XML, donc c'est du XHTML5, mais j'obéis à certaines contraintes qui font qu'ils seront analysés de la même façon par un parseur HTML5 (et, de façon limitée, c'est-à-dire SVG et MathML exclus, par un parseur HTML soupe-de-tags traditionnel). C'est un peu confus à expliquer, mais pas trop difficile au final, et ça marche plutôt bien.

Mais maintenant, comment valider ? Déjà, en principe, je devrais valider chaque page deux fois, une fois avec syntaxe HTML5 et une fois comme XHTML5, puisque mes pages sont censées être les deux à la fois. En fait, côté XML, je n'ai pas trop d'inquiétude, vu que les outils que j'utilise peuvent difficilement produire quelque chose qui n'est pas au moins bien-formé (j'ai eu cependant un cas où un oubli de ma part faisait que des balises ressemblaient à <p xml:lang="en" lang="en" lang="en"> avec une indication redondante d'attribut, ce qui rend le XML non-bien-formé), et si le XHTML5 est bien-formé en tant que XML et également valide comme HTML5, il y a fort à parier qu'il soit du XHTML5 valide (on peut donner des contre-exemples, par exemple en oubliant les bons attributs xmlns, mais il faut un peu le faire exprès). Mais comment vérifier, justement, qu'on a du HTML5 valide ?

En principe, il y a un validateur pour ça. En pratique, il est loin d'être exempt de problèmes. D'abord parce que — et ce n'est pas la faute du navigateur — le standard HTML5 n'arrête pas de bouger. Récemment ils avaient supprimé la balise time. Puis ils l'ont remise, mais avec un modèle différent. C'est un peu agaçant : je comprends qu'ils veuillent être un living standard (ce sont leurs mots), mais enfin, à ce point-là, sept ans après avoir commencé à bosser dessus, ce n'est pas très sérieux. Ensuite, parce que le validateur, je veux en avoir une copie chez moi, pas l'utiliser via un site Web distant (je veux valider mes pages avant de les avoir publiées, et sans forcément avoir l'intention de les publier d'ailleurs), or celui de validator.nu, il est particulièrement lourdingue à faire marcher : en principe le code est disponible, mais c'est une vraie bagarre à compiler, et l'arbre de compilation fait plus de 400Mo. Soyons sérieux ! Est-il normal que ce standard censé rendre le parsage du HTML plus robuste soit aussi monstrueusement compliqué à valider ? Et enfin, parce que ce validateur comporte des erreurs, ou en tout cas des bizarreries, par exemple quand on commence à mélanger le HTML avec SVG et MathML (ce qui était le but, somme toute). Je viens de me rendre compte, par exemple, qu'il n'inclut que les attributs de MathML 2, alors que le standard HTML5 fait (maintenant ?) référence à MathML 3 : du coup, j'ai des pages correctes qui me crachent des bordées d'insultes. Et comme je ne comprends rien à la façon dont fonctionne cette tambouille (en principe c'est juste du RelaxNG+Schematron utilisé derrière un parseur HTML5, mais apparemment les choses sont bien plus compliquées, parce que ça ça n'expliquerait certainement pas d'où sortent les 400Mo), je ne sais pas, par exemple, réparer le truc pour aller chercher les schémas MathML 3[#]. De toute façon, ce validateur a l'air de ne plus être maintenu.

Bref, pour l'instant, la validation HTML5, c'est pas encore trop ça. Alors je pourrais me dire, à quoi bon valider, de toute façon ça n'a pas d'importance, la chose qui importe est d'essayer avec deux ou trois navigateurs et vérifier que la page marche. Mais je n'aime pas cette attitude : d'abord, parce qu'il est parfaitement possible qu'une erreur faite maintenant, surtout sur des standards encore un peu chauds sortis du four, ne se manifeste dans les navigateurs qu'à l'avenir, et de toute façon je n'ai pas beaucoup de choix de navigateurs avec lesquels tester (s'agissant du MathML, comme Safari ne tourne pas sous Linux, j'ai exactement un navigateur utilisable, il se trouve qu'il a de sévères limitations sur précisément un truc que je voulais utiliser et dont le validateur m'aurait permis de vérifier que j'avais écrit les choses correctement dans l'espoir qu'un jour un navigateur les implémente… sauf que le validateur non plus ne connaît pas ces attributs… bref…). Et il y a quand même des fautes que je fais souvent, et qui ne se remarquent pas forcément, comme une faute de frappe dans une balise (comme c'est mon éditeur qui les insère, la même faute se retrouver sur la balise ouvrante et fermante), qu'il est quand même utile qu'un validateur puisse détecter.

[#] Bon, ce n'est pas tout à fait vrai : j'ai trouvé des schémas RelaxNG pour MathML 3, j'ai trouvé comment faire pour que le validateur tente de les charger, mais il me crache l'erreur suivante : Multiple definitions of “image” without “combine” attribute. File: http://s.validator.nu/mathml3/mathml3-content.rnc Line: 94 Col: 1 (de fait, la ligne en question du fichier mathml3/mathml3-content.rnc, qu'on peut trouver dans le fichier mathml3-relaxng.zip téléchargeable par le lien précédent, a pour contenu : image = element image { CommonAtt, DefEncAtt, empty} ; moi je ne sais pas du tout ce que ça veut dire vu que je ne connais pas RelaxNG, mais ce fichier ne contient certainement pas d'erreur vu qu'il est distribué par le W3C, et j'ai tendance à trouver que si le langage n'a pas été prévu pour pouvoir réutiliser tels quels les schémas, c'est vraiment qu'il est complètement pourri).

↑Entry #1970 [older| permalink|newer] / ↑Entrée #1970 [précédente| permalien|suivante] ↑

↓Entry #1936 [older| permalink|newer] / ↓Entrée #1936 [précédente| permalien|suivante] ↓

(mardi)

hAtom

Encore un petit fignolage, après quoi j'espère arrêter pour un moment de faire du méta sur ce blog (parce que les blogs qui parlent d'eux-mêmes, je pense que ça n'intéresse pas tellement les gens[#] — mais il faut bien s'occuper de la technique de temps en temps).

Comme il y a manifestement une demande pour un feed de ce blog qui inclue les entrées complètes et formatées, et comme je suis résolument hostile au fait de mettre ça dans le fichier RSS — non pas, je répète, parce que je ne veux pas qu'un feed contienne les entrées complètes, mais simplement parce que le fichier qui contient les entrées complètes, c'est le fichier HTML lui-même, donc ce sont aux agrégateurs de se démerder avec pour le présenter comme un feed[#2] — j'ai ajouté des informations au microformat hAtom qui sont censées indiquer que la page est un feed, que chaque entrée est une entrée, quelle en est la date et heure de publication, le titre et le contenu (forcément complet, donc). Il paraît qu'il existe des agrégateurs qui savent effectivement en faire quelque chose : donc essayez l'adresse principale du blog (http://www.madore.org/~david/weblog/) comme flux dans votre agrégateur préféré (ou tout autre outil équivalent), et voyez si ça donne quelque chose. Je suis un peu sceptique, parce que le format hAtom est vraiment mal spécifié et mal documenté (et est d'interaction douteuse avec le HTML5 : j'ai utilisé time pour spécifier les heures[#3] vu qu'il est hors de question de pervertir abbr pour ça comme les microformats le préconisent), mais bon, ça peut difficilement faire du mal.

Bref, si quelqu'un voit une amélioration quelconque, qu'il me le fasse savoir, ça me surprendra agréablement. Si ça ne marche pas, inutile de le signaler : je m'en doutais. (Si ça casse quelque chose, dites-le, m'enfin ça m'étonnerait quand même beaucoup.)

[#] Ceci dit, c'est peut-être un concept, en fait, un blog qui ne parle que de lui-même, avec des entrées qui pourraient s'intituler critique de l'entrée précédente, ou apologie de cette entrée-ci. Douglas Hofstadter avait bien proposé de faire un livre intitulé Reviews of this book, dont le contenu serait entièrement constitué des critiques du livre (l'idée serait de demander aux critiques littéraires de faire un premier tour où ils critiqueraient l'idée, on concatène ça en un livre, on leur envoie et ils modifient leurs critiques, et on répète jusqu'à ce que, on l'espère, ça finisse par converger, auquel moment on publie le livre et chacun peut écrire sa critique). Et je serais assez tenté de le lire, ce livre, s'il paraissait (enfin, je commencerais peut-être par vérifier si les critiques sont bonnes 😉).

[#2] C'est une idée qui flotte depuis longtemps puisque Mark Pilgrim la discutait en 2002.

[#3] Malheureusement, la date (published ou updated) est justement le truc considéré comme indispensable dans hAtom. Donc si l'utilisation de la balise time perturbe, rien n'en ressortira ; heureusement, j'ai mis cette balise sur la date qui servait de toute façon de permalien, et comme la date est au format ISO valide (sauf pour cette unique entrée que je conserve fièrement et précieusement), au moins un outil ne comprenant pas la balise time a des chances de lire la date du post sans l'heure.

↑Entry #1936 [older| permalink|newer] / ↑Entrée #1936 [précédente| permalien|suivante] ↑

↓Entry #1934 [older| permalink|newer] / ↓Entrée #1934 [précédente| permalien|suivante] ↓

(lundi)

Microdonnées, donc

J'avais évoqué le Web sémantique le mois dernier, je reviens un peu sur le sujet puisque je suis maintenant entré dans le monde merveilleux de HTML5.

Qu'est-ce que le Web sémantique ?

L'idée du Web sémantique, expliquée à un enfant de cinq ans (bon, OK, peut-être douze), pourrait être exposée comme ceci. Les ordinateurs ne sont pas très malins, ils ne savent pas comprendre le français (ou l'anglais, ou le chinois…), et en particulier, les moteurs de recherche ne comprennent rien du tout des pages Web qu'ils indicent : ils ne voient qu'un tas de liens qui pointent vers d'autres pages Web, séparées par du texte qui pourrait aussi bien être en cunéiforme. Ça ne les empêche pas de donner de bons résultats avec de la simple recherche dans du texte, mais parfois on aimerait bien qu'ils comprissent ce qu'ils reçoivent : ça permettrait de faire des recherches plus sophistiquées (par exemple : trouve-moi une recette de cuisine de gâteau facile à préparer en moins de 40′ — si on recherche les mots-clés les plus évidents, on peut encore s'en sortir pour les mots recette, gâteau, facile, mais le moins de 40′ à peu de chances d'apparaître comme ça dans la page, et inversement on peut tomber sur une page qui raconte j'ai réparé mon ordinateur en moins de 40′, c'était vraiment facile de changer le disque dur, la bidouille c'est du gâteau et je vais vous donner la recette de comment je m'y suis pris). D'où l'idée d'inventer un langage permettant de communiquer des informations simples d'une manière compréhensible par un moteur de recherche : non pas d'écrire une page Web séparée dans un langage adressé aux ordinateurs, mais d'annoter une page Web destinée aux humains pour permettre aux ordinateurs de s'y retrouver un peu, et de savoir vaguement de quoi ça parle.

Il n'est pas question de traduire tout le texte en langage machine, ni que ça s'applique à des concepts subtils, mais uniquement de faciliter la digestion d'informations factuelles simples qui pourraient figurer dans une base de données. Par exemple, expliquer que ceci est un blog, que le lien en haut à gauche est un permalien, que l'avant-dernière entrée est la critique d'un film (que les mots Habemus papam sont le titre de ce film, et Nanni Moretti le nom du réalisateur, et que la critique dans son ensemble pourrait se résumer par telle note). Un commerçant en ligne pourrait indiquer qu'il s'agit d'un commerçant en ligne, spécialisé dans tel type de choses, et s'il a des locaux dans le monde physique, à quel endroit ils sont, quelles en sont les horaires d'ouverture, etc. De cette manière, quelqu'un qui chercherait sur Google Maps tel type de commerce pourrait voir ce résultat apparaître.

C'est une bien jolie idée, il n'est pas sûr que ça puisse marcher. Par exemple parce que dès lors que les moteurs de recherche et les humains ne lisent pas exactement la même chose, quelqu'un peut avoir intérêt à chercher à tricher, à présenter une information dans le texte en français et une autre, contradictoire, dans le Web sémantique, parce que c'est la première qui l'engage et la seconde qui aide à le trouver, donc il pourrait afficher des prix faux pour ses articles. Ou quelque chose comme ça. D'un autre côté, il est déjà possible de faire à des fins douteuses des sites Web qui apparaissent différemment à Google et à un humain (mais si Google l'apprend ils vous punissent, et il y a des mécanismes pour signaler ce genre de tromperies). Il n'est pas non plus clair que ce soit si rentable (si quelqu'un est venu vous voir en cherchant le produit X et que vous ne l'avez pas, vous pouvez y gagner en vendant le produit Y à la place, mais vous pouvez aussi l'énerver beaucoup). Enfin, si les navigateurs évoluent eux aussi pour comprendre le Web sémantique et le présenter aux utilisateurs, ça permettra de démasquer ce genre de tromperie. Bref, pour l'instant, tout ceci est assez théorique — mais la question se pose en tout cas de savoir qui doit faire confiance à qui pour dire quoi sur quoi.

↑Entry #1934 [older| permalink|newer] / ↑Entrée #1934 [précédente| permalien|suivante] ↑

↓Entry #1929 [older| permalink|newer] / ↓Entrée #1929 [précédente| permalien|suivante] ↓

(jeudi)

Quels navigateurs utilisent mes lecteurs ?

Comme le passage à HTML5, évoqué dans l'entrée précédente pose le problème de la compatibilité des navigateurs, j'ai voulu essayer de savoir ce qu'utilisent mes lecteurs.

Problème : ce n'est pas évident du tout. D'abord parce que mon serveur Web est pollué de zillions de requêtes dont très peu, finalement, concernent vraiment le contenu réel : il y a les gens qui viennent depuis les moteurs de recherche (et dont l'écrasante majorité ne doit pas trouver ce qu'ils cherchaient, ou trouvent des choses idiotes : la page la plus populaire de mon site, et de très loin est celle-ci via Google images, ce ne sont pas des gens intéressés par moi ou par ce que je raconte), il y a les moteurs de recherche eux-mêmes et toute la jungle des robots butineurs, et il y a les agrégateurs… Une même personne peut revenir très souvent et plein de personnes peuvent se cacher derrière la même IP. Bref, c'est compliqué.

J'ai opté pour la méthodologie suivante : j'ai pris l'ensemble des requêtes depuis le 28 août, j'ai sélectionné uniquement celles qui demandaient une URL sous /~david/weblog/, puis j'ai trié par couple IP+UA (où UA désigne l'User-Agent, c'est-à-dire l'identifiant du navigateur tel qu'il est renvoyé par le navigateur). Je n'ai gardé que les couples IP+UA ayant fait au moins 5 requêtes dans la période (façon de m'assurer que ce sont de « vrais » lecteurs et pas des gens tombés là par hasard) : on peut appeler un tel couple IP+UA un « lecteur », même si bien entendu cela ne correspond pas forcément à une personne physique (par exemple parce que quelqu'un peut utiliser régulièrement deux navigateurs différents, ou deux ordinateurs différents, auquel cas il apparaît deux fois, et bien sûr parce qu'il y a encore des robots dans le tas). À ce stade-là, il restait 575 lecteurs. (Je jette le nombre de requêtes de chacun, qui ne m'intéresse pas.) Sur ces 575 lecteurs, j'ai essayé d'identifier (de façon semi-manuelle) tous les navigateurs habituels, en jetant tout ce qui est robot ou agrégateur (ou, en fait, tout ce que je ne comprenais pas) : il me reste 323 entrées, qui se répartissent de la façon suivante : [#]

118Firefox 6.0
49Firefox 3.6
32Chrome 13.0
17Firefox 5.0
11MSIE 8.0
11Firefox 9.0a1
10Opera 9.80
8Safari 5.0
7Safari 5.1
7MSIE 7.0
7MSIE 6.0
7Firefox 4.0
7Firefox 3.5
5MSIE 9.0
5Firefox 7.0
5Firefox 3.0
3Safari 4.0
3Chrome 12.0
2Chrome 14.0
1w3m 0.5.2
1Safari 4.1
1Safari 3.0
1Firefox 2.0
1Firefox 1.5
1Chrome 9.0
1Chrome 7.0
1Chrome 15.0
1Android 2.3

Bon, je ne peux qu'insister sur le fait que ça ne veut pas dire grand-chose (par exemple, les 11 « lecteurs » utilisant Firefox 9.0, c'est plutôt une personne qui a changé 11 fois de version), mais ça donne quand même une idée : très grossièrement 68% de mon lectorat qui ne passe pas par un agrégateur utilise Firefox, 12% utilise Chrome (ou Chromium), 9% IE, 6% Safari et 3% Opera. Le navigateur le plus susceptible de poser problème est MSIE ≤8, et j'aimerais savoir s'il arrive encore à afficher mon site (je ne parle évidemment pas de comprendre le SVG ou le MathML, mais juste d'afficher quelque chose de vaguement lisible).

[#] Je profite de cette table pour pousser une gueulante : avec tout ce que le HTML a inventé, et tout ce que le CSS permet de faire, il reste excessivement pénible de fixer l'alignement d'une colonne d'un tableau (par exemple, comme je voudrais le faire ici, aligner sur la droite les chiffres de la première colonne). Le HTML5 a supprimé l'attribut align qui était la façon évidente de faire ça en HTML4, en reléguant la fonction à CSS, mais justement CSS n'offre pas vraiment de mécanisme qui convienne. Naïvement on pourrait penser qu'ajouter un <col style="text-align: right" /> fonctionnerait, mais comme Ian Hickson l'explique, ce n'est pas le cas, parce que les propriétés CSS des colonnes ne servent que pour un très très petit nombre de trucs, et il y a des raisons à ça (je trouve que ces raisons assez peu convaincantes, d'ailleurs, mais je ne vais pas entrer dans les détails). On peut toujours faire un truc comme #maTable td:nth-child(n) { text-align: right } [#2], mais ce n'est pas vraiment une réponse, parce que les cellules d'une table peuvent faire plusieurs colonnes de largeur, donc il n'y a pas moyen de sélectionner à coup sûr les cellules de la colonne n avec un truc aussi simple que nth-child… du coup, la seule solution est de styler chaque cellule individuellement (ce qui ne répond pas à la question : on ne fixe pas l'alignement de la colonne, on fixe l'alignement de chaque cellule de la colonne). En guise de protestation, je laisse le tableau non aligné.

[#2] Par contre, j'e profiter de ça pour évoquer quelque chose d'autre : ma très grande satisfaction à découvrir que le HTML5 a introduit l'attribut scoped sur l'élément style, qui permet d'ajouter des règles de style sur un élément et tous ses descendants. En effet, en HTML4, on pouvait déjà mettre des attributs style sur un élément pour définir des règles qui s'appliquent à lui, mais si on voulait mettre une règle sur ses descendants, on était obligé de passer par la stylesheet globale : pas moyen d'écrire par exemple <table style="THIS td:first-child { text-align: right }">…</table> pour que tous les premiers td contenus dans la table soient alignés à droite : on devait soit mettre l'attribut style séparément sur chaque balise td de la table, soit donner à la table un id ou une classe (ce qui n'est pas problématique en soi) et insérer la règle de style à un tout autre endroit (ce qui, en revanche, est sérieusement merdique quand on songe que le bout de HTML en question pourrait être, par exemple, transcopié dans un autre document, par exemple par un agrégateur, qui peut reproduire l'arbre DOM mais pas chasser et interpréter les règles de style). En HTML5, on peut écrire : <table><style>td:first-child { text-align: right }</style>…</table>. Cela faisait des années que je me disais que cette possibilité manquait !

↑Entry #1929 [older| permalink|newer] / ↑Entrée #1929 [précédente| permalien|suivante] ↑

↓Entry #1928 [older| permalink|newer] / ↓Entrée #1928 [précédente| permalien|suivante] ↓

(mercredi)

Passage en HTML5

On va encore me reprocher de faire des annonces techniques qui n'ont aucune conséquence perceptible (mais bon, quand je parle d'autre chose, l'électro-encéphalogramme des commentaires enregistre un calme plat, alors que voulez-vous ?) : je viens de passer ce blog (et toutes les pages de ce site gérées par le même moteur) en HTML5[#]. C'est encore mal dégrossi, mais j'ai essayé de mettre les balises sémantiques comme article, header, footer, nav là où elles s'imposaient. Sur les navigateurs modernes, cela ne devrait faire aucune différence visible. Il y a peut-être un espoir que Google soit moins désorienté dans l'indexation, mais je n'y crois pas trop[#2].

En revanche, ce qui est bien est que je peux maintenant, enfin, librement inclure du SVG et du MathML dans mon blog. Et pour que mon annonce ne soit pas complètement creuse, donc, voici à gauche une étoile à sept branches en SVG (donc si vous ne voyez pas d'étoile à sept branches, c'est que votre navigateur n'est pas assez récent), et voici une formule en MathML permettant de montrer que l'étoile en question est constructible par origami :

e 2iπ 7 = 16 ( 1 +7 + 72 + 213 2 3 + 72 213 2 3 + 4972 + 2733 2 6 4972 2733 2 6 )

(La démonstration de la formule est laissée en exercice au lecteur. Je ne sais pas ce que j'ai trouvé le plus pénible dans l'histoire, d'ailleurs, entre la calculer et la taper en MathML.) Si vous voyez juste quelques nombres éparpillés mais pas de fraction ou de racine, même conclusion que pour le SVG : votre navigateur est trop vieux ou mauvais (et je note avec déception que, chez moi, aussi bien Chrome qu'Opera sont incapables d'afficher le MathML — ce qui est d'autant plus bizarre, s'agissant de Chrome, que WebKit est censé avoir au moins une implémentation partielle de MathML).

[#] Techniquement, et pour répondre à la première de mes questions techniques de l'autre jour, en polyglotte HTML5/XHTML5. J'ai validé un certain nombre de pages (certes pas toutes) contre le validateur expérimental, ce qui m'a d'ailleurs fait trouver un bug dedans (dû à la façon dont Java saucisonne l'Unicode en UTF-16 ; c'est assez ironique, parce que l'auteur de ce validateur écrit en faisant l'éloge de Java's notion of Unicode frozen as UTF-16 from to dawn of time until eternity).

[#2] En revanche, et cela devrait répondre du même coup à la deuxième de mes questions techniques de l'autre jour, si j'adopte, et je vais envisager de le faire, le microformat hAtom, j'ai bon espoir que cela permette de vraiment définir la limite des entrées et aux agrégateurs de fournir un contenu complet.

↑Entry #1928 [older| permalink|newer] / ↑Entrée #1928 [précédente| permalien|suivante] ↑

↓Entry #1926 [older| permalink|newer] / ↓Entrée #1926 [précédente| permalien|suivante] ↓

(lundi)

Quelques questions techniques sur le contenu Web

Maintenant que mon nouveau moteur de blog me permet de faire des changements techniques sur ce blog (c'est-à-dire, en fait, de faire joujou), encore faut-il savoir quels changements je voudrais/devrais/pourrais faire. Voici certaines des questions que je me pose, et sur lesquelles certains de mes lecteurs ont peut-être un avis.

Première question, comment servir du contenu XHTML ? Il faut savoir que le XHTML, qui, comme son nom le suggère, est la version XML du HTML, peut en gros être servi de deux façons différentes : comme du HTML (c'est-à-dire, sous le type MIME text/html) ou comme du XML (c'est-à-dire, sous le type MIME application/xhtml+xml). Dans le premier cas (ce que je fais actuellement), bien que le contenu soit réputé être du XML bien-formé, il n'est pas analysé comme tel, mais comme une « soupe de tags » (par exemple, si une balise ouverte n'était jamais fermée, cela ne provoquerait pas une erreur fatale), autrement dit, on ignore qu'il s'agit de XML. Certaines mesures de compatibilité doivent alors être prises pour permettre au contenu d'être analysé de la même façon par un parseur « soupe de tags » que par un parseur XML (par exemple, si on doit pour une raison ou une autre créer un élément div vide, par exemple pour lui donner des attributs de style, il faut l'écrire sous la forme <div style="clear: both"></div> et pas <div style="clear: both"/> comme le XML permettrait mais ce qui confuserait les parseurs « soupe de tags » qui y verraient une balise ouvrante jamais refermée). Actuellement, je fais toutes sortes d'efforts dans ce sens, ce qui a d'ailleurs pas mal compliqué la tâche de l'écriture du moteur de blog (parce que bien que ces mesures de compatibilité soient recommandées par le W3C, personne ne semble avoir écrit de code spécifique pour produire du XHTML en en tenant compte). À l'inverse, servir du XHTML comme du XML présente différents avantages, notamment le fait de pouvoir y mélanger différents autres standards XML, comme le SVG ou le MathML. Mais au moment où j'ai écrit le précédent moteur de ce blog, cette possibilité était mal supportée : certains navigateurs ne comprenaient pas du tout le XHTML présenté sous le type MIME application/xhtml+xml, et même ceux qui le supportaient ne le géraient pas toujours très bien, par exemple Firefox ne faisait pas de rendu incrémental (il devait attendre que toute la page soit chargée avant de commencer à afficher quoi que ce soit). Probablement, de ce point de vue-là, la situation s'est améliorée, et je suppose que le seul navigateur qui gère encore imparfaitement le XHTML servi comme XML est IE dans ses anciennes versions (et même si je ne veux pas envoyer paître les gens qui utilisent encore ça, je peux toujours servir les pages avec un type MIME différent pour ce navigateur).

Mais la question du type MIME n'est pas tout. Même si je sers le XHTML comme du XML, il se pose la question de savoir si je déclare une DTD, et si oui, laquelle. Actuellement, je déclare <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">, autrement dit je promets du XHTML 1.0 strict, je fais les efforts nécessaires pour que ç'en soit, et je valide effectivement mes pages contre cette DTD. Seulement, de nos jours où la multiplication des standards du Web a beaucoup compliqué le jeu de tags qui peuvent apparaître dans un document, les DTD sont un mécanisme de validation plus ou moins obsolète : on préfère des choses plus flexibles et basées sur du XML pur, comme RelaxNG ou XSD (je n'y connais rien, donc je ne sais pas ce qui exite vraiment dans l'un ou l'autre pour valider du XHTML moderne, mais je n'ai pas de doute qu'il y ait des possibilités dans cette direction). Notamment, il n'a été que très difficilement possible de produire une DTD pour la combinaison XHTML+MathML+SVG, et cela représentera probablement la culminaison des efforts dans cette direction. Seulement, ne pas déclarer de DOCTYPE du tout va faire (si le document est servi avec type text/html) que des navigateurs Web tomberont dans un mode spécial « quirks », où ils ne gèrent pas le CSS correctement. La meilleure solution est sans doute de commencer les documents par <!DOCTYPE html>, comme le préconise le HTML5.

Voilà justement un autre sujet, le HTML5 : comme le XHTML2 a été maintenant officiellement abandonné, on doit bien admettre que le HTML5 est le standard moderne. Mais il ne facilite pas forcément les questions précédentes. Notamment, il se pose toujours la question de savoir si, et comment, on peut fabriquer des documents qui soient du HTML5 valide à la fois quand ils sont interprétés en mode « soupe de tags » text/html (qui cette fois est une soupe de tags normalisée, donc plus si soupesque que ça) et en mode XML (c'est-à-dire XHTML). Or si je veux produire et manipuler mon document avec des outils XML (ce que je veux), et quand même le rendre lisible aussi largement que possible, c'est bien ce que je dois faire. Cette page de FAQ, au demeurant très intéressante, fait une réponse inquiétante : It is possible to construct documents that are valid HTML5 when labeled as text/html and valid XHTML5 when labeled as application/xhtml+xml. Doing so is much harder than it first appears and is most often useless, so you'd probably spend your time better by not trying.[#] Ceci contredit d'ailleurs un petit peu l'autre réponse suivante, qui est faite un peu plus loin : If you don't care about IE, you can use an XML serializer and serialize to XHTML5 (application/xhtml+xml). However, if you do care about IE, you can use an HTML5 serializer and serialize from an XML pipeline to text/html. In this case, you must avoid constructs that aren't supported in text/html (e.g. div as a child of p). Accessoirement, le fait que le standard HTML5 ne soit pas encore fini n'aide pas trop les choses !

Tiens, un petit détail s'agissant de HTML5 : je suis un grand fan de la distinction entre les balises abbr et acronym[#2], et ces andouilles ont décidé assez gratuitement de la supprimer (il ne subsiste que abbr). Pourquoi tant de haine ? Je pourrais remplacer acronym par abbr dans toutes mes pages, mais c'est quand même une perte d'information assez violente ; à la place, je suppose qu'il faut plutôt remplacer acronym par abbr class="acronym" et faire une stylesheet orale pour indiquer comment lire le texte.

[#] Je pense que si je ne mets aucune entité, j'arrive bien à produire des documents qui sont à la fois du HTML5 et du XHTML5 valides. En revanche, si je veux mettre des entités (juste par défi), ça devient vraiment technique. Voici donc un défi : produire un document qui soit (1) du HTML5 valide en mode « soupe de tags », (2) du XHTML5 valide selon la spécification HTML5, (3) du XML bien-formé et si il contient une référence à une DTD, alors valide selon cette DTD, et (4) pour garantir la non-trivialité, qu'il contienne à la fois une référence à une entité (disons &mdash;) et un élément SVG. Est-ce possible ?

[#2] Pour préciser, abbr sert à marquer une abréviation qui doit se lire lettre par lettre, par exemple HTML, noté <abbr>HTML</abbr> et prononcé [aʃteɛmɛl], et acronym sert à marquer un acronyme qui se lit comme un seul mot, par exemple MIME, noté <acronym>MIME</acronym> et prononcé [maɪm].

Deuxième question, comment faire un flux de syndication correct ? Je fais notamment référence à des commentaires sur l'entrée précédente. Actuellement, je propose un flux RSS 1.0, auquel je peux assez facilement ajouter un flux Atom s'il y a de la demande. Mais encore faut-il savoir quoi mettre dedans. Auparavant il n'y avait que le titre des entrées. Maintenant j'ai mis le début du texte proprement dit (160 caractères initialement, que je viens d'augmenter à 500 puisque 160 semble un peu court). Mais j'avoue que je ne sais pas très bien à quoi ce truc sert (en fait, je n'ai jamais utilisé d'agrégateur de flux, ce qui n'aide pas). Dans mon esprit, avoir le début du contenu devait servir à voir rapidement si on a lu l'article et, sinon, si on est éventuellement intéressé à la lire, un peu comme Google affiche en-dessous d'un lien dans les résultats de recherche : du coup, cela fait sens de ne mettre que le début (et de retirer le formatage). Apparemment, il y a des gens qui préfèrent lire complètement le contenu par un agrégateur. Je n'ai pas d'objection à ça (je vois mal quelle objection je pourrais avoir, à part que je suppose que ça casse toutes les stylesheets CSS), mais j'ai un petit problème avec l'usage du fichier RSS (ou Atom) lui-même : dans mon esprit, le fichier RSS a pour but d'être petit et téléchargeable rapidement et fréquemment, pour pouvoir facilement savoir s'il y a du nouveau contenu — si on veut télécharger le contenu proprement dit, il faut voir ailleurs. Autrement dit, je veux bien qu'un agrégateur permette de lire mon blog complètement, mais dans ce cas c'est le boulot de l'agrégateur de télécharger le fichier HTML proprement dit (s'il a calculé qu'il y avait du nouveau et qu'il y avait raison de télécharger), d'en extraire la bonne section, et de la présenter comme il veut la présenter, cela ne devrait pas se limiter à la lecture du RSS. Donc il faut m'expliquer comment obtenir ça, parce qu'en l'état je suis un peu perplexe (on me souffle qu'Atom doit permettre de fournir un lien vers le contenu proprement dit, mais je ne comprends pas vraiment comment). Ajout () : Quelqu'un me dit que ce n'est pas possible pour un flux Atom de référencer du contenu externe, mais quelqu'un d'autre suggère, et cette page semble confirmer, que si, avec l'attribut src sur la balise atom:content ; mais les agrégateurs Atom sont-ils assez malins pour utiliser correctement une ressource externe qui soit un div dans un document HTML ?, voilà ce que je voudrais savoir.

Cette question rejoint un peu la précédente : si je passe à HTML5, alors on me suggère que je peux mettre les entrées dans des balises article, ce qui simplifierait le boulot d'outils cherchant à analyser le blog automatiquement. Je suis tout à fait favorable à ça.

Ajout () : voir l'entrée du surlendemain.

Troisième question, comment gérer les commentaires ? Actuellement c'est un script Perl maison qui s'en occupe, et qui tourne sous la forme d'un CGI sur mon serveur Web. Je n'y ai pas touché du tout : ce moteur de commentaires est à peu près complètement séparé du moteur de blog (et il permet d'ailleurs de commenter n'importe quelle page Web, c'est voulu, même si j'aurais tendance à être réticent à modérer favorablement des commentaires sur des pages ne me concernant pas du tout), les seules connexions étant que je fournis au moteur de commentaires des alias pour les entrées de mon blog (pour afficher le titre de l'entrée commentée) et qu'à l'inverse j'ai un petit bout de JavaScript qui affiche le nombre de commentaires et la date du dernier à la fin de chaque entrée. Cette séparation a l'avantage que le système de commentaires ne m'a pas handicapé pour le changement du moteur de blog ; elle a l'inconvénient que quand on me demande de produire un flux RSS des commentaires ou, pire, de reproduire l'entrée elle-même en tête de chaque page de commentaires, ce n'est pas facile.

Je voudrais donc probablement, à terme, refaire ce moteur de commentaires, ce qui est d'ailleurs sans doute plus facile. Et probablement l'intégrer de façon plus proche avec le moteur de blog. Pour ça, j'ai déjà choisi mon arme : Apache Tomcat, parce que pour s'intégrer avec un outil en Java ce sera le mieux (et parce que je ne veux vraiment pas apprendre PHP ; quant à Perl, il m'a profondément déçu par son absence de bibliothèque convenable pour gérer le XML : XML::LibXML est complètement cassé dès qu'on commence à jouer avec les namespaces, or on doit le faire si on prétend mélanger XHTML avec n'importe quoi).

Mais une question d'un peu plus haut niveau consiste à se demander quel mécanisme d'entrée fournir pour les commentaires. Actuellement, on tape du pur texte, seule est fournie la possibilité d'entrer un lien en tapant <URL: schéma://monurl >, ce qui est malcommode et d'ailleurs les gens ne lisent pas les instructions et se trompent plus souvent qu'ils ne réussissent. Je voudrais faire plus agréable que ça, mais c'est extrêmement délicat : permettre de taper du HTML demande par exemple soit de trouver un parseur « soupe de tags » (capable de transformer la soupe en un vrai arbre DOM) soit d'exiger que le commentateur produise du XHTML bien-formé, ce qui est bourré d'écueils (les gens n'ont pas envie de refermer leurs balises, je pense, il n'y a que les maniaques comme moi pour le faire). Sans doute les navigateurs modernes ont-ils tout ce qu'il faut (un éditeur de HTML inclus qui produise automatiquement du XHTML bien-formé), ce qui fait que je pourrais fournir le choix entre taper du texte pur, taper du XHTML à la main ou, si on a un navigateur convenable, taper du XHTML à travers un widget fourni par le navigateur. Reste qu'il faudra encore, pour des raisons de sécurité, valider ce XHTML derrière, choisir un modèle de contenu autorisé, etc. : tout ça est un peu fastidieux.

Par ailleurs, j'ai un ami qui réclame que les commentaires soient accessibles par une interface NNTP, pour pouvoir les agréger avec ses autres groupes de discussion. La demande est raisonnable sur le principe, même si je n'aime vraiment pas le protocole NNTP, et que la conversion HTML↔texte est au mieux déplaisante (sans parler de la quasi-impossibilité de faire un round-trip correct, quelque chose qui figure d'ailleurs dans ma TORANT-list). Si au moins il existait des standards d'échange ou téléchargement des messages sur les webforums (un standard basé sur JSON, typiquement), je pourrais utiliser ça et lui dire que dès lors que les messages sont récupérables sous un format clair c'est à lui de se débrouillre pour interface avec NNTP… mais je ne crois pas qu'un tel standard existe. (Ce qui est hautement regrettable, parce qu'il est vraiment pénible de suivre des webforums qui ont tous leur style différent, sans pouvoir les agréger sous une interface unique dans un newsreader.) Au moins en lecture, un flux RSS ou Atom serait sans doute désirable.

↑Entry #1926 [older| permalink|newer] / ↑Entrée #1926 [précédente| permalien|suivante] ↑

↓Entry #1925 [older| permalink|newer] / ↓Entrée #1925 [précédente| permalien|suivante] ↓

(dimanche)

Il est arrivé le moteur nouveau !

Sonnez hautbois, résonnez musettes ! Il est arrivé le moteur de blog nouveau ! Chantons tous son avènement !

Ça fait un an et demi que j'y pensais, que je bassinais mes lecteurs régulièrement avec ça, que j'y travaillais très très épisodiquement (après avoir mis du temps à faire les choix techniques), mais voilà, enfin, les choses sont en place et j'ai une première version un peu coupante sur les bords mais réellement fonctionnelle : ce blog[#] n'est plus généré par un programme en C de 3000 lignes mal écrit, buggué et impossible à maintenir, mais par… un programme en Java de 3000 lignes que j'espère légèrement moins mal écrit, légèrement moins buggué et légèrement moins impossible à maintenir.

Vous ne voyez pas la différence ? C'est normal. C'est voulu, même : à part de timides petits changements dans l'en-tête et le pied-de-page des différentes parties de ce blog, j'ai visé à tout garder identique. Le principal changement qui devrait être visible pour ceux qui utilisent le flux RSS, c'est le truc qu'on me réclamait régulièrement, à savoir une date et heure sur les entrées, et le (début du) contenu des entrées elles-mêmes dans le flux (chose qu'il aurait été quasiment impossible de faire avec l'ancien moteur sans s'arracher les cheveux). Sinon, la plupart des changements ont lieu de mon côté : mon blog n'est plus tapé comme un fichier unique de 6.6Mo (and counting) mais comme un petit fichier par mois (ça va rendre git plus heureux, même si en contrepartie c'est moins commode pour rechercher dedans), et quand je recompile il y a plein de magie noire mêlant du PostgreSQL, du Perl et du Java pour ne regénérer que les bouts vraiment modifiés. J'ai aussi dû me battre avec plusieurs misfeatures de XML ou des parseurs XML[#2].

Ceci étant, le but n'était pas tellement de changer des choses, même pour moi, mais de me donner les moyens de pouvoir les changer : autrement dit, de quitter une situation où je ne peux rien faire évoluer parce que le programme est tellement horrible que je refuse d'y toucher. Et pour ça, je crois avoir effectivement gagné.

[#] Ce blog, et avec lui une bonne partie des pages Web de ce site, celles qui ont vaguement le même look.

[#2] En voici une qui m'a causé pas mal d'arrachage de cheveux : si vous considérez le fichier XML suivant : <?xml version="1.0"?> <pouet>&pouet;</pouet>, il n'est pas bien-formé, parce que l'entité &pouet; est référencée sans être définie ; en revanche, si je rajoute n'importe quelle référence à un document externe, disons <?xml version="1.0"?> <!DOCTYPE pouet [<!ENTITY % nothing SYSTEM "/dev/null"> %nothing;]> <pouet>&pouet;</pouet>, alors magiquement le document devient bien-formé. La logique, assez compréhensible, est que le caractère bien-formé ou non d'un document XML doit pouvoir se décider sans consulter la moindre ressource externe, donc dès qu'on ne peut plus être sûr sans en consulter que l'entité n'a pas été définie, ce ne peut plus être une contrainte de bien-formitude bonne forme. (C'est cependant toujours une contrainte de validité.) Mais ce qui m'agace c'est que, du coup, les parseurs XML ne signalent pas d'erreur et qu'il n'y a apparemment pas de moyen de les forcer à en produire une (j'ai vraiment envie que Xerces me signale si j'utilise une entité non définie parce que j'ai fait une faute de frappe, et pas qu'il la remplace par la chaîne vide !). La seule façon de faire semble être de demander au parseur de valider, et d'ignorer la floppée d'erreurs qu'il va pondre sauf celle-ci : c'est vraiment absurde. (Et je ne vous parle pas du fait que Xerces a douze interfaces différentes avec douze façons différentes d'enregistrer un gestionnaire d'erreurs, et que trouver comment lui faire avaler un org.apache.xerces.xni.parser.XMLErrorHandler et pas un org.xml.sax.ErrorHandler parce qu'on veut éviter d'avoir à parser le message d'erreur, c'est pas évident.)

↑Entry #1925 [older| permalink|newer] / ↑Entrée #1925 [précédente| permalien|suivante] ↑

↓Entry #1921 [older| permalink|newer] / ↓Entrée #1921 [précédente| permalien|suivante] ↓

(dimanche)

OpenData, Web sémantique et pâquerettes

C'est épatant le pouvoir qu'a le fait de donner un nom à quelque chose. Pendant longtemps — presque depuis que j'ai accès au Web, en fait — je me suis acharné à expliquer la thèse que c'est bien d'avoir des informations sur Internet, mais c'est encore mieux si ces informations sont sous un format téléchargeable en bloc, et utilisable par un ordinateur. Les gens ne comprenaient pas du tout ce que je racontais (mais si ces données sont en ligne, c'est bien qu'elles sont utilisables par un ordinateur ?). Ce n'est pas facile d'expliquer, par exemple, pourquoi il ne suffit pas qu'un institut de statistiques ou de sondages fournisse des PDF joliment formatés synthétisant ses enquêtes mais devrait aussi fournir accès aux données brutes ; pourquoi l'éditeur d'un dictionnaire qui fournirait un accès en ligne à celui-ci ou un institut de cartographie qui permettrait de consulter ses cartes par un site Web ne sont pas en train d'ouvrir leurs données mais au contraire de contrôler leur accès. Ce qu'on voudrait vraiment, c'est pouvoir télécharger la totalité et le traiter par soi-même. (Et s'agissant de l'IGN, qui a plus la rentabilité que le service public à l'esprit, on peut toujours courir pour qu'ils fournissent de vraies cartes de France sous un format informatiquement utilisable comme les Pays-Bas ont fait en versant des cartes complètes du pays à OpenStreetMap. Du coup on est obligé de refaire bénévolement, laborieusement, et très mal, un boulot qui a déjà été fait sur des deniers publics.) Tout ça passe pour des râleries de geek et Madame Michu demande en quoi cette problématique peut l'intéresser.

La situation a un peu évolué, notamment par la popularisation (relative, certes, mais suffisante pour pouvoir au moins conseiller à Madame Michu de le rechercher dans Wikipédia ou dans Google) d'un mot : OpenData. La situation a évolué et les pouvoirs publics commencent très lentement à comprendre que ça peut être intéressant pour l'intérêt général de fournir ces bonbons aux geeks : je le signalais au sujet de Paris, et il semble qu'au niveau national le gouvernement y pense, en se donnant notamment pour modèle ce qui se fait en Grande-Bretagne. Il faut aussi reconnaître qu'à un niveau moins systématique, des instituts comme l'INSEE ou pour quelque chose de plus pointu la BCE, ont tendance à fournir beaucoup de chiffres sous des formats au moins un peu utilisables (bon, en général de simples tableaux de chiffres publiés sous formes de tableaux Excel, n'allons pas demander des données hiérarchisées XML, mais c'est déjà bien).

Je mélange à dessein plusieurs choses, pas forcément applicables de la même manière, concernant l'utilisabilité des données : des choses qui pour moi relèvent de la même optique générale, et dont l'OpenData n'est qu'une facette :

  • que les données soient disponibles en bloc, en téléchargement, et pas à travers le filtre d'un site Web qu'on peut interroger requête par requête,
  • que ces données soient placées sous une licence ouverte (et idéalement une absence complète de propriété intellectuelle, s'il s'agit de données factuelles sur le réel ou de reproductions d'œuvres du domaine public),
  • que les données soient disponibles sous un format standard et ouvert, ce qui permet de les récupérer et de les traiter de façon automatisée (OpenData),
  • que la sémantique sous-jacente aux données soit elle-même décrite de façon utilisable (et standardisée, pour une utilisation uniforme à travers plusieurs jeux de données) (Web sémantique).

Les premiers points devraient être assez clairs. Le dernier ne l'est pas forcément, et n'a pas toujours de sens, mais je peux donner un contre-exemple pour l'illustrer : Wikipédia passe clairement les trois premières conditions : on peut télécharger l'intégralité du contenu de Wikipédia (même si des problèmes purement techniques — ils n'ont pas les moyens de maintenir ça correctement — font que les dumps sont atrocement périmés et le dump le plus intégral, celui qui fait des centaines de gigas comprimés avec l'historique complet, a l'air de ne jamais être disponible), la licence est ouverte, le format de markup est connu et documenté (et il existe plusieurs moteurs pour le traiter), en revanche, ce qui manque encore, même si des efforts sont faits dans ce sens, c'est l'aspect Web sémantique ; pour prendre un exemple plus précis, il existe des zillions de personnes recensées sur Wikipédia, mais si on veut en extraire automatiquement des informatiques basiques comme le nom, la date et le lieu de naissance, la date et le lieu de mort (le cas échéant), la nationalité, la profession ou raison principale de célébrité, etc., ce n'est pas facile : l'information est là, mais elle est écrite dans des phrases en anglais qui ne sont pas du tout faciles à analyser informatiquement. Le but du Web sémantique, ce serait de mettre en place des formats qui permettent vraiment la collecte informatisée et automatisée d'informations sur le Web et pas seulement de bouts de texte.

Je ne sais pas si ça se fera. La technologie qui était censée rendre le Web vraiment sémantique (et créer le Web 3.0), c'était RDF, je ne sais pas si elle n'est pas un peu morte à ce stade-là. Il y a des initiatives, éventuellement plus modestes comme les microformats, qui semblent cependant progresser, donc tout espoir n'est pas perdu. Je pense aussi que l'essor des bases de données NoSQL, va (certes indirectement) dans le même sens. S'agissant spécifiquement de Wikipédia et plus généralement des choses sous MediaWiki, il y a Semantic MediaWiki qui est destiné au moins à permettre l'ajout d'informations sémantiques dans le Wiki.

Pour répondre à la question de Madame Michu, s'agissant spécifiquement du Web sémantique : j'aimerais pouvoir demander à un moteur de recherche est-ce qu'il y a dans le quartier où je suis un magasin de Foobars ouvert le dimanche ? ou bien où pourrais-je acheter en ligne tel produit précis dont je connais la référence exacte (par exemple le code barre EAN-13) à un prix inférieur à 42¤ ? ou encore comment s'appelle déjà cet acteur américain d'origine russe né dans les années 1910 et dont le nom commence par un ‘D’ ? — actuellement les moteurs de recherche sont mauvais pour ce genre de choses, parce qu'ils ne peuvent que chercher du texte dans une page, malgré beaucoup d'astuces de leur part pour trouver les résultats les plus pertinents. Si les pages Web, par exemple, de tous les articles vendus en ligne et de toutes les boutiques, comportaient des informations de base (s'agissant d'un produit vendu en ligne, le code EAN-13, le prix, les délais de livraison ou des choses comme ça ; s'agissant d'une boutique, les coordonnées géographiques, les horaires d'ouverture, la catégorie générale, éventuellement le catalogue ; etc.) de façon parsable informatiquement, cela permettrait ce genre de recherches. J'ai l'espoir qu'un jour Google dira si vous mettez sur votre site Web vos coordonnées géographiques et vos horaires d'ouverture sous tel format, cela facilitera le référencement, ce qui pousserait certainement les gens à le faire vu l'importance du référencement par Google pour n'importe quel commerçant. Déjà un standard qui soit vraiment pris en compte pour publier un permalien pour une page Web un peu dynamique (par exemple celle décrivant un article sur un site de commerce en ligne) serait une bénédiction.

Mais l'éléphant au milieu de la pièce, évidemment, ce sont les réseaux sociaux. Parce que s'il y a une donnée qui vaut des milliards, qui existe par essence même sous forme informatisée, ce sont toutes les informations que « nous » avons mises dans Facebook : sur nos noms, nos dates de naissances, nos centres d'intérêt, nos liens d'amitié (et même les groupements entre ces liens d'amitiés), et quantité d'autres choses. Peut-être que « nous » alons nous amuser à retaper toute cette information dans Google Plus ; peut-être pas. Ce que je voudrais vraiment, c'est pouvoir télécharger les informations que j'ai moi-même entrées dans Facebook, sous un format ouvert (malheureusement inexistant), pour pouvoir les mettre sur ma page Web pour celles que je décide de rendre complètement publiques, ou pour pouvoir les communiquer à d'autres éventuels réseaux sociaux si d'autres apparaissent (et ne pas avoir à refaire tout le boulot de saisie). Je préférerais mille fois que le Web social fût sémantique et décentralisé, que chacun mette sur sa propre page Web des fichiers décrivant ce qu'il veut publier sur lui-même, et qu'en suite ce soient des moteurs de recherche qui interprètent ces données et les mettent en forme. Il y a eu une tentative dans ce sens, c'est le format FOAF : il est apparu en 2000 (oui, pour les oublieux, les réseaux sociaux sont beaucoup plus anciens que Facebook) et n'a malheureusement eu aucun succès (j'avais publié une description RDF de moi-même en 2003), mais ça ne va vraiment pas loin, et il n'y a rien à en faire parce que personne n'utilise ça. Même Diaspora, le truc ouvert censé faire concurrence à Facebook (entreprise indispensable mais tellement désespérée que Facebook lui donne de l'argent par charité ou par ironie je ne sais pas) n'utilise pas vraiment FOAF, je crois.

↑Entry #1921 [older| permalink|newer] / ↑Entrée #1921 [précédente| permalien|suivante] ↑

↓Entry #1902 [older| permalink|newer] / ↓Entrée #1902 [précédente| permalien|suivante] ↓

(mardi)

Note technique sur le flux RSS de ce blog

Suite à la demande d'un lecteur, j'ai fait un changement dans le flux RSS de ce blog, de sorte que les liens sont maintenant les liens permanents des entrées plutôt que les liens vers la page d'accueil (qui contient les 20 dernières entrées). Ça semble plus logique. J'avais dû faire le choix de faire des liens vers la page des 20 dernières entrées en me disant que les agrégateurs RSS n'avaient pas de mémoire, ou parce que je ne voulais pas que des lecteurs risquassent de lire (ou bookmarker) une page mensuelle et de rester coincés à la fin du mois, mais c'était assez stupide. Ceci étant, j'espère ne pas avoir tout cassé : RSS est un format terriblement mal foutu et mal spécifié, dont il existe trente-douze versions insidieusement incompatibles les unes avec les autres (certaines basées sur RDF, d'autres pas) et que chaque agrégateur doit interpréter avec ses propres idiosyncrasies. On marche donc sur des œufs quand on y touche.

Ah, et il est inutile de me rappeler que ce serait utile de donner le début des entrées dans le flux RSS, j'en suis conscient, c'est prévu pour Un Jour® (et plus précisément, pour le cinquième jour de la semaine sans ‘i’ suivant les calendes grecques du mois de la Saint-Glinglin prochaine).

Ce que je pourrais faire, par ailleurs, sans doute sans trop de mal, c'est faire un peu de magie en JavaScript qui redirige une URL comme weblog/#d.2011-07-12.1902 vers weblog/2011-07.html#d.2011-07-12.1902 si elle est partie de la page. Comme ça si d'aventure de telles adresses ont été publiées, elles seront réparées.

↑Entry #1902 [older| permalink|newer] / ↑Entrée #1902 [précédente| permalien|suivante] ↑

↓Entry #1894 [older| permalink|newer] / ↓Entrée #1894 [précédente| permalien|suivante] ↓

(dimanche)

Les technologies qui donnent envie de s'en servir

Le principe de l'utilisation d'un outil, et en particulier d'un outil technologique, normalement, c'est que le besoin précède, et détermine, le choix de l'outil. En pratique, je pense que c'est loin d'être toujours le cas, et il y a des marteaux qui, quand vous les avez en main, vous donnent envie de chercher partout les clous. Ce n'est pas toujours une bonne chose (quand on utilise un outil inapproprié à une tâche juste pour le plaisir de se servir ce cet outil), mais ça peut l'être (quand on fait quelque chose de vraiment utile parce qu'on avait le marteau qui démangeait la main).

Je ne sais pas si c'est le cas de tous les geeks, mais l'informatique me fait souvent cet effet. Souvent, quand je lis la description des zillions de programmes, bibliothèques, ou autres formes de technologies qui sont à la portée de mon ordinateur, cela me donne envie d'en faire quelque chose — n'importe quoi, juste pour m'en servir — dans le même genre qu'un enfant à qui on montre un joujou tout neuf (« tout neuf » parce que c'est surtout quand je découvre de nouvelles features que je ressens ça). C'est particulièrement vrai, en ce qui me concerne, pour les technologies du Web : le Web 2.0 est plein de strass et paillettes, moins visuelles que celles de celui de 1996, mais beaucoup plus attractives pour les geeks. Quand je lis les nouvelles features de telle ou telle version de JavaScript, par exemple, ou tout ce qu'on peut faire avec HMTML5, SVG, CSS et compagnie, ça donne envie de jouer avec… Et même, j'avoue ça comme une perversion dont j'ai un peu honte, Java me donne envie de le tripoter dans tous les sens.

Mais pour faire quoi ? Le problème, c'est que dès qu'on regarde de plus près ces bijoux en caoutchouc qui brillent comme des vrais, on se rend compte qu'ils sont, justement, en caoutchouc, et que tout ce qu'il y a autour est beaucoup moins reluisant : tel standard prévoit telle feature extrêmement amusante, mais elle n'est implémentée nulle part, ou de façon incohérente avec le standard, ou il manque un autre truc qui rendrait la feature utilisable, ou le fait de s'en servir casse autre chose (du genre, les pages Web dynamiques, c'est joli, mais ça met en défaut plein de mécanismes d'historique ou de reflow des navigateurs Web), ou plein d'autres briques sont tout simplement mal foutues (en HTML, les événements, ah, comment ont-ils réussi quelque chose d'aussi cassé ?), ou encore il faut être à deux jouer avec tel nouveau gadget (IPv6, ou tel ou tel nouveau caractère Unicode scintillant 😻). Ou on rencontre des problèmes qu'on a soi-même mis en place (l'architecture idiote et obsolète que j'utilise pour ce blog et que je n'en finis pas de ne pas me décider à réécrire ne me permet pas vraiment de profiter de tous les gadgets que je voudrais, que ce soit pour jouer avec du HTML plus moderne ou avec des pages dynamiques). Quand par miracle les choses marchent comme spécifié, on rencontre des tonnes de problèmes d'efficacité. Il y a des bibliothèques entières écrites pour contourner les problèmes des briques d'en-dessous, comme jQuery ou Node.js. Peut-être même y a-t-il des bibliothèques pour contourner les problèmes de ces bibliothèques : tout d'un coup ça ne sent plus bon le bonbon frais, ça ne donne juste plus envie de mettre les mains dans le cambouis.

Du coup, je ne code rien. Au moins, les maths, ça scintille moins, mais la beauté du temple grec ne disparaît pas quand on regarde de plus près. (⇜Hum, en fait, je ne crois pas du tout ce que je dis, là. Il y a plein de cambouis dans les maths aussi.)

↑Entry #1894 [older| permalink|newer] / ↑Entrée #1894 [précédente| permalien|suivante] ↑

↓Entry #1757 [older| permalink|newer] / ↓Entrée #1757 [précédente| permalien|suivante] ↓

(mardi)

Le HTTPS, c'est de la merde en boîte

Le HTTPS, c'est la version « sécurisée » (c'est-à-dire, chiffrée et signée/authentifiée) du protocole HTTP utilisé de façon générale pour véhiculer le Web. Pour Madame Michu, le HTTPS se manifeste par un petit cadenas fermé affiché quelque part par le navigateur et probablement par la sensation confortable que les données qu'on échange sont protégées (donc que le méchant hacker russe ne peut pas lire votre numéro de carte de crédit en passant). L'idée est bonne. La crypto est raisonnable. Malheureusement, l'implémentation — la péri-crypto, pourrait-on dire, ou, en fait, la politique — est épouvantable, à tel point que ce truc est tout simplement à jeter à la poubelle. Le problème est simple : tout le HTTPS du Web est basé sur une chaîne de confiance, dont la source (les autorités racines) ne fait absolument pas son travail, voire, se comporte comme des escrocs méritent exactement zéro confiance, ce qui, inévitablement, ramène à zéro la confiance qu'on peut avoir en tout le reste de l'édifice construit sur ces fondations pourries.

Le principe, c'est que pour établir une connexion sécurisée (chiffrée), les deux partenaires (le client, donc le navigateur Web qui veut accéder au site sécurisé, et le serveur de ce site sécurisé) s'identifient l'un à l'autre (en pratique, en fait, c'est généralement seulement le serveur qui s'identifie auprès du client) en échangeant des certificats qui permettent que chacun soit sûr de parler à la bonne personne et d'en connaître la bonne clé publique de chiffrement, pour pouvoir ensuite se mettre d'accord sur une clé. Le serveur, pour s'authentifier auprès du client, va fournir une chaîne de signatures : sa clé publique, avec son nom officiel et le nom du site qu'il opère, sont signés par une autorité avec une clé elle-même signée par une autre, et ainsi de suite jusqu'à une autorité racine que le navigateur connaît nativement. Dans la pratique, ces autorités intermédiaires sont du bidon, on peut faire comme si l'identité du site était signée directement par l'autorité racine. Tout ceci prend place dans le cadre défini par une moussaka géante appelée X.509.

Si les autorités racines faisaient un boulot un tant soit peu sérieux, et si Madame Michu comprenait ce qui se passe, ce système ne serait peut-être pas si mauvais. Le but est de se prémunir contre deux sortes de risques : le premier est l'attaque par un espion passif (eavesdropper) qui ne peut qu'espionner les communications sans les altérer : il s'agit du risque le plus vraisemblable, et pour ça on connaît en fait une méthode bien plus simple permettant d'assurer une communication privée résistante aux espion passifs sans même à avoir à authentifier les participants, c'est le protocole d'échange de clés de Diffie-Hellman ; l'autre risque, moins vraisemblable sur Internet mais aussi plus difficile à éviter et où il faut vraiment établir l'identité des participants, c'est l'attaque de l'homme au milieu (man-in-the-middle), c'est-à-dire un espion qui peut intercepter complètement la communication entre A et B et se faire passer pour A auprès de B et pour B auprès de A en recopiant les données mais en changeant les clés. J'estime que les attaques man-in-the-middle sont assez peu probables sur Internet, mais si on veut s'en protéger, il faut effectivement utiliser un système qui permet d'identifier l'interlocuteur et pas seulement de sécuriser un canal avec lui. Donc le principe général de HTTPS et de ses chaînes de signatures n'est pas absurde.

Les problèmes sont multiples. Un problème zéro est que Madame Michu n'a rien à faire de comprendre ces histoires de chiffrement et de signature, elle veut savoir si elle peut avoir confiance dans le site Web et dans la connexion : l'architecture garantit peut-être que la connexion soit sécurisée, éventuellement que le site Web soit bien qui il indique qu'il est, mais certainement pas qu'il est honnête ni même qu'il n'est pas quelqu'un d'autre avec un nom très subtilement semblable et avec lequel Madame Michu va probablement confondre. Dans cette optique, le problème principal est que les autorités racines ne font pas du tout ce qu'on attend d'elles. On attend d'elles (si on veut que le système fonctionne un peu) qu'elles vérifient soigneusement l'identité des personnes à qui elles délivrent des certificats, qu'elles vérifient que le nom ne prête pas à confusion, qu'il s'agit d'une compagnie vraiment implantée et pas d'un petit malin qui a fondée une association Société Généralle sans aucun rapport avec la Société Générale, etc. Ce que font en réalité les autorités racines, c'est recevoir de l'argent (parfois beaucoup) et mettre leur tampon sur les certificats sans regarder quoi que ce soit. Dès lors, le système est une pure escroquerie. Même si toutes les autorités racines ne sont pas des escrocs, il suffit qu'une seule le soit pour que tout le système soit pourri — or il y en a toute une ribambelle et on ne sait pas très bien, d'ailleurs, par quel processus elles sont choisies (cela dépend du navigateur : Firefox est un peu transparent sur la question, mais les autres navigateurs carrément moins, et certains aussi se contenent de recevoir de l'argent (toujours beaucoup) et mettre le certificat demandé parmiles certificats racines).

À ce compte-là — tant qu'à avoir un système qui ne vérifie rien, finalement, que le nom de domaine — on aurait pu faire plus simple et moins cher : avoir un système de signature qui suive le mécanisme hiérarchique du DNS : en achetant le domaine madore.org je recevrais automatiquement un certificat prouvant que je suis bien propriétaire du domaine en question, et signé par la clé du domaine org. C'est effectivement ce qui va se faire avec le DNS sécurisé, mais pour autant que je comprenne il n'est malheureusement pas prévu que ce système hiérarchique soit directement utilisable dans les navigateurs Web (probablement pour ne pas tuer la poule aux œufs d'or des escrocs qui détiennent des certificats racines).

Idéalement, le système que je voudrais avoir, moi (mais que je conviendrait probablement pas trop à Madame Michu), quand je me connecterais à un site sécurisé, il me dirait : bonjour, ceci est la première fois que vous vous connectez à un site du domaine exemple.tld : le certificat qui l'authentifie a été signé par <telle autorité> et <telle autorité> et <telle autorité> : voulez-vous continuer à vous connecter ? avec des options diverses permettant, par exemple, de marquer qu'on veut continuer la connexion mais sans faire confiance à la sécurité de la connexion (rappeler si besoin est que le canal n'est pas forcément sûr), ou je ne sais quoi du genre. (À tout le moins, même en l'absence de signature identifiant l'interlocuteur, on aurait une protection contre les espions passifs en utilisant un échange de type Diffie-Hellman, ce qui n'est déjà pas mal.) Quand le certificat expirerait (arriverait au bout de sa date de validité), j'aurais un message semblable me signalant de plus que le nouveau certificat utilise la même clé que précédemment ou est signé avec celle-ci (ce qui augmente ma confiance). Et surtout, si jamais le certificat change sans raison, même si le nouveau est signé par des autorités censément de confiance, j'aurais droit à un message expliquant la situation. C'est, grosso modo, les signatures en moins, comment fonctionne SSH.

Mais le HTTPS, en tout cas tel qu'il est implémenté dans les navigateurs, ne fonctionne pas du tout comme ceci. D'abord, ce système irrémédiablement mal foutu ne permet à un certificat d'être signé que par une autorité : on établit une chaîne de confiance et pas un réseau de confiance : pas moyen, donc, pour un site Web de faire signer son certificat par plusieurs autorités (ou par sa précédente clé en cas de changement) pour combiner un peu la confiance très limitée que j'apporte en chacune. Ensuite, on ne peut faire confiance que totalement ou pas du tout : si je donne ma confiance à une autorité, je ne serai pas prévenu d'un changement apporté au certificat d'un site que je consulte ; pas moyen, non plus, d'avoir un message particulier à la première connexion sauf à refuser complètement la confiance en l'autorité racine. Tout ceci est totalement nul.

Sur un de mes ordinateurs, j'ai fait l'expérience de retirer la confiance accordée par mon Firefox à tous les certificats des autorités racines. D'abord, ce n'est pas du tout facile à faire, même s'il y a peut-être eu des progrès depuis dans Firefox (dans EditPreferencesAdvancedEncryptionCertificatsView CertificatesAuthorities on peut régler des choses) ; j'ai gribouillé les notes suivantes, qui donnent une idée de combien c'est mal foutu :

### TO LIST DEFAULT ROOT CERTIFICATES:
cd "`mktemp -d`"
# Create a new certificate database:
certutil -N -d .
# (type return twice for empty password)
# Add roots from libnssckbi:
modutil -add roots -libfile /usr/lib/nss/libnssckbi.so -dbdir .
# replace /usr/lib/nss/libnssckbi.so by wherever libnssckbi is found on your system
# (confirm: this is a temporary directory so there is no danger)
# Check that the Builtin Object Token was added:
modutil -list -dbdir .
# Now you can list the contents of the Builtin Object Token:
certutil -L -d . -h "Builtin Object Token"

### TO UNTRUST ROOT CERTIFICATES:
# (Make sure Firefox is not running!)
cd .mozilla/firefox/$salt
# (replace $salt by wherever your profile is stored)
modutil -add roots -libfile /usr/lib/nss/libnssckbi.so -dbdir .
# (same comment as above for libnssckbi.so,
# but this time really make sure the browser is not running!).
TEMPFILE="`mktemp`"
certutil -L -d . -h "Builtin Object Token" | perl -ne 'next unless /^(.*?)\s+([A-Za-z]*\,[A-Za-z]*\,[A-Za-z]*)\s*$/; $n=$1; $v=$2; $v=~s/C/c/g; $v=~s/G//g; $v=~s/T/c/g; print "certutil -M -d . -n \"$n\" -t \"$v\"\n";' > "$TEMPFILE"
# Review or edit $TEMPFILE and possibly run it with:
. "$TEMPFILE"

Ensuite, évidemment, se connecter la première fois à n'importe quel site HTTPS conduit à un avertissement : ça c'est l'effet désiré, et je ne m'en plains pas. Je me plains, en revanche, du fait que cet avertissement est peu utile, et notamment il n'est pas du tout évident d'arriver à voir si la signature par l'autorité racine est valable ou non (je ne veux pas faire confiance automatiquement à une autorité racine, mais je veux quand même savoir si elle a ou non signé le certificat). Mais surtout, il y a pire : autant les choses se passent raisonnablement bien quand on essaie explicitement de se connecter à un site HTTPS (en entrant une URL en https:// ou en suivant un lien), autant quand c'est un script ou une image ou quelque chose comme ça que le navigateur essaie de charger depuis un domaine dont on n'a jamais accepté le certificat, la connexion échoue purement et simplement (ou alors avec une fenêtre d'avertissement qui ne propose qu'une seule option : faire échouer l'opération). Voilà qui est profondément crétin ! Même si le navigateur ne fait qu'aller chercher une erreur ou un bout de JavaScript à une adresse en https://, je veux voir la même page me proposant de voir le certificat et de choisir si je veux l'accepter ou non ! (Je me suis rendu compte du problème en essayant d'accéder à un site qui utilisait un CAPTCHA en https://, probablement ReCAPTCHA, et qui n'apparaissait tout simplement pas. Du coup, je ne pouvais rien faire et j'ai mis un temps fou à comprendre ce qui se passait.) Il y a aussi des problèmes bizarres avec les extensions Firefox, qui n'ont pas l'air de se mettre à jour correctement (sans pour autant signaler à l'utilisateur qu'il est face à tel certificat signé de telle et telle manière) si on détruit la confiance dans les certificats racines. Bref, cela conduit à plein de problèmes, donc on est quasiment obligé d'accepter ces autorités racines…

…Sans pour autant que ça aide Madame Michu, qui risque tout à fait de tomber sur le domaine amazoon.com présentant un certificat en bonne et due forme signé par n'importe quelle autorité racine (donc montrant à Madame Michu le petit cadenas fermé qui lui inspire confiance) et qui ressemble comme deux gouttes d'eau à amazon.com mais qui appartient à une compagnie moins scrupuleuse. Madame Michu ne peut rien dire : le certificat montrait bien qu'elle était chez la compagnie Amazoon avec deux ‘o’, et l'autorité racine ne s'est jamais engagée à vérifier qu'il n'y avait pas ce genre de confusion. Tout ce système est à foutre à la poubelle.

Mise à jour : une entrée plus tardive sur ce même sujet (ou proche).

↑Entry #1757 [older| permalink|newer] / ↑Entrée #1757 [précédente| permalien|suivante] ↑

↓Entry #1748 [older| permalink|newer] / ↓Entrée #1748 [précédente| permalien|suivante] ↓

(lundi)

Finalement, je programme en Java

Pour ceux qui ont suivi les premiers volets (ici et ) de la saga Ruxor veut refaire le moteur de son blog, finalement j'ai été suffisamment excédé par la libxml2 pour décider d'utiliser Xerces et… Java. Oui, je sais, je ne suis pas très cohérent avec moi-même, mais bon, c'est l'occasion d'apprendre un peu mieux à programmer en Java, chose qui, comparé à programmer en Perl, ressemble un peu à construire des temples grecs par rapport à des maisons dans les arbres : c'est plus fastidieux, ça paraît plus joli et plus propre quand c'est fini, et il y a plein de règles un peu bizarres à suivre et d'incantations à prononcer pour faire plaisir aux dieux (static public abstract class GoddessOfWisdom extends Pantheon.Goddess, ô Athéna aux yeux de hibou…) : donc ça va parfaitement bien pour combattre Xerces. Si vous voulez suivre les progrès en direct, il y a une interface Gitweb qui vous dira tout ce que je fais là-dessus.

Mais ce que j'ai surtout fait, récemment, c'est modifier juste un tout petit peu l'ancien moteur (celui qui est écrit en C et qui, malheureusement, sert encore et toujours) pour qu'il puisse gérer, a minima, le format que je veux donner à mon fichier d'entrée (c'est-à-dire, où toutes les balises que j'ai inventées vivent dans un espace de noms séparé ; mon hack consiste juste à les reconnaître à leur préfixe, donc c'est un changement totalement trivial sur cet ancien moteur). Comme ça je ne suis pas prisonnier de mon travail en cours, et je peux continuer à bloguer sans avoir à jongler avec deux versions du fichier (une à l'ancien format et une au nouveau), donc, en pratique, sans avoir à attendre d'avoir fini de coder mon temple grec en Java.

Bon, entre temps, évidemment, toutes les idées géniales qui m'ont traversé la tête en sont — justement — ressorties, ce qui est quand même dommage parce que je pourrais jurer que, si, si, elles étaient vraiment géniales. Enfin, je crois. Faute de pensées profonde, vous aurez droit à ma vie (ce qui est, après tout, le principe d'un blog).

↑Entry #1748 [older| permalink|newer] / ↑Entrée #1748 [précédente| permalien|suivante] ↑

↓Entry #1747 [older| permalink|newer] / ↓Entrée #1747 [précédente| permalien|suivante] ↓

(mardi)

libxml2 et maux de tête

Loi de Hofstadter : Les choses prennent toujours plus de temps que prévu, même quand on tient compte de la loi de Hofstadter.

Quand je me suis mis mis en quête de remplacer le moteur de ce blog, il y a déjà un mois (traduire : ça fait un mois que je travaille là-dessus dès que j'ai du temps libre), je pensais que ce serait plutôt facile. C'était sans compter le principe ci-dessus, et surtout le fait général qu'à chaque fois que je commence à utiliser un programme ou une bibliothèque qui, superficiellement, de loin, a l'air bien pensé et bien écrit, je me rends compte que tout n'est que façade, que c'est bourré de bugs ou de limitations obscures et que rien ne marche comme annoncé, qu'il y a généralement des petites crottes de ragondin partout. C'est le cas, spécifiquement, de la libxml2 et (par voie de conséquence) de son enrobage Perl, XML::LibXML.

En l'occurrence, ce qui me cause le plus de maux de tête, c'est la façon dont sont gérés les namespaces XML. (J'utilise un namespace à moi pour séparer les balises que j'ai inventées, dans le code que je tape, des balises HTML — c'est justement à ça que servent les namespaces.) Superficiellement, la façon dont la libxml2 procède est très bien : plutôt que d'imposer que le programmeur attache lui-même les attributs xmlns nécessaires aux endroits voulus (comme ce serait le cas en principe avec une implémentation conforme du DOM), la libxml2 attache elle-même les attributs comme il faut aux endroits où il faut. L'ennui, c'est que parfois ces attributs cessent d'être nécessaires, ou parfois on est obligé d'en ajouter à cause de limitations bizarres de la bibliothèque, et alors c'est la croix et la bannière de les retirer. Or le standard XHTML ne m'autorise pas la fantaisie d'avoir des attributs xmlns:inutile="http://www.example.tld/mon/namespace/a/moi/" qui ne servent pas — on a le droit (pour êre valide) à exactement un attribut xmlns sur tout le document, c'est sur l'élément <html> à la racine, point-barre. Enfer et damnation ! J'ai passé un temps infini à contourner ce bug, qui n'est pas grave en lui-même, mais qui est rendu gênant par celui-ci, après avoir aussi trébuché sur ce bug (corrigé dans la dernière version), et m'être lamenté qu'il n'y ait pas une autre façon de faire. La seule façon que j'aie finalement trouvé pour contourner (pas résoudre, mais contourner) ce genre de problèmes, c'est de recopier tout l'arbre DOM juste avant de le sortir, de façon à obliger la bibliothèque à ne recopier que les déclarations de namespace qui servent vraiment (et, on l'espère, une seule) : ceci coûte un temps délirant et vraiment inacceptable (environ quatre à cinq secondes pour traiter mon blog, sur une machine relativement puissante).

Évidemment, je m'expose à un concert de protestations comme quoi j'aurais dû écrire en <insérez ici votre langage de programmation préféré>. Bon, pour une fois, on ne pourra pas me dire Python, parce que l'implémentation du DOM XML de Python, soit elle est aussi basée sur la libxml2, et elle souffre exactement des mêmes défauts, soit c'est xml.dom.minidom qui a d'autres limitations encore plus douloureuses. Par contre, il est possible que j'aureusse dû [←ceci est un subjonctif conditionnel passé, ne cherchez pas] utiliser Java ou C#/Mono. Toujours est-il que je ne sais plus où donner de la tête.

↑Entry #1747 [older| permalink|newer] / ↑Entrée #1747 [précédente| permalien|suivante] ↑

↓Entry #1742 [older| permalink|newer] / ↓Entrée #1742 [précédente| permalien|suivante] ↓

(lundi)

xml:lang et le DOM

La râlante du jour (dans le fil de la quête envisagée hier) :

Le W3C standardise en XML l'usage de l'attribut xml:lang pour indiquer la langue du contenu d'un élément (la langue est implicitement héritée par tous les descendants de la balise). J'en fais un usage systématique[#] quand je tape du texte en n'importe quelle variante de XML (par exemple, si je dois citer The Lord of the Rings dans ce blog, j'écris : <cite xml:lang="en">The Lord of the Rings</cite> (et mon moteur de blog ajoutera un lang="en" en plus du xml:lang="en" pour compatibilité HTML, mais peu importe ici). Très bien.

Le W3C standardise un modèle d'objets (DOM) pour accéder à un document XML. Énormément de bibliothèques se basent dessus pour les manipulations, et il n'est pas trop déplaisant à utiliser. Tant mieux.

Mais ce DOM ignore complètement les spécificités de l'attribut xml:lang : aucune fonction n'est prévue pour interroger la langue d'un élément du DOM, ni pour copier/déplacer/supprimer un élément en préservant sa langue et celle de tous les descendants (c'est-à-dire en ajoutant un attribut xml:lang si nécessaire, ou en le retirant s'il est devenu superflu au nouvel emplacement). Il faut tout faire à la main. Moins bien. Beaucoup moins bien.

La façon évidente de procéder consiste en début de traitement à propager systématiquement l'attribut xml:lang à tous les descendants de n'importe quel nœud, à manipuler le document ainsi transformé, et à expurger les attributs xml:lang inutiles à la fin du traitement. Malheureusement, cette façon évidente est lente, très lente. Pas bien du tout, ça.

Alors, à chaque déplacement d'une balise, il faut se farcir une réflexion pénible : Est-ce que je suis en train de casser potentiellement un héritage de xml:lang, là ?

Bref, des petites crottes de ragondin, comme aime le dire mon ami David Monniaux.

[#] Dans le fol espoir, par exemple, qu'un jour il existe un correcteur orthographique en tenant compte (c'est-à-dire, capable de corriger un mélange aléatoire de français, d'anglais et de je ne sais quoi, dans n'importe quelle instance de XML, en prenant le bon dictionnaire pour chaque passage). Ou qu'un moteur de recherche sache en faire un usage intelligent. Je sais, je suis naïf, c'est touchant.

↑Entry #1742 [older| permalink|newer] / ↑Entrée #1742 [précédente| permalien|suivante] ↑

↓Entry #1741 [older| permalink|newer] / ↓Entrée #1741 [précédente| permalien|suivante] ↓

(dimanche)

Je voudrais changer le moteur de ce blog

Le moteur de ce blog est une abomination sans nom. Il s'agit d'un programme C, que j'ai écrit il y a sept ans, qui parse un fichier source XML unique que j'édite et qui contient toutes les entrées, pour produire les fichiers HTML statiques rassemblant les entrées de chaque mois ainsi que celui contenant les 20 dernières entrées et celui reprenant mes fragments littéraires gratuits ou encore l'index de toutes les entrées. Le même programme sert à générer un certain nombre d'autres pages de ce site Web (mais pas toutes, parce que j'ai un bon nombre de couches de vieilleries empilées les unes sur les autres ☹️ — avec au moins trois styles de présentation différents, plus quelques pages qui sont exceptionnelles pour une raison ou une autre).

Je n'ai pas voulu utiliser un moteur de contenu|blog standard, d'abord parce qu'en 2003 le choix n'était pas terrible, mais aussi parce que je tiens à avoir des pages HTML statiques et pas générées à chaque requête, ou parce que je déteste le PHP, ou simplement parce que je suis control-freak. Je me suis dit qu'avoir mon propre moteur me donnerait plus de flexibilité pour me créer des nouveaux tags dans le source, pour organiser mon contenu comme je le veux, ou ce genre de choses. Enfin, ça c'était la théorie, et ça n'a pas marché du tout.

J'ai écrit le moteur en C pour des raisons d'efficacité : la machine qui fait le traitement était initialement une machine de l'ENS complètement à bout de souffle, et toutes les autres solutions que j'avais regardées (notamment des choses sur Perl) étaient abominablement lentes. Quant à XSLT, sur lequel j'étais parti, il n'était décidément pas adapté (déjà, seule la version 1 existait en 2003, mais le moindre test, comme pour vérifier que les entrées étaient bien numérotées correctement, devenait une insupportable prise de tête).

Mais même en C, l'efficacité est devenue un problème. Mon programme ne génère qu'un fichier mensuel par appel : pour générer tous les 86 fichiers de sortie (84 mois plus trois fichiers particuliers), il faut donc l'appeler 86 fois, et à chaque fois il doit parser complètement le fichier d'entrée qui fait maintenant 5.5Mo. Ça fait l'équivalent de 470Mo de XML à traiter : même si le serveur qui fait le traitement est un peu plus rapide que celui avec lequel j'ai commencé, ça prend presque une minute, que je n'ai pas envie d'attendre à chaque fois que je compile pour vérifier que tout s'affiche bien comme je veux. J'ai adopté la moyenne mesure consistant à recompiler à chaque modification seulement les fichiers des trois derniers mois (plus l'index et le fichier des 20 dernières entrées), et à recompiler une fois par mois (ou quand j'en éprouve le besoin particulièrement) la totalité du HTML, des fois que j'aurais fait des corrections de fautes d'orthographes dans des entrées un peu anciennes. Ce n'est vraiment pas satisfaisant (mais détecter si une entrée ancienne a changé n'est pas facilement possible). Et surtout, ça m'a empêché de créer d'autre « catégorie » que celle des fragments littéraires gratuits (savoir quels fichiers recompiler deviendrait de plus en plus abominable). En l'état actuel du programme, le modifier pour produire plusieurs fichiers en sortie par un seul appel serait d'une difficulté inextricable.

Et je ne parle pas des maux de tête au sujet du fil RDF, qui est une abomination dans une abomination (un autre programme C qui partage une partie du code source du premier) : je sais qu'on m'a demandé mille fois de mettre des heures dedans, et/ou de mettre le début de mes entrées plutôt que juste leur titre, mais avec le programme que j'ai c'est juste trop difficile.

Ajouter à ça que la compilation du programme C moteur de blog lui-même est très lente (il y a un fichier source qui est assez énorme). Donc, même sans compter que toute manipulation de chaînes de caractères en C s'apparente au plaisir de résoudre une équation différentielle à la règle à calcul : ajouter le moindre tag que je pourrais utiliser dans le source est vraiment trop chiant. Du coup, finalement, je fais presque tout à la main (par exemple, les notes en bas d'entrée, elles ne sont pas formatées automatiquement comme elles devraient l'être). Tout ça fait que j'ai envie de tout mettre à la poubelle.

Je viens de passer la journée à me demander ce que je veux utiliser à la place. Je pense que je m'oriente vers une architecture en Perl, utilisant la XML::LibXML (même si j'ai déjà eu des soucis avec), et vers une compilation en deux parties, une partie consistant à insérer les entrées dans une base de données SQL (ce qui permettra, par exemple, de savoir plus facilement celles qui ont changé) et la seconde consistant à générer les fichiers HTML à partir de différents modèles qui font appel à cette base de données.

↑Entry #1741 [older| permalink|newer] / ↑Entrée #1741 [précédente| permalien|suivante] ↑

↓Entry #1701 [older| permalink|newer] / ↓Entrée #1701 [précédente| permalien|suivante] ↓

(mercredi)

TP en Sage, et webapplications

J'ai donné hier un TP pour un cours d'(introduction à l')arithmétique pour la cryptographie[#] dont je suis responsable à Télécom (dans le cadre d'un master sécurité). Le choix du logiciel de calcul symbolique dans lequel travailler est toujours un peu épineux. Je préfère par principe un logiciel libre, ce qui laisse encore un certain choix ; mais il faut tenir compte de l'environnement disponible dans les salles de TP auxquelles j'ai accès. Or, à ce sujet, sauf à aller frapper à la porte d'autres départements de l'École, le choix est entre des salles de PC Windows (or je ne sais pas utiliser Windows, et je n'ai pas trop envie d'apprendre) ou de Sun (également Intel) sous Solaris 11, l'installation de ce dernier OS n'étant pas toujours complètement orthodoxe (et, concrètement, compiler n'importe quoi est une gageüre). L'an dernier j'avais fait mes TP sous Maxima qui est, il faut le dire, assez mauvais (et je ne sais pas qui a eu l'idée d'utiliser “:” pour l'affectation, mais il devait vraiment avoir fumé quelque chose). Cette année, j'ai jeté l'éponge sur l'idée de compiler quoi que ce soit sur les machines de TP, et j'ai utilisé Sage[#2] à distance : le programme tourne sur ma machine au bureau, et les étudiants y accèdent par un navigateur Web. Il faut dire que Sage a un système de worksheets assez impressionnant de ce point de vue-là (il y en a une démonstration publiquement accessible sur www.sagenb.org[#3]).

C'est une idée séduisante a priori : au lieu de faire une interface graphique, un programme peut toujours décider d'utiliser un navigateur pour ça, de se présenter sous la forme d'un site Web. Et de fait, les webapplications rencontrent un succès spectaculaire qu'on peut juger au nombre de bouquins sur Ajax (il ne s'agit pas du cousin d'Achille) qu'on peut trouver dans n'importe quel rayon informatique (section technologies Web) de librairie.

Mais en fait, le concept a aussi ses limitations, qu'on rencontre rapidement même quand la réalisation est soignée, et qui donnent un petit goût désagréable d'inachevé ou de bricolé. Prenez les racourcis clavier : on ne peut y mettre que ce que le navigateur lui-même n'a pas réquisitionné ; prenez les commandes à la souris : elles sont sévèrement contraintes par ce que le modèle de focus du document permet ; on a du mal à avoir un vrai menu contextuel, on a du mal à avoir du glisser-déplacer qui marche de façon fluide et claire, on a du mal à avoir un copier-coller riche, on a du mal à avoir un système de menus ou un toolkit qui s'harmonise bien avec le navigateur, l'édition des textes se fait dans des widgets qui ne sont pas de vrais éditeurs, la notion de session est difficile à faire avaler à un système (le Web) prévu pour être sans état… Bref, l'idée est sympa et certainement très utile, mais j'aimerais bien que des solutions soient trouvées pour que ça cesse d'être du bricolage et que l'intégration soit vraiment parfaite (c'est-à-dire aussi bonne que pour une application native) : or j'y crois fort peu. S'agissant de l'interface worksheet de Sage, le boulot réalisé est impressionnant, certes, mais ce genre de limitations me frappe toujours : le copier-coller a des ratées, les rectangles de saisie varient parfois de taille de façon inexpliquée, bref, les finitions manquent (et ce n'est pas la faute de Sage, c'est le concept de webapplication qui rend ça pour l'instant inévitable).

Bon, le pire ça a surtout été quand j'ai voulu faire cet après-midi un corrigé de ce TP : je me suis dit que j'allais l'écrire comme une worksheet Sage, justement (plutôt qu'en tapant tout en TeX). Mauvaise idée. D'abord, tous les commentaires entourant les commandes, j'ai dû les saisir dans un éditeur HTML appelé depuis l'interface et qui est certes impressionnant mais qui n'est pas l'éditeur que j'ai l'habitude d'utiliser (et pour ce qui est du copier-coller, de nouveau, c'est pas terrible). Mais une fois que j'eus fini et que j'eus publié ma worksheet, je me suis senti un peu escroqué : la page Web ainsi produite est assez jolie, mais pas moyen de l'exporter en PDF (si j'essaie de l'imprimer vers un PDF, mon navigateur produit quelque chose de vraiment très moche), pas vraiment moyen non plus de la sauver comme une page HTML (elle fait appel à des quantités invraisemblables de JavaScript de chez jQuery et jsMath), on peut juste en sauvegarder une version au format Sage worksheet, qui sera certes lisible sur un autre Sage, mais bon, le problème initial était justement que ce n'est pas la chose la plus facile au monde à installer.

[#] Le but du cours étant d'arriver à faire comprendre à des gens qui ont fait des parcours assez différents (et parfois plus fait de maths depuis longtemps) comment « fonctionnent », si j'ose dire, ℤ/mℤ (le théorème chinois, les éléments primitifs, ce genre de choses) et (un tout petit peu) les corps finis.

[#2] Aux dernières nouvelles, Sage ne tourne pas sous Windows, et pas bien (ou pas complètement) sous Solaris. Donc c'était peu évident, comme solution !

[#3] Je me demande comment ce site fait pour ne pas être complètement vandalisé, d'ailleurs.

↑Entry #1701 [older| permalink|newer] / ↑Entrée #1701 [précédente| permalien|suivante] ↑

↓Entry #1634 [older| permalink|newer] / ↓Entrée #1634 [précédente| permalien|suivante] ↓

(vendredi)

Martine écrit en UTF-8

Vu sur le blog de David Monniaux :

Captcha anti-spam : quel est le septième caractère du mot "réaction" ?

Je n'arrive pas à deviner si c'est le résultat d'un programme mal configuré, si c'est une blague ou si c'est un test particulièrement subtil et raffiné, et s'il s'agit de reconnaître les robots au sens propre ou les logiciens… Apparemment, la réponse i a été considérée comme correcte.

Pour les non-informaticiens : l'UTF-8 est le mécanisme le plus courant pour encoder (c'est-à-dire stocker sous forme de suite d'octets) le jeu de caractères universel Unicode. Parfois il arrive que des programmes (mal configurés) ne soient pas d'accord entre eux sur un encodage et, par exemple, l'un émet des caractères encodés en UTF-8 tandis qu'un autre les comprend comme étant du Latin-1 (c'est-à-dire l'encodage le plus simple possible, à base de 1 caractère = 1 octet de même valeur, des 256 premières cases d'Unicode, qui constituent également le standard plus ancien Latin-1) : cela donne des résultats caractéristiques que tout le monde a sans doute vus au moins une fois.

↑Entry #1634 [older| permalink|newer] / ↑Entrée #1634 [précédente| permalien|suivante] ↑

↓Entry #1605 [older| permalink|newer] / ↓Entrée #1605 [précédente| permalien|suivante] ↓

(Wednesday)

Elements of an EmotionML 1.0

I checked the date: nowhere does this say April 1st. So apparently there really are people at the W3C conteplating the idea of replacing the lowly smiley :-) by the more advanced, much more precise, and so much easier to type and read <emotionml xmlns="http://www.w3.org/2008/11/emotionml"> <emotion> <category set="everydayEmotions" name="Amusement" /> <intensity value="0.6" confidence="0.8" /> </emotion> </emotionml>.

Wonderful. I can't wait to annotate my emails with those. <emotionml xmlns="http://www.w3.org/2008/11/emotionml"> <emotion> <category set="everydayEmotions" name="Sarcasm" /> <intensity value="0.9" /> </emotion> </emotionml>

↑Entry #1605 [older| permalink|newer] / ↑Entrée #1605 [précédente| permalien|suivante] ↑

↓Entry #1570 [older| permalink|newer] / ↓Entrée #1570 [précédente| permalien|suivante] ↓

(Friday)

How to add a personal menu to Firefox

(I'm too busy to blog right now, so I'm just posting something I had written previously and was hoping to improve but didn't have the time to. I figured it was better to publish it as such—and rough at the edges—than to postpone indefinitely.)

Here's a quick HOWTO on how to add a personal menu to Firefox. The point, here, is not to publish a Firefox extension (there's already abundant doc on this subject) but, rather, to modify one's profile to personalize the menu system in a quick and (relatively) easy way. What follows should work on every operating system supported by Firefox, although I've only tested it on Unix; also, I will assume Firefox 3. I assume the reader has some basic knowledge of XML, and, of course, if you want to do anything useful in your menu you must know some JavaScript.

First, create a directory in which the menu files will reside. I suggest something like ~/firefox/mymenu/ and I will assume that name in what follows. It will be an easy thing to copy the content of this directory to other machines to distribute the menu extension on them; also, it will be relatively easy to turn this working directory into a bona fide (i.e., .xpi) Firefox extension, although I won't cover this here.

Next, create a file called install.rdf inside the menu's working directory (so, ~/firefox/mymenu/install.rdf). Model it as follows:

<?xml version="1.0" encoding="utf-8"?>
<RDF:RDF xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 
         xmlns:NS1="http://www.mozilla.org/2004/em-rdf#">
  <RDF:Description RDF:about="urn:mozilla:install-manifest">
    <NS1:id>mymenu@local</NS1:id>
    <NS1:name>My Local Menu Extension</NS1:name>
    <NS1:version>0.0.0.0.0.1</NS1:version>
    <NS1:creator>John Doe User</NS1:creator>
    <NS1:description>A local menu loaded with goodies!</NS1:description>
    <NS1:targetApplication>
      <RDF:Description>
        <NS1:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</NS1:id> <!-- firefox -->
        <NS1:minVersion>3.0</NS1:minVersion>
        <NS1:maxVersion>3.0.*</NS1:maxVersion>
      </RDF:Description>
    </NS1:targetApplication>
  </RDF:Description>
</RDF:RDF>

RDF is a bit arcane (see here if you want to learn more about it), but you don't need to understand it in order to write this: basically, what matters is that this files specifies a number of important properties of the extension we are defining (yes, we are defining a Firefox extension, albeit one which might remain purely local). The most important such property is NS1:id (actually the property's name is really http://www.mozilla.org/2004/em-rdf#id, but that doesn't matter here), which specifies a unique identifier for the extension: here I am calling it mymenu@local, which is fine if you don't expect it to ever become public—if you do, it's probably better to call it something like mymenu@mydomain.example.tld where mydomain.example.tld is some domain you own. Another possibility is to use a UUID such as {da0bfd29-39a2-44d5-8b58-8e9badbbec7a} (you can use the uuidgen program to create one; remember to enclose it in curly braces, as shown here), although UUIDs are obviously more difficult to type and remember. Other properties required in install.rdf are NS1:name (the human-readable name of the extension, as it will appear in the extension list) and NS1:version (the extension's version number; there are sophisticated rules to compare version numbers, but I suggest sticking to something very simple, i.e., a period-separated list of numbers which will be ordered component by component). The NS1:creator (creator's name) and NS1:description (one-line description of the extension) properties are optional, but I suggest filling them in anyway. Finally, NS1:targetApplication indicates which programs the extension is made to work with: here, {ec8030f7-c20a-464f-9b0e-13a3a9e97384} means Firefox, and the NS1:minVersion and NS1:maxVersion specify the minimal and maximal accepted versions of Firefox, here anything in the form 3.0 or 3.0.something will match (I suggest leaving it as such, and increasing NS1:maxVersion after testing with 3.1 when it comes out). If you mean to make your menu also work for Thunderbird, add another NS1:targetApplication block (don't reuse the previous one!) and specify {3550f703-e582-4d05-9a08-453d09bdfdc6} as NS1:id. For more information about what can go in the install.rdf file, see here on developer.mozilla.org and here on mozillazine.org.

After you've written the install.rdf file, the other important file which needs to be created is chrome.manifest (details about it here). Create it in the same directory (so ~/firefox/mymenu/chrome.manifest) and model it as follows:

content mymenu chrome/content/
overlay chrome://browser/content/browser.xul chrome://mymenu/content/mymenu.xul

What we're saying here is:

  • The chrome://mymenu/content/ URL shall now refer to the files in the chrome/content/ subdirectory (i.e., ~/firefox/mymenu/chrome/content/). This is important, because residing in the chrome:// URL scheme gives the files extra privileges (the JavaScript they contain can freely access all Mozilla components, for example). If you want to be able to access the files with their chrome:// URL by typing it directly in the URL box (or linking to them, or such things), you need to add contentaccessible=yes at the end of the first line.
  • The chrome://browser/content/browser.xul file shall be modified by the overlay found in chrome://mymenu/content/mymenu.xul (and which, according to the previous line, will reside in ~/firefox/mymenu/chrome/content/mymenu.xul). This is important, because chrome://browser/content/browser.xul is the master URL for the Firefox browser (in a way, it is the browser), so to define a new menu you need to modify it by overlaying it. If you need to similarly overlay Thunderbird, the master URL is chrome://messenger/content/messenger.xul. (More details about overlays can be found here and here.)

Now we need to create the ~/firefox/mymenu/chrome/content/mymenu.xul file with the actual menu. Here is a template for it:

<?xml version="1.0" encoding="utf-8"?>
<overlay xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         xmlns:html="http://www.w3.org/1999/xhtml">
<script type="application/javascript">
// <![CDATA[
function StupidAlert() {
    alert("This is a stupid alert!");
}
// ]]>
</script>
<menubar id="main-menubar">
  <menu id="mymenu-menu" label="My Menu" accesskey="M">
    <menupopup>
      <menuitem label="Nop" accesskey="N" />
      <menuitem label="Stupid alert" accesskey="S" oncommand="StupidAlert()" />
    </menupopup>
  </menu>
</menubar>
</overlay>

This is, of course, an utterly stupid example, merely intended to demonstrate how the file can be written: here, we overlay the Firefox main menubar (the main-menubar is the key, here) with a new menu which is labeled My Menu (the first ‘M’ will be underlined and will serve as access key), which pops up with two items: the first is labeled Nop and does absolutely nothing, and the second is labeled Stupid alert and runs the JavaScript function StupidAlert() defined above (this is contrary to Mozilla good practice which demands that JavaScript code be separated from the XUL structure, and also that user-readable labels be separated so they can be i13zed, but when defining a personal menu one typically does not care about such practices).

The language in which this file is written is an instance of XML called XUL: to learn more about XUL you can start with this excellent tutorial, but you can also learn it the quick-and-dirty way by trying to imitate the Firefox XUL itself, which you can find in a file called browser.jar (you can extract it with unzip) somewhere in your Firefox installation directories (a typical directory under Linux would be /usr/share/firefox/chrome/browser.jar, but YMMV). Similarly, if you want your menu to do something useful, you need some JavaScript, and, more probably, you need some Mozilla-specific JavaScript: you'll find many examples of that here (you might also find this page useful if you need to access Firefox windows or their content).

But before you start coding away, there is one last thing that needs to be done: now that a basic menu has been created in ~/firefox/mymenu/, you still need to tell Firefox about its existence! To do that, stop all running Firefoxen, then go in the extensions/ subdirectory inside your profile directory (on Unix, that would typically be ~/.mozilla/firefox/*.default/extensions/), and create a file called mymenu@local (use the same name as the NS1:id of your extension, even if that means using curly braces around a UUID) which just contains one line:

~/firefox/mymenu

i.e., name of the directory in which your extension (and importantly, the install.rdf and chrome.manifest files) resides. When Firefox is next launched, it should tell you that a new extension has been installed and the menu should be visible. After that, whenever you modify something in the ~/firefox/mymenu/ directory, increment the version number in install.rdf and restart Firefox (while this is not always strictly necessary, it is definitely good practice to avoid confusion).

↑Entry #1570 [older| permalink|newer] / ↑Entrée #1570 [précédente| permalien|suivante] ↑

↓Entry #1564 [older| permalink|newer] / ↓Entrée #1564 [précédente| permalien|suivante] ↓

(lundi)

Déboires avec OpenOffice.org, ou comment mettre en page un roman

Je laisse (temporairement ?) de côté la suite de mes rants contre le principe de précaution, parce que ça va sans doute me prendre encore beaucoup trop de temps d'écrire les numéros (2) et (3).

Mes déboires avec OpenOffice.org ont commencé lorsque mon poussinet, au cours d'une discussion sur des romans d'un auteur de heroic fantasy que nous apprécions tous deux (Raymond Feist), a appris que j'avais moi-même écrit un roman quand j'étais petit (roman qui est plus cher à mon cœur qu'il n'est littérairement potable), et il [le poussinet] a exprimé le désir[#] de le lire. Seulement, pour ça, il en fallait une version imprimée, la version HTML étant trop peu commode à lire (version HTML qui actuellement est mais je compte la remplacer par mieux, justement, cf. ci-dessous). D'où l'idée, née de mon enthousiasme naïf et de la supposition candide que la technique marche parfois, d'en générer une version PDF par conversion d'une version OpenDocument via OpenOffice.org. [Ajout : voir cette entrée ultérieure au sujet de ce roman,]

↑Entry #1564 [older| permalink|newer] / ↑Entrée #1564 [précédente| permalien|suivante] ↑

↓Entry #0266 [older| permalink|newer] / ↓Entrée #0266 [précédente| permalien|suivante] ↓

(Friday) · German Unification Anniversary

XHTML or no XHTML?

Ian Hickson has written an interesting note on why not to use XHTML for the moment. He raises some very interesting issues. One of them is that the overwhelming majority of Web authors are hopelessly clueless and will just copy their HTML code from some other site or some poorly written book. Now when they start copying thinks like <?xml version="1.0" encoding="utf-8"?> and <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> without understanding what it means, then we have problems. Also when they start writing <br /> when they should have written <br> or vice versa, because they haven't heard of XHTML or don't know the difference with SGML-based HTML. Hell will not break loose now, because existing Web browsers have been built to be very fault-tolerant, but it may break loose in the future.

So, my important advice to Web authors: if you don't want to write markup that validates (or if this all sounds Chinese to you), fine, but then make sure of one thing: don't include in your HTML code anything which contains the characters <? or the word DOCTYPE. Just don't. Unless you know exactly what they mean, that is, and are prepared to face the consequences. If you don't, what you're writing is known as a tag soup, and the correct way to start an HTML tag soup is with <html> (or perhaps <html lang="en"> or some such thing). If you start the document with <?xml version="1.0" encoding="utf-8"?> then you are promising well-formed XML, so you had better know what this means. If you include a line such as <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> then you are promising markup that validates against a specific DOCTYPE, so you had better check that it does validate. If you aren't prepared to go through all that, then start with <html> and write tag soup, which just works.

Now why do I write XHTML when Ian Hickson quite rightly points out that it will bring me no advantage whatsoever (since it is served as text/html and not application/xhtml+xml)? Well, for one thing, my XHTML is valid: but the point of being valid is not that it makes the page any better per se, it simply helps me check for some basic mistakes that even using two-and-fourty different Web browsers wouldn't catch. But also, quite trivially, I find XHTML simpler to write than HTML4: writing <br> without ever closing the tag, for example, just seems wrong. And when the pages are computer-generated it's even more obvious: it is such a pain to write a program that will have to remember that the <br> tag may not be closed, for example, whereas in XHTML we simply close every tag, no questions asked.

↑Entry #0266 [older| permalink|newer] / ↑Entrée #0266 [précédente| permalien|suivante] ↑

↓Entry #0213 [older| permalink|newer] / ↓Entrée #0213 [précédente| permalien|suivante] ↓

(Monday)

Maxwell's equations in MathML

I wrote down a set of electromagnetic relations in XHTML+MathML: this is both because I got tired of looking them up in books all the time and so as to test MathML functionality. And it isn't great: only (a recent version of) Mozilla displays something even vaguely accurate (but far from pretty). Opera shows every formula as a pretty much meaningless sequence of letters and numbers (interestingly enough, the Maxwell-Gauß equation is named Maxwell-Gau [sic] in Opera and becomes simply D=D, which is certainly true, but not what was intended). Konqueror is honest about its inabilities and refuses to even try and open the file. And the big disappointment comes from Amaya which also refuses to understand the MIME type application/xhtml+xml and, even if you force it to, isn't smart enough to avoid (wrongly) displaying the MathML semantic content annotation.

***Sigh***. And this is two and a half years after the standardization of version 2.0 of MathML. Hullo? Anyone doing any work around here?

↑Entry #0213 [older| permalink|newer] / ↑Entrée #0213 [précédente| permalien|suivante] ↑

↓Entry #0149 [older| permalink|newer] / ↓Entrée #0149 [précédente| permalien|suivante] ↓

(Friday) · Assumption

I am now an RDF property

Upon deciding that I would write an RSS feed for this site, and consider the possibility of using Web annotations to provide 'blog talkback (which, incidentally, seems completely unrealistic after further examination, given the present level of support of Web annotations on the client side), I endeavored to learn some more about RDF, which forms the basis of the semantic Web. I had previously learned something about RDF, but many things still escaped me, and I now understand it much better.

To illustrate it all, I “incarnated” myself as an RDF resource: http://www.eleves.ens.fr:8080/home/madore/meta.rdf#dmadore (don't expect anything remarkable, or indeed anything even remotely interesting, to happen if you follow this link—most probably your browser won't know what to make of the file; maybe this link will be of greater interest). Ideally I would like to convert all of my personal information page in RDF, but I don't think I'll be patient enough to do this. But if for some reason you wanted to say something about me in RDF language, the correct way to refer to me would be the URL I just gave.

Update: Just as I finish writing this, Garoo points me to the FOAF project, a kind of Friendster-alike (see my previous entry concerning Friendster) except that it works in a distributed (non-centralized) fashion, with self-provided RDF descriptions. So I definitely have to look into this.

↑Entry #0149 [older| permalink|newer] / ↑Entrée #0149 [précédente| permalien|suivante] ↑

↓Entry #0148 [older| permalink|newer] / ↓Entrée #0148 [précédente| permalien|suivante] ↓

(Friday) · Assumption

Should I pioneer the use of Web technologies?

The next big thing that is coming to this 'blog, now that I have it divided in pieces, will be the introduction of an RSS feed, so übergeeks can add the channel to their news aggregator and be informed within minutes of every word of wisdom that pours forth from my mouth. Ain't technology impressive? Seriously, an RSS feed should be a simple task to set up, since I already have the XML parser and producer chains in place. I take the occasion, however, to underline the fact that RSS is an atrociously badly conceived format, obviously designed by people who didn't have a clue as to the use of XML (the most singularly stupid feature is probably the way that it refuses to allocate an XML namespace for itself, pretexting that that would break upward compatibility—probably the most massively ridiculous argument I ever read). But since RSS is a de facto standard, I guess I'll have to come to terms with the annoyance.

Other than that, several people by now have complained about the absence of talkback on this 'blog. The reason is part technical, part political: I can't allow myself to install the required cgi-bin on the ENS students server, and while I could dissociate comments from post by putting comments on a separate server (say, my own PC, which has a permanent IP address), there are practical problems there. You're always welcome to email me (david[plus]www[at sign]madore[dot]org) about anything I write, of course.

However, a crazy idea struck me: what if, instead of setting up a bunch of cgi-bin to enable specific talkback for this 'blog, I resorted to using generic Web annotations? For those who don't know what this is about, Web annotations are a generic (and yet experimental) framework for storing (personal or shared) annotations and comments on Web pages on a server without modifying the Web page itself. On the client side you have a browser or browser extension or plugin that will query the extension server for annotations on the Web page under consideration; annotation clients exist for Mozilla (Annozilla, the Mozilla annotation extension) and even for Internet Explorer (Snufkin), while the testbed client is the Amaya browser. On the server side, the annotation server is a specialized Web server that stores a lot of RDF metadata linking the annotation to the annotated page. Annotations can be used for common reviews, for shared bookmarks or for a quantity of other things. There's no reason why they shouldn't be used for 'blog talkback—barring the obvious reason that it's still experimental, little supported and clumsy, but that's just the sort of things that appeals to me. And the nice thing is it wouldn't be restricted to 'blog talkback: annotations are completely generic, so if I set up an annotation server, anyone who has access to it can use it to comment any Web page whatsoever, or to read my annotations on any Web page whatsoever.

↑Entry #0148 [older| permalink|newer] / ↑Entrée #0148 [précédente| permalien|suivante] ↑

↓Entry #0031 [older| permalink|newer] / ↓Entrée #0031 [précédente| permalien|suivante] ↓

(Monday) · Memorial Day (US)

A note about XML and the DTD annoyance

XML is an interesting (but possibly heavily over-hyped) generic (or “meta”) description language, based on the markup concept (aka, “tags”), that allows a very wide variety of applications, from hypertext to mathematics, through graphics, abstract semantics, synchronized multimedia, user interface description, site syndication and much more. One of its ingenious (or, actually, completely trivial) ideas is the use of namespaces to separate tag vocabularies into semantic units.

One of the dubious features of XML, however, is the fact that it maintains compatibility with the older SGML (or ISO 8879). For this reason, an XML file typically contains, or includes by reference, a Document Type Declaration (DTD). The unfortunate thing is that (for legacy reasons) this DTD plays a double role: it serves both to define validity constraints on the document (such as to define which tags can contain which), which can be verified by a “validating parser”, and on the other hand to provide genuine semantic content / data information. For example, the fact that in HTML the entity &eacute; represents the character “é” (LATIN SMALL LETTER E WITH ACUTE) is determined by the DTD; whereas the fact that the tag <link> determines a link is governed by the namespace (in the case of XHTML, http://www.w3.org/1999/xhtml). This is an unpleasant grouping of attributions, for one would sometimes want to be able to invent an XML application that has its own namespace and also its own set of entities but that does not care about validation (or for which validation is pretty much meaningless). Also, it is the DTD which determines the fact that such or such an attribute might have this or that default or fixed value, which means that the DTD has to be read not only to validate the document but also to determine entity replacements (part of the actual document content) and attribute values. And the DTD also determines which attribute (normally named id) is the fragment ID reference.

It has become much more obvious to me while working with XSLT (which cannot produce an internal DTD subset in the output document, unfortunately), and XUL or MathML (which, embedded in HTML, are very difficult to describe through a DTD), that DTDs are rather inadequate, but that they are tied up with XML in such a way that it is difficult to dispense with them entirely.

↑Entry #0031 [older| permalink|newer] / ↑Entrée #0031 [précédente| permalien|suivante] ↑

↓Entry #0030 [older| permalink|newer] / ↓Entrée #0030 [précédente| permalien|suivante] ↓

(Sunday) · Mother's day (France)

Isn't Mozilla great?

I've had some fun prodding the mighty Lizard today. Now I can play some of my favorite solitaire card games (though free cell is missing, unfortunately) within my browser just by clicking on this link (which probably won't work for you). Yeah, it's pretty useless of course (and rather slow, too, since it's all in JavaScript and XUL), but it's so cool. Actually, it's not completely useless, because it has the advantage of being cross-platform: I have all these card games from other sources on my home PC under GNU/Linux, but I might not have them everywhere. Anyway. Mozilla might not brew coffee yet, and looks very much like a kitchen sink, but it does some interesting things. Of course, the question is whether it can compete with Emacs.

↑Entry #0030 [older| permalink|newer] / ↑Entrée #0030 [précédente| permalien|suivante] ↑

↓Entry #0017 [older| permalink|newer] / ↓Entrée #0017 [précédente| permalien|suivante] ↓

(Wednesday)

On metadata

I'm slowly beginning to grasp the concept of metadata, so I thought I'd say a few words about it. In truth, the difficulty is not with the concept itself (there's nothing so complicated about it: metadata are just ancillary data, that are not part of a document's content but describe the document itself), but the strange and fascinating architecture that various organizations, notably the World Wide Web Consortium, have built around it, and that bizarre language, RDF. RDF is a language of which one can easily (and that is what happened to me) read the specs and guide, and still not have the slightest idea of what it's all about: it seems at once completely abstract and devoid of utility. (As a mathematician, I really shouldn't have any problem with notions that are abstract and devoid of utility, yet…) Yet RDF is not a content-free language, and although claims that it is the universal “semantic” language (whatever that may mean) are pompous and not very meaningful, it is an interesting idea.

The most basic use of metadata would be, say, in an HTML document: to indicate a list of keywords associated with the document, one might write <meta name="Keywords" content="foo, bar, baz, qux" />, for example. Or to indicate who wrote the document, <meta name="Creator" content="Doe, John" /> might be used. But who decides what tags like “Keywords” and “Creator” are available? It could be, of course, a simple de facto list, with various tags understood by various kinds of potential users. But there is a more formal aspect: metadata vocabularies can be defined and collected in so-called “profiles”. In HTML, the profile attribute to the head element specifies the metadata vocabulary profile that is used.

One such profile is the Dublin core element set, which specifies a small list of basic (“core”) metadata properties. The formal description of the Dublin core namespace is an RDF file located at http://purl.org/dc/elements/1.1/, so one appropriate way to specify the keywords and creator for the document might be <head profile="http://purl.org/dc/elements/1.1/"> <meta name="Keywords" content="foo, bar, baz, qux" /> <meta name="Creator" content="Doe, John" /> </head>; another way, which is recommended by RFC 2731 consists of using the <link> element as follows: <head> <link rel="schema.DC" href="http://purl.org/dc/elements/1.1/" /> <meta name="DC.Keywords" content="foo, bar, baz, qux" /> <meta name="DC.Creator" content="Doe, John" /> </head>.

To exploit metadata to their full power, and to describe them commodiously, however, the RDF language is necessary. For example, to write the same metainformation as above in RDF, one would write, if I am not mistaken, <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"> <rdf:Description rdf:about="http://www.somedomain.tld/some/uri/" dc:keywords="foo, bar, baz, qux" dc:creator="Doe, John" /> </rdf:RDF>: this formally states that John Doe is the creator of http://www.somedomain.tld/some/uri/ which has keywords foo, bar, baz and qux. But RDF goes much beyond that: it is capable, for example, of making metastatements about the metadata themselves (as in “Jane Smith says that John Doe is the author of http://www.somedomain.tld/some/uri/”), or of defining (to some extent, of course—at a point it becomes necessary to express things in a natural language) the vocabulary that it uses (thus, the Dublin Core RDF vocabulary is itself expressed in RDF).

A strange and fascinating architecture, but beautiful it its way! I guess I should slowly start attaching some correctly labeled metadata to these pages.

↑Entry #0017 [older| permalink|newer] / ↑Entrée #0017 [précédente| permalien|suivante] ↑

↓Entry #0001 [older| permalink|newer] / ↓Entrée #0001 [précédente| permalien|suivante] ↓

(Thursday) · Labor's Day · New Moon

Starting this 'blog

[Traduction française ci-dessous.]

Well, here I am, having, apparently, finally succumbed to the “WebLog” fad.

Actually, this is an attempt to resuscitate my Web site, which has lain dormant for far too long: I no longer had the energy to motivate myself to make changes in it, and the more I waited, the more changes needed to be done, so the more discouraging it became, until I essentially dropped it (or “froze” it) altogether.

Now I will try to revive it piece by piece, migrating it to a different style. This WebLog (or “'blog”, as they say) should be the new nexus of it. The point being that this “Web log” style of writing should be more appropriate to the way I work: I get into sudden passions about this or that, and then I lose interest in it just as suddenly, so making a log entry is more appropriate than starting a whole Web page that will never be finished (of course, nothing I do is ever finished); and if my interest lasts long enough, I can try to copy the entry into a new page and develop it from there. Or something. Well, I'm not sure I'm making myself clear, but that's the idea. Naturally, I will never completely rewrite my old Web site in the new style (I don't even intend to try), so it will look yet more heterogeneous, but who cares? On the other hand, I will make a definite effort to avoid breaking existing links.

So what's different? Well, for one thing I'm now using XSLT to process what I write: this makes it easier to write Web pages which follow well-defined templates (and that is precisely my intention). I have also tried to make a better use of CSS in the hope of producing something a little less ugly than usual—I know not with what success. The font used here, by the way, is Zapf Optima (at least if available on your system), which is in my opinion simply the best type font in existence. I also hope XSLT will help me make this site more easily transportable, in preparation with the time when I'll have to relinquish my beloved http://www.eleves.ens.fr:8080/home/madore/ address (I already had to fight to keep the :8080 when every other page on the server lost it). Of course, XSLT has its price, too, because it's such a strange and perverse language, but I hope the benefits outweigh the cost.

Another thing is that I now entirely cease to care about non-standards-compliant Web browsers. It is simply too much of a pain to write the mass of bugware necessary to get the site working on antique and outdated browsers such as Netscape's Navigator / Communicator version 4.x, or Microsoft's Internet Explorer version 4 or 5, especially as I am moving to an XML-based architecture. I strongly recommend anyone using such browsers to switch to Mozilla, Konqueror, Apple's Safari browser, Netscape version 7.x, IE version 6.x, or a similar modern Web browser. For those who browse in text mode, Links should be a safe choice, although you evidently won't get all the bells and whistles of truly graphical browsers (though even Links now has a graphical interface, it is a mere extension of its text-based interface).

But enough of technicalities! Another major question I had to solve was, which language should I use: either English or French (there is no other language that I know even remotely well enough to write such a log in it). I am daily reminded that my English is nowhere as good as I wish it were: although some people have tried to persuade me of the contrary, I know better (and let me just insert a little wink at Pierre at this point: hi, Pierre!). On the other hand, English has, shall we say, a rather larger audience than French. And when I think about it, there are certain things which I'm more comfortable saying in English, and others in French: so I'll just do the obvious things, write some entries in English and others in French. I'll rarely translate from one to the other, however, because it takes so much work and I'm terribly bad at it either way; this entry is an exception because it's the first one and in a way the introduction.

Anyway, for better or for worse, this 'blog is started (maybe it will simply peter out after three entries, that wouldn't really surprise me, knowing myself for the lazy sloth I am). May first seemed like an appropriate time to do it; in French we have this proverb, en mai, fais ce qu'il te plaît (in May, do as you please), and it did please me. Did you notice that one third of the decade (I mean the 2000's, the years from 2000 through 2009) is by us already? And a third of 2003 also. Somehow, I think this is depressing. I'll say more about this some other day.

[French translation of the above.]

Eh bien voilà, j'ai enfin, semble-t-il, succombé à la mode des « WebLogs ».

En fait, ceci est une tentative pour ressusciter mon site Web, qui est resté au point mort bien trop longtemps : je n'avais plus la motivation nécessaire pour y faire des changements, et plus j'attendais, plus de changements devenaient nécessaires, donc plus cela devenait décourageant, jusqu'à ce que je laisse complètement tomber (ou « geler »).

Maintenant je vais tenter de le faire revivre morceau par morceau, le migrant vers un style différent. Ce WebLog (ou « 'blog », comme ils disent) devrait en être le nouveau cœur. Le principe, c'est que ce style d'écriture « WebLog » devrait être plus approprié à ma façon de travailler : je me passionne soudainement pour ceci ou cela, et j'y perds intérêt tout aussi rapidement, donc il vaut mieux faire une entrée dans un log que de commencer une page Web entière qui ne sera jamais finie (bien sûr, rien de ce que je fais n'est jamais fini) ; et si mon intérêt se maintient assez longtemps, je peux essayer de copier l'entrée dans une nouvelle page et la développer à partir de là. Ou quelque chose comme ça. Enfin, je ne sais pas si je m'exprime clairement, mais c'est l'idée. Naturellement, je ne réécrirai jamais complètement mon vieux site Web dans le nouveau style (je n'ai même pas l'intention d'essayer), donc il aura l'air encore plus hétérogène, mais qu'importe ? En revanche, je ferai un effort certain pour éviter de casser les liens existants.

Alors qu'est-ce qui est différent ? Eh bien pour commencer, j'utilise maintenant XSLT pour traiter ce que j'écris : ceci rend plus commode l'écriture de pages Web qui suivent des modèles bien définis (et c'est précisément mon intention). J'ai aussi tenté de faire un meilleur usage des CSS dans l'espoir de produire quelque chose d'un peu moins hideux que d'habitude — je ne sais pas avec quel succès. La police utilisée ici, à propos, est Zapf Optima (au moins si elle est disponible sur votre système), qui à mon avis est tout simplement la meilleure police de caractère qui existe. J'espère aussi que XSLT m'aidera à rendre ce site plus facilement transportable, en prévision du moment où je devrai abandonner mon adresse http://www.eleves.ens.fr:8080/home/madore/ bien-aimée (j'ai déjà dû lutter pour conserver le :8080 quand toutes les autres pages du serveur l'ont perdu). Bien sûr, XSLT a son prix, aussi, car c'est un langage étrange et pervers, mais j'espère que les bénéfices dépassent les coûts.

Une autre chose est que j'ai maintenant entièrement cessé de me préoccuper des navigateurs non conformes aux standards. C'est tout simplement trop pénible d'écrire la masse de bugware pour faire fonctionner le site sur des navigateurs aussi antiques et obsolètes que la version 4.x de Netscape Navigator / Communicator, ou Internet Explorer de Microsoft version 4 ou 5, surtout que j'emploie maintenant une architecture basée sur XML. Je recommande vivement à quiconque utilise ces navigateurs de passer à Mozilla, Konqueror, le browser Safari d'Apple, Netscape version 7.x, IE version 6.x, ou un semblable navigateur Web moderne. Pour ceux qui surfent en mode texte, Links devrait être un choix raisonnable, même si évidemment vous n'aurez pas tous les bonus d'un navigateur vraiment graphique (même si Links a maintenant une interface graphique, c'est une simple extension de son interface texte).

Mais assez de technicité ! Une autre question essentielle que j'ai dû résoudre est, quel langage devrais-je utiliser : soit l'anglais soit le français (il n'y a pas d'autre langage que je connaisse ne serait-ce qu'à peu près assez bien pour pouvoir écrire un log de ce genre dedans). Je me rappelle quotidiennement que mon anglais est loin d'être aussi bon que je le souhaiterais : même si certains essaient de me persuader du contraire, je ne suis pas dupe (et à ce stade-là je voudrais faire un petit clin d'œil à Pierre : salut, Pierre !). D'un autre côté, l'anglais a, disons, un meilleur taux d'audience que le français. Et quand j'y pense, il y a certaines choses que je dis plus confortablement en anglais, d'autres en français : je ferai donc ce qui s'impose, écrire certaines entrées an anglais et d'autres en français. Je traduirai rarement d'une langue à l'autre, cependant, parce que c'est beaucoup de boulot et j'y suis très mauvais ; cette entrée est une exception parce que c'est la première, et en quelque sorte l'introduction.

En tout cas, pour le meilleur ou pour le pire, ce 'blog est commencé (peut-être va-t-il se terminer en queue de poisson après trois entrées, ça ne me surprendrait pas énormément, me connaissant comme le flemmard que je suis). Le premier mai semblait un moment approprié pour le faire ; il y a ce proverbe en mai, fais ce qu'il te plaît, et ça me plaisait. Avez-vous remarqué que le tiers de la décennie (je veux dire, les années 2000, les années de 2000 à 2009) est déjà passé ? Et le tiers de 2003, aussi. Quelque part, je trouve ça déprimant. J'en dirai plus un autre jour.

↑Entry #0001 [older| permalink|newer] / ↑Entrée #0001 [précédente| permalien|suivante] ↑


List of all categories / Liste de toutes les catégories: glf, math, phys, ego, html, gay, relig, philo, polit, lex, libri, lang, unicode, cinema, linux, comp-hw, econom, auto-moto, gardinia, meta

[Index of all entries / Index de toutes les entréesLatest entries / Dernières entréesXML (RSS 1.0) • Recent comments / Commentaires récents]