Dr Clèm's Blog

A-t-on déjà eu un président de gauche en France ?

Tuesday Aug 18, 2020 20:25

En regardant la liste des président sous la Cinquième République, je me demande si nous avons déjà eu un président de gauche. Le seul président pouvant potentiellement être considéré de gauche est François Mitterrand. Cependant, lorsque je me renseigne sur le ≪tournant de la rigueur≫, je me demande comment une personne de gauche a pu mettre ça en place.

En regardant la liste complète, je remarque Vincent Auriol de la Section française de l'Internationale ouvrière, mais je reste partagé compte tenu de la Guerre d'Indochine.

Finalement, j'ai l'impression que la seule période où la gauche a été au pouvoir en France a été au moment du Front populaire.

Se faire soigner en France

Tuesday Aug 18, 2020 14:35

Je souffre depuis début 2018 d'un conflit fémoro-acétabulaire. Il m'aura fallu plusieurs années pour avoir un accès pariel à des soins en passant par le secteur privé car le secteur public ne peut pas répondre à la demande. Voici comment mon histoire depuis les premières douleurs.

La lourde administrative

La sécurité sociale en France est un système inégalitaire où chacun se bat pour sa part. En effet, en fonction de son régime, nos droits ne sont pas les mêmes. J'ai été rattaché à la Mutuelle générale de l'Éducation nationale (MGEN) pendant plusieurs années. Lorsque me situation changeât, en février 2018, en trouvant un contrat de travail à durée indéterminée (CDI) dans le secteur privé, j'ai dû changer de régime pour passer au régime général. J'ai beaucoup perdu. En effet, la MGEN fut épargnée par la réforme de 2004 de la sécurité sociale sur l'autorisation de remboursement intégrale des consultations, dite contrat ≪responsable≫, qui n'a rien de responsable car empêche les plus démunis d’accéder aux soins. D'autre part, la MGEN n'est pas restée coincée dans un puits temporel datant d'avant l'existence de l'Internet. Donc, pendant mes années de rattachement chez eux, et grâce à la complémentaire santé, je pouvais consulter un professionnel de santé, donner ma carte vitale et repartir sans payé et sans avoir de dette. Avec le régime général, c'est une toute autre histoire. Interdiction de remboursement intégral des actes de santé, ce qui veut dire que si je sors de l’hôpital sans rien payé, je dois tout de même de l'argent au régime général. Il est désormais à ma charge d'avancer les frais des actes de soins. Il y a aussi des délais de traitement de leur part, ce qui implique en plus du délais de remboursement de la part du régime général, un délais pour le remboursement de la part de la complémentaire santé.

Rattachement au régime général

Encore faut il se faire rembourser. En effet, le rattachement au régime général peut prendre 25 mois. C'est le cas en Isère. Cela a pris 13 mois dans mon cas. Pendant ces années, pas de remboursement. Il faut faire des fiches de soins. Celles-ci expirant après deux ans, à partir du moment où la caisse primaire d'assurance maladie met plus de deux ans à faire son travail, certains soins ne sont plus remboursables.

Le fait que cela prenne au tant de temps en Isère est simplement car cette caisse ne fait pas son travail. En effet, comme les processus de traitement n'ont pas été informatisé, le premier ordinateur datant pourtant de 1937, il serait judicieux de leur part de s'y mettre, il est impossible d’effectuer des démarche en ligne, ni d'avoir un suivi. Sans même compté les courriers perdus par La Poste, la caisse de l'Isère perdra votre dossier en moyenne une à deux fois. Si le courrier n'est pas perdu, les pièces justificatives seront perdues, ou refusées. Un exemple de situation qui n'est pas gérée par la caisse de l'Isère, les personnes ayant plus d'un seul prénom. En effet, si vous avez deux prénoms, ou plus, les pièces justificatives ou autres documents seront refusées dans la moitié des cas si votre prénom d'usage n'est pas votre premier prénom ou si les pièces justificatives font apparaître tous vos prénoms. Par exemple, si trois feuilles de soins sont écrites par le même médecin avec strictement les mêmes informations sauf la date, l'une sera refusé avec comme justification Nous n'avons pas pu faire correspondre le nom du bénéficiaire des soins avec le numéro de sécurité sociale, alors qu'il n'y a eu aucun problème pour les autres. C'est donc un processus aléatoire. Cela montre qu'en plus d'une procédure qui ne fonctionne pas, les employés mettent de la mauvaise volonté dans leur travail. Enfin, la caisse de l'Isère ne gère pas les déménagements. Si vous déménagez dans la même ville au cours de votre rattachement, qui je le rappelle prends entre 13 et 25 mois, alors la demande de rattachement est considérée comme invalide.

Rattachement à la complémentaire santé

Nous sommes en mars 2019, après 13 mois, je suis enfin rattaché au régime général mais rien n'est fini. Il faut encore que je sois rattaché à la complémentaire santé, que je paie depuis le début de mon CDI. La complémentaire de mon entreprise était AXA. Pour faire court, ce sont des escrocs.

Il n'est pas possible de mettre à jour son régime sur leur interface web. J'envoie donc un formulaire de demande de changement de régime obligatoire. J'ai un accusé de réception de ma demande. N'ayant pas de réponse, je renouvelle ma demande par plusieurs moyens. À chaque fois, j'ai un accusé de réception. Je finis par contacter le service administratif de mon entreprise. AXA leur envoie un mail mensonger. Ils prétendent que je le les ai jamais contacté. Ils me demandent d'effectuer à nouveau les démarches, ce que je fais dans l'heure, à nouveau par plusieurs moyens avec accusés de réception. N'ayant toujours pas de réponse de leur part, mon entreprise étant démunie face à tant de mensonge et de mauvaise foi, celle-ci décide de passer par un courtier, 10 jours plus part, je suis rattaché à ma complémentaire. Cela fait 22 mois que toute cette histoire à commencer. Le mois suivant, mon entreprise résille son contrat avec AXA.

La télétransmission

Il reste encore un soucis, celui de la télétransmission. En effet, changer de complémentaire santé ne change pas la télétransmission. Ceci est d'une stupidité déconcertante. Demander la télétransmission à la nouvelle complémentaire n'est pas possible. En effet, il faut que ma précédente complémentaire, que j'ai alors résilié il y a de ça deux ans, la désactive. J'ai donc dû faire une demande à la MGEN de déconnexion de la télétransmission, puis attendre que cela soit pris en compte, puis faire la demande de télétransmission à ma nouvelle complémentaire. Tout cela est inutilement lourd, long et compliqué.

La caisse de l'Isère (bis)

Nous arrivons donc à janvier 2020, cela fait donc 23 mois que je cumule des fiches de soins. Cela fait 23 mois que je ne procède pas à tous les examens dont j'ai besoin pour comprendre d'où viennent mes douleurs, car à l'époque je n'avais pas de diagnostique sur l'origine de ces dernières, parfois aiguës, qui procurent des douleurs intenses la nuit, et m’empêchent de faire des actions simples comme lacer mes lacets car trop chers. J'ai déjà vu plusieurs médecins et chirurgiens mais ils étaient sans réponses et m'envoyaient vers d'autres spécialistes. Bref, ma situation semble en règle. J'envoie donc mes feuilles de soins à la caisse de l'Isère. Une partie de ceux-ci reçoivent la mention Hors parcours soin. En effet, entre ma première demande de rattachement et la régularisation de ma situation, j'ai déménagé, certes intra-muros, mais j'ai changé de médecin traitant. Donc toutes les consultations de mon ancien médecin traitant ne sont pas considérées comme faisant par du parcours de soins coordonnés, je n'ai donc pas été remboursé. De plus, contrairement à d'autres décisions du régime général, celle-ci ne peut pas être soumise à contestation.

Le CHU Grenoble Alpes (bis)

Dans mon post Le jour où l’hôpital public est devenu Aliexpress., j'ai commencé à raconter les absurdités administratives du CHU Grenoble Alpes. Pendant ces deux années de période de rattachement, j'ai dû me rendre à l'hôpital à plusieurs reprise, premièrement pour bursite à l’épaule droite en faisant du bloc, deuxièmement pour les premiers examens sur mes douleurs qui se sont avérées être le conflit fémoro-acétabulaire. Le service administratif a oublié d'enregistrer ma complémentaire santé. N'en ayant pas d'enregistré, au lieu de réagir humainement, décemment, solidairement, en me contactant pour que je leur fournisse les informations manquantes, le CHU Grenoble Alpes n'a pas transmis la demande de remboursement au régime général, mais m'a envoyé la facture de l'intégralité des soins. Je les ai donc payés. À ce jour, je n'ai pas pu me faire rembourser et il n'y a pas de mécanisme pour que soit un jour le cas.

La lourdeur administrative a seul but de lourdeur administrative

Le régime général est conscient de ma complémentaire santé. La télétransmission est activée. Pourquoi y a-t-il besoin que je donne ma carte de mutuelle à chaque fois à tout le monde alors qu'il est possible de tout transmettre avec la carte vitale ? C'est à nouveau une technique pour éviter les remboursements de soins car d'une part, il peut être possible d'oublier cette carte, changeant tous les 6 mois, il peut arriver qu'on ait oublié de prendre la nouvelle. De cette manière, dès qu'il y a une erreur, c'est la victime qui paie, ce qui est habitude française dont ceux qui ont déjà eu à faire à la police comprennent de quoi je parle. C'est un peu comme se rendre au commissariat.

La préparation de l'intervention

23 mois et je peux enfin contacter plus sereinement le spécialiste qui devrait être en mesure de m'apporter au moins des réponses. J’appelle donc son secrétariat, au CHU Grenoble Alpes, qui me dit Si vous voulez un rendez-vous dans un délais raisonnable, il faut passer par son cabinet privé, par contre, ça ne sera pas un tarif conventionné. Des années de souffrances, je n'en peux plus, je veux que cela se termine vite, tant pis si je paie. Je demande donc D'accord. Pouvez-vous me donner le numéro de téléphone et l'adresse, s'il vous plaît ?. La réponse de la secrétaire Ne vous inquiétez pas, c'est ici aussi. J'appelle donc l'hôpital public qui me dit qu'il n'y a pas de rendez-vous disponible dans un temps raisonnable. Ce qui veut dire que l'accès aux soins en France est difficile. Cet échange montre aussi qu'il faut avoir les moyens financiers de payer pour ses soins car il n'y a pas de disponibilité em secteur 1. On peut voir, une fois de plus, que l'accès aux soins n'est pas gratuit en France. Ce qui est aussi choquant, c'est un professeur puisse utiliser les ressources de l'hôpital à des fins d'enrichissement personnel et ceci au détriment des patients car en effet, son cabinet privé empiète tellement sur ses fonctions à l'hôpital public, que l'hôpital ne peut plus remplir ses fonctions et fournir un accès aux soins aux plus démunis.

Finalement, après tout ce temps, à force de recherche, je finis par poser un diagnostique : le conflit fémoro-acétabualiaire. J'ai pu procéder à un diagnostique physiologique par mes propres moyens. Il y a une explication à l'émergence de ce conflit avec entre autres 10ans de karaté, sport intense avec notamment la participation et la préparation à la MB Ultra Somfy, épreuve de la MB race et du bloc. Une visite chez le chirurgien orthopédique confirme le diagnostique.

La pharmacie

Mon hospitalisation est enfin planifiée pour le 26 mars. Je reçois une partie des ordonnances. Je m'empresse donc d'aller chercher ce qui m'est prescrit avant l'opération pour ne pas avoir à m'en préoccuper après. La pharmacienne voyant que j'allais devoir vider ses stocks n'a pas été enthousiaste à l'idée de me servir. C'est pourtant son travail. Ce n'est pas de ma faute. Ça lui rapporte de l'argent. En voyant les ordonnances, elle me demande je vous en mets combien ? J'avoue avoir été déconcerté par la question. Je voulais demander si je m'étais trompé et si je n'étais pas à la boulangerie, mais finalement, j'ai simplement répondu ce que son bon sens aurait dû lui dicter
ce qu'il y a sur l'ordonnance.
Vous pensez avoir beaucoup mal ? Est-ce que je ne peux vous en mettre qu'une partie ?
Je n'ai pas l'habitude de me faire opérer de la hanche, dans le doute, pouvez-vous me donner ce qui est prescrit, s'il vous plaît ?
Honnêtement, je ne suis pas certain d'avoir dit s'il vous plaît, je commençais à être agacé.
Non mais parce que vous comprenez, ça va vider mon stock, après, je vais devoir en recommander
Oui, en même temps, c'est ton job. Tu es commerçante et ça t'emmerde de servir. Ça t'emmerde de me vendre un produit pour avoir de l'argent.
Je ne sais pas pas à quel point je vais avoir mal. C'est ma première opération de la hanche. Si on m'a prescrit autant d'anti douleur, c'est certainement pour une bonne raison. Merci de me donner ce qu'il y a sur l'ordonnance.
Tout d'un coup, elle n'avait plus suffisamment de stock pour me fournir sur l'ordonnance. Je lui dis que ce n'était pas grave et qu'elle pouvait déjà me donner ce qu'elle avait et que je reviendrai prendre le reste plus tard. Évidemment, après une telle expérience, je n'y retournerai pas. Je préfère aller un peu plus loin.

Entre le moment où j'ai écrit ce dernier paragraphe et aujourd'hui, la douleur est tellement intense que je n'ai pas pu aller plus loin et je suis retourné dans cette pharmacie.

Ce n'est pas ma première mauvaise expérience avec une pharmacie à Grenoble. On a déjà refusé de me servir car la pharmacienne avait peur de ne pas être dédommagée par la caisse de l'Isère pendant que mon dossier était en cours de traitement.

La caisse de l'Isère (ter)

En plus de mes ordonnances, j'ai aussi un arrêt de travail de 6 semaines. Dans la même optique que pour les médicaments, j'ai envoyé mon arrêt de travail en avance. En effet, après une telle opération et dans l'incapacité de me déplacer, je voulais que tout soit réglé avant. Ce fut une grosse erreur. On a toujours tendance à sous estimer la bêtise administrative française. Il est interdit de prescrire un arrêt de travail en avance. Aller dire ça a des étrangers, ils vont vous regarder avec des grands yeux et vous demandez pourquoi ? La réponse, sans aucune raison. Si, pour faire payer la victime une fois de plus. Tu as un problème de santé. Cela veut dire que tu profites du système. Tu dois souffrir pour avoir le droit à toucher une compensation salariale.

Pour me prévenir d'une décision aussi importe que vous ne serez pas payé pendant 6 semaines, le papier, si cher habituellement à la caisse de l'Isère, a disparu. Je n'ai même pas reçu d'email. J'ai uniquement reçu une notification.

Un document important lié à la gestion de votre dossier est disponible dans votre compte ameli.
Consultez dès maintenant la messagerie de votre compte ameli en cliquant ici ou depuis l'application pour smartphone ou tablette.
Avec toute mon attention,
votre correspondant de l'Assurance Maladie.

Le document en question tient en une phrase. Nous ne pouvons pas enregistrer votre arrêt de travail car il a été établi par anticipation, période du 26 03 2020 au 06 05 2020. Le document contient une formule de politesse appropriée, probablement sarcastique. Avec toute mon attention,
Madame X X
votre correspondant de l'Assurance Maladie

Je note l'absence d'accord du genre.

La décision de ne pas verser 6 semaines de salaire mérite un courrier. Mais non, la caisse de l'Isère aime en recevoir, mais pas en envoyer. Pour preuve, il n'est pas possible de contester cette décision par email, c'est pourtant par ce moyen que m'a été communiqué cette décision. Par contre, un courrier, oui. Vous pouvez toutefois contester l’interprétation de cette décision dans un délai de deux mois à compter de la réception de cette lettre. Pour cela, adressez un courrier à la commission de recours amiable, en indiquant les motifs de votre contestation. Pensez à joindre les justificatifs en votre possession et une copie de ce courrier.

On notera à nouveau que j'ai reçu un message sur le site web d'ameli, mais il est à ma charge de l'imprimer.

Kinésithérapeute

Cette opération nécessite beaucoup de rééducation avec notamment 5 séances hebdomadaire de kinésithérapeute par semaine à domicile, en plus d'autres exercices, dont certains requièrent de l'équipement.
Premièrement, cela demande environ 300€ d'équipement qui n'est pas remboursé par le régime général. Si vous êtes au revenu de solidarité active, vous ne pourrez vous le permettre.
Deuxièmement, probablement compte tenu de la petite taille de Grenoble-Alpes Métropole, en franglais car c'est plus classe, mais aussi de la mauvaise volonté de la plus part des praticiens, il est impossible de trouver 5 séances hebdomadaire à domicile. Une des raisons est que très peu de cabinets sont ouverts 5 jours par semaines. Une autre raison est que les praticiens se déplaçant restent dans un périmètre de moins de 500m. Étant à plus de 500m de tous les cabinets de kinésithérapeute, cela est impossible. J'ai contacté l'ensemble des kinésithérapeutes de Grenoble, Saint-Martin-le-Vinoux et Échirolles, secteur 1 et 2, sans succès, trop loin, pas de place, pas à domicile, pas plus de 3 séances par semaine, etc.

J'ai eu des réponses du type Vous habitez à 500m, c'est trop loin pour moi à vélo. Est-ce que vous pouvez venir en béquille ? Donc, d'après ce kinésithérapeute, 500m en béquille, ce qui n'est pas possible après une opération de la hanche est plus envisageable que 500m à vélo. Non, merci. Qu'on ne vienne pas me dire qu'il n'y a pas de mauvaise volonté la dedans.

Une autre réponse de la part de quelqu'un qui voulait faire son pain mais qui ne pouvait venir que 3 jours par semaine. Le conflit machin chose, je ne connais pas, mais je suis sûr que 5 séances par semaine c'est trop. Si tu ne connais pas la pathologie, n'a jamais entendu parlé de l'opération, fémoroplastie sous arthroscopie, comment peux-tu dire que ce que le chirurgien expert prescrit trop ?

Au final, je n'ai pas trouvé. Il n'est pas possible en vivant dans les quartiers résidentiels de Grenoble, d'avoir accès aux soins.
Heureusement, une personne finit par me recontacter. Elle a un cabinet loin, mais je suis sur son chemin, donc elle peut passer avant d'y aller 4 fois par semaines. 4 fois, ce n'est pas 5, mais c'est le mieux que l'on m'est proposé. Je réponds oui tout de suite, à moitié soulager d'en avoir fini avec des jours complets de recherche.

Lorsque j'ai parlé de cette difficulté avec une infirmière à domicile, celle-ci m'a répondu les médecins ne se rendent pas compte. Ils prescrivent trop. Ce à quoi j'ai répondu que le problème n'est peut-être pas qu'ils prescrivent trop, mais qu'il n'y a pas assez de praticiens. Lorsqu'elle a vu mon ordonnance pour les pansements, elle a dit ces médecins, ils ne prescrivent jamais assez. Elle m'a ensuite fait part des difficultés de son cabinets à gérer le trop grand nombre de patients et qu'ils ont un rayons trop étendu pour ne pas laisser les personnes sans soins. Encore une fois, cela montre bien que le problème n'est pas trop de prescription, mais pas assez de personnel. Je tiens tout de même à remercier ce cabinet d'infirmier qui s'est déplacé plus loin que son rayon d'action normal.

Coronavirus

Le dernier paragraphe s'est déroulé après mon opération, revenons donc à la décision de la caisse de l'Isère sur mon arrête de travail. Nous sommes le 24 mars. Je viens de recevoir la notification de l'Assurance Maladie. Mon arrêt de travail est refusé l'avant veille de mon opération. Que faire ? Je reçois alors un coup de fil de l'hôpital. Mon opération est reportée jusqu'à une date indéterminée à cause du coronavirus. À ce moment là, on ne parle pas encore de covid-19. Enfin, j'ai du répit pour régler cette situation. Je me demande sincèrement comment j'aurai pu m'en sortir en si peu de temps. Encore une fois, cette restriction sur le fait qu'en France, il soit interdit d'émettre des arrêts de travail anticipés est tout à fait absurde.

Aujourd'hui

Aujourd'hui, j'ai mal. Il y a des jours plus difficiles que d'autres, c'est une des raisons de l'aspect ponctuel des mes notes de blog. Je ne peux écrire que les bons jours. Il m'a donc fallut trois jours juste pour écrire ces quelques lignes, grâce à la prise d'opium. Cela fait plus d'un mois que j'ai été opéré et je dois encore prendre des anti-douleurs pour marcher. Il ne m'aurait pas été possible de me déplacer chez un kinésithérapeute juste après l'opération.

Kinésithérapeute

Il y a 12 jours, la kinésithérapeute qui me suivait m'annonça qu'elle ne pouvait plus me suivre à partir du 17 août. Je savais qu'il m'est impossible de trouver quelqu'un pour venir à domicile. Je suis parti résigné dès le départ en rappelant la même liste qu'auparavant. Je suis à nouveau tomber sur une nouvelle personne me disant que ça ne sert à rien d'avoir autant de séances, bien qu'elle ne connaissait ni ma pathologie, ni l'intervention chirurgicale. Les personnes qui me proposait cinq séances au cabinet, ne m'en propose plus qu'une ou deux lorsque vient le moment de prendre les rendez-vous. Cela m'est arrivé trois fois. Je ne comprends vraiment pas pourquoi les kinésithérapeutes ne veulent pas prendre en charge correctement un patient. J'ai trouvé un cabinet me proposant à nouveau cinq séances par semaine, me disant que l'on combinerait deux praticiens pour faire les cinq séances. Encore une fois, au moment de faire le planning des séances, elle ne m'en propose plus que quatre. C'est mieux que les autres, mais je ne comprends toujours pas pourquoi ils refusent de me faire toutes mes séances. Je suis déjà en train de regarder des kinésithérapeutes à 4km de chez moi. J'abandonne. Encore une fois, je ne serai pas bien pris en charge et pour un effort important. 4km pour me rendre au cabinet après une fémoroplastie alors que je suis encore en arrêt de travail, plus 4km pour revenir chez moi. Non, je n'ai pas de voiture. Non, personne ne peut m'emmener car mes amis n'ont soit pas de voiture, soit ils travaillent. Non, je ne peux pas prendre les transport en commun, le tramway est à 2km de chez moi, ça ne vaut pas le coup.

Arrêt de travail

Lorsque l'hôpital à annuler mon rendez-vous avec le chirurgien pour le remplacer par un autre, ils n'ont pas modifié mon arrêt de travail pour que la période de ce dernier couvre au moins jusqu'à ce que puisse voir un chirurgien avant ma reprise. Il ne me paraît pas acceptable d'avoir à voir un médecin pour que celui-ci le prolonge, et donc payer une part non remboursable car l'hôpital, une fois de plus, n'a pas fait son travail. Heureusement, en appelant plusieurs fois, différents services, j'ai fini par trouver une personne qui fait son travail et m'a fait une prolongation de mon arrêt de travail jusqu'à ce que je puisse voir un chirurgien.

Conclusion

Une partie de ces mésaventures font parti d'un schéma pour décourager les français l'accès aux soins. Ce que nos gouvernements appelle être responsable. L'accès aux soins est payant et difficile. Il n'est pas possible de recevoir des soins adéquates si l'on ne vit pas dans une métropole. Le système de santé en France est truffé d'absurdité, de lourdeur administrative et de latence. Il ne permet pas une prise en charge correcte d'un patient, notamment pour une guérison suite à l'intervention. De même, pour les soins post-opératoires, la lourdeur administrative de base, plus celle qui s'ajoute dû aux erreurs administratives systématiques, ne permet pas de se concentrer sur sa guérison.

How to fix a broken LXD server due to fail snap auto-refresh

Sunday Aug 16, 2020 15:37, last edition on Sunday Aug 16, 2020 15:42

For my Linux containers, I am using LXD. The recommended way to install LXD is Snap, which updates daily. Few days ago, the last release of LXD has been released and the update started automatically. For the next two following days, I experienced timeout on my virtual servers. I also noticed at lot of input/output (I/O) on the hard drives. I started to investigate. I identified, using Htop among other tools like Netdata, that the process snapd, from Snap, was using 100% of the hard drives and all the I/O were on the /var/ partition. Using the command snap watch --last auto-refresh, I saw that the update stated more than two days ago and was stuck at the step Copy snap "lxd" data. I aborted the ongoing procedure but I ended up with a completely broken LXD. Hopefully, on Linux Containers forum, I found someone with the same, or at least similar enough, issue.

You can try to automate snap in offline mode. Make sure your host is not connected to the internet. This is definitely recommended for hypervisors and therefore also the LXD hosts. (my opinion for LXD hosts)

Download snap somewhere else with:
snap download lxd

Copy the files to your LXD node and install the snap:
snap ack <package.assert>
snap install <package.snap>

Linux Containers

It saved my day! At least, what was left ot it. It is at least the second time that this issue happens to me and it appears to impact other user. Unfortunately, it is a sign that LXD is not ready for production environment which requires stability. It is also a reminder that I need to find a way to backup LXD.

Taille d'une image, et plus, en ligne de commande

Thursday Jul 30, 2020 14:02

Je viens de découvrir la commande file. Celle-ci permet d'obtenir des informations rudimentaires sur un fichier. Par exemple

% file template-xenial.cfg template-xenial.cfg: ASCII text
Pour les images PNG, cette commande retourne notamment le nombre de pixels dans chaque direction
% file firefox.svg.png
firefox.svg.png: PNG image data, 2000 x 3135, 8-bit/color RGBA, non-interlaced
J'essayerai d'utiliser cette commande pour créer les champs Open Graph protocol de mes notes de blog.

Activer le plugin IPv6 dans AWStats

Tuesday Jul 28, 2020 15:46, last edition on Tuesday Jul 28, 2020 15:51

Dans AWStats, si à l’exécution de

/usr/lib/cgi-bin/awstats.pl -config=domain.tld -update
vous avez des retours sur l'impossibilité d'effectuer la résolution DNS inverse des IPv6, cela veut dire que le plugin IPv6 n'est pas activé. Ce plugin dépend de deux modules, Net::IP and Net::DNS. Sur Ubuntu, il est possible des les installer avec APT
% apt install libnet-ip-perl libnet-dns-perl
Pour activer le plugin avec Vim, vous devez ouvrir le fichier de configuration du virtual host /etc/awstats/awstats.domain.tld.conf et entrer la commande
:%s/#LoadPlugin="ipv6"/LoadPlugin="ipv6"/
La commande
/usr/lib/cgi-bin/awstats.pl -config=domain.tld -update
devrait normalement s’exécuter normalement.

Vim : Ajouter en fin de ligne et utiliser le texte yanked dans une commande

Tuesday Jul 28, 2020 12:02

Je vous présente deux petites astuces avec Vim.

Ajouter en fin de ligne

Pour ajouter en fin de ligne, il suffit de remplacer $, qui signifie fin de ligne, par ce que vous voulez ajouter. Je l'utilise pour écrire sur ce blog, par exemple pour ajouter des balises <br> lorsque je copie colle de longues sorties de terminal. Par exemple

:%s/$/a/
Ajoutera a à la fin, $ de chaque ligne du fichier, %.

utiliser le texte yanked dans une commande

Lorsque l'on cherche à faire des substitution ou lorsque l'on veut chercher un élément assez long, il arrive fréquemment qu'il soit pratique de copier coller le texte depuis la zone de texte vers l'interface en ligne de commande. Pour réaliser cette action, il faut yank le texte, rentrer de commencer à écrire sa commande avec :, puis pour coller, put, il faut faire Ctrl+R puis ".

Apache HTTP Server ne renvoie pas le bon certificat à OpenSSL

Tuesday Jul 28, 2020 10:07

J'ai utilisé OpenSSL pour vérifier le certificat de ce site fonctionnant avec Apache HTTP Server et j'ai obtenu des résultats aléatoires.

% openssl s_client -connect clementfevrier.fr:443
CONNECTED(00000005)
depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
verify return:1
depth=0 CN = clementfevrier.fr
verify return:1
---
Certificate chain
0 s:CN = clementfevrier.fr
i:C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
1 s:C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
i:O = Digital Signature Trust Co., CN = DST Root CA X3
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIGbzCCBVegAwIBAgISA5hZCLbOyHsuTxNLqVmT2Ux+MA0GCSqGSIb3DQEBCwUA
MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0yMDA2MTAwOTA3MjBaFw0y
MDA5MDgwOTA3MjBaMBwxGjAYBgNVBAMTEWNsZW1lbnRmZXZyaWVyLmZyMIICIjAN
BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAt6arsvarIBaP0LmwOYpg3J2sFH69
g23kgUXPHEg+icDl16O0yLsNZy/3OmnBS+pL1ZXT1IyfX7YC6GwOYWoBb8dfwS6V
TncKhtwTPG28FJSuXezMlcjCOSdq0cxyrmt4SHajdeaaNNGPRqRjsOAtYT1KMsTM
FhxfSAT+gbSA0iqY632m22329P3OEVpjbBgkNAXE3Nv5x5AqIrAK+GsppX2A8wr0
a5n3sF0fYb8byCoaCwVvV1Bgwa20adJHUjCTBSYOoGR1wpo3LDys/GATLAUfYSOy
bSzTP4b8DWAxspFDcm0aQuO9/PzYlOP+jeq6ShYM+3OybQe/yrmvEpckX2Jz00O/
5mx0nJLd77jaBNkC02hEdL0z5G59qq4G/mgm2em4tjHk8wvPuQ8yohnLr0lk7BPZ
bedEyFb6OM8WJYufBaR/wqo31VTRzUGzNwXJqzzVW2yZUrcYKF3/nAfhq3fivPNx
J2CqpSE7wopf1jJ2lkKITlAJXGXAnePwDpMxx1DEofhLnxvAE1xWlb81qSuyKlAQ
V2jiwflvFUoY0Y1cGJyINBzLuMBiSSJtTlpELGxw7zbQKTdWQizQxL5YEcq0zCoj
KnZMlmYD79JKQ5HfCIv6kPjyllh/r6DVS6WuKd/B0YaRoU6H+9jkb+CE3I2QU0OV
VtCIq8K5zRmJrGkCAwEAAaOCAnswggJ3MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUE
FjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU
L8eqTvf8KwSRnt5TaPS1y2vuufEwHwYDVR0jBBgwFoAUqEpqYwR93brm0Tm3pkVl
7/Oo7KEwbwYIKwYBBQUHAQEEYzBhMC4GCCsGAQUFBzABhiJodHRwOi8vb2NzcC5p
bnQteDMubGV0c2VuY3J5cHQub3JnMC8GCCsGAQUFBzAChiNodHRwOi8vY2VydC5p
bnQteDMubGV0c2VuY3J5cHQub3JnLzAxBgNVHREEKjAoghMqLmNsZW1lbnRmZXZy
aWVyLmZyghFjbGVtZW50ZmV2cmllci5mcjBMBgNVHSAERTBDMAgGBmeBDAECATA3
BgsrBgEEAYLfEwEBATAoMCYGCCsGAQUFBwIBFhpodHRwOi8vY3BzLmxldHNlbmNy
eXB0Lm9yZzCCAQQGCisGAQQB1nkCBAIEgfUEgfIA8AB1ALIeBcyLos2KIE6HZvkr
uYolIGdr2vpw57JJUy3vi5BeAAABcp2yzLwAAAQDAEYwRAIgaR2cyhJ0XGOo6t5j
ONvKPspMdGAp9wFf3mGj4kfAN10CIBdLdswoMfdwZ/qveOJjpLJiTRjq8LeTZzMv
UZZUwBX3AHcAb1N2rDHwMRnYmQCkURX/dxUcEdkCwQApBo2yCJo32RMAAAFynbLM
5gAABAMASDBGAiEAu3mmQ6lFg6EvA32qSvRNRoXhviRmb1cYJNi2gqn0ShICIQDR
UvdT/vhSgH7O3B8L+TkGKyHwWibis3FpdrkEH1MERDANBgkqhkiG9w0BAQsFAAOC
AQEAgOfa0V7+sn2WULujrQy3Ob837nV+oMDmQgv59SKUR9aOxU3CBAcGsXOXzS6Z
aY1AUFT9b8D4YKNCjVi/0jruEXNGEk49IviHmU+7r2blf2MuvQfoQIABjGUvKH5+
u2dP+8Y+kqwfZc/lZ04KjMCJv1+osQMzBHhzz5HQ9SR+XgBG+Ah+5XxClfzm1odu
1IGWDrC7qDzv4leqWk69uazZLjEPWDxodFsgPAlviCnYBT1Q58x8UcOoqbRVT6Fo
3Gyi0wUeMG3wx4bbzhLKpeyJEd9BxX0U1MMR3moublihWvnIh06OXday6QjxWR/r
bYOkfH/5V04jDm8tSnC3lK9C/Q==
-----END CERTIFICATE-----
subject=CN = clementfevrier.fr

issuer=C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3

---
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: RSA-PSS
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 3646 bytes and written 399 bytes
Verification: OK
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Server public key is 4096 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
---
---
Post-Handshake New Session Ticket arrived:
SSL-Session:
Protocol : TLSv1.3
Cipher : TLS_AES_256_GCM_SHA384
Session-ID: EA567A55348D38DEC3BBB7414AB1B3B38A7E4FEFA0AA8FB0468E97650F359FC0
Session-ID-ctx:
Resumption PSK: E335C79A8C6F1F18480760304163359F1E741208AACF26D94CF49B88B87541BA0DE9592D89D2091B90C08134EDD4D6AF
PSK identity: None
PSK identity hint: None
SRP username: None
TLS session ticket lifetime hint: 300 (seconds)
TLS session ticket:
0000 - 7c 56 31 2e 2c 34 71 38-1a d8 ab 01 6c 69 0a 58 |V1.,4q8....li.X
0010 - 69 62 0c 1b 33 4f ab 0a-4e aa b6 5a 3f f5 d6 bb ib..3O..N..Z?...
0020 - 73 b8 d0 8a ff f6 9c 38-fc 31 a2 da 4a 25 62 9b s......8.1..J%b.
0030 - e9 9f 09 04 7b cd 24 71-01 42 76 d2 3d 00 e5 1b ....{.$q.Bv.=...
0040 - ff 45 ab 98 41 60 2f e2-ee d5 25 5d 69 1c 89 01 .E..A`/...%]i...
0050 - 13 ec 1a 72 b7 e0 3b 9d-51 d7 87 31 6c 89 b4 a5 ...r..;.Q..1l...
0060 - eb c4 44 83 e3 99 06 2c-e8 c1 d1 a6 e1 d2 4d 19 ..D....,......M.
0070 - 69 7e 6d 62 c7 b6 00 b5-f7 e6 ae 6e 69 bf bb 90 i~mb.......ni...
0080 - 43 87 7a be 00 75 8f 24-cb 01 17 cb fb f9 35 71 C.z..u.$......5q
0090 - fa 73 57 f9 28 cb 16 86-91 a4 14 58 cb 25 49 cf .sW.(......X.%I.
00a0 - d4 e8 2a 6a 3b 94 0b 08-72 a0 3e 2a 8c cd ff 39 ..*j;...r.>*...9
00b0 - 59 36 52 97 2c c7 2f 92-ce 99 8d 8b 24 3d 14 fc Y6R.,./.....$=..
00c0 - 2b 6e 83 07 6e da 57 35-31 c9 35 fd 53 4f 5d af +n..n.W51.5.SO].
00d0 - 4a 01 ce c5 b7 7a 3b 13-e5 b0 7a 3f 14 d1 ba f4 J....z;...z?....
00e0 - 88 9f dd 09 20 6c 76 d6-69 88 e9 6b 78 8b b3 36 .... lv.i..kx..6
00f0 - fe 04 38 bd ea 30 16 c0-b8 37 6a 5e db a5 1c 19 ..8..0...7j^....

Start Time: 1595887003
Timeout : 7200 (sec)
Verify return code: 0 (ok)
Extended master secret: no
Max Early Data: 0
---
read R BLOCK
---
Post-Handshake New Session Ticket arrived:
SSL-Session:
Protocol : TLSv1.3
Cipher : TLS_AES_256_GCM_SHA384
Session-ID: EDFE0B9061C93DC3C98510117D0A9824979A4423673597A76D1D10AF97969726
Session-ID-ctx:
Resumption PSK: 620FE5C493BD46AC848548F637F1FE74F2A2FF44449BAA785E4F7EEE12393FBA9533805DA1B41835F3BF1A2E232EC212
PSK identity: None
PSK identity hint: None
SRP username: None
TLS session ticket lifetime hint: 300 (seconds)
TLS session ticket:
0000 - 7c 56 31 2e 2c 34 71 38-1a d8 ab 01 6c 69 0a 58 |V1.,4q8....li.X
0010 - 95 68 d7 b3 f6 39 18 5c-36 53 f4 ef 1a dc 3a 8e .h...9.\6S....:.
0020 - 92 9b 96 4d 35 4e dc f7-1a 4c 6e 69 9b 51 cb 98 ...M5N...Lni.Q..
0030 - b9 d4 e0 bb 18 db 2c 2e-46 14 14 e2 98 73 2f a4 ......,.F....s/.
0040 - 40 55 e9 7a 59 fb 26 70-09 03 cd 41 0d 16 ce 43 @U.zY.&p...A...C
0050 - 2d 63 9d 3f 2a 52 3f d9-e3 d0 c8 b8 5a bf 9d ba -c.?*R?.....Z...
0060 - c9 e3 f3 1f 40 ba 91 c5-84 eb 57 d5 e3 51 62 1e ....@.....W..Qb.
0070 - 3c c6 65 6d 98 2e f4 f7-87 75 c3 37 f1 ae 7a 9f <.em.....u.7..z.
0080 - 85 a6 91 58 ec fc 68 7f-81 18 0b da ee 19 ab aa ...X..h.........
0090 - c9 88 d1 39 d6 7a de 21-53 8b b1 b0 9d 1d 4d ce ...9.z.!S.....M.
00a0 - a6 e9 98 79 74 75 fd eb-06 f2 60 b7 35 c7 ff d6 ...ytu....`.5...
00b0 - 0b 26 32 da c8 b1 8f e5-ec da c7 59 90 3f 47 9a .&2........Y.?G.
00c0 - fb ef 0d a8 f8 75 0a cb-f1 ea b9 24 bb cc 5a 27 .....u.....$..Z'
00d0 - f0 41 be 36 11 b3 cf e7-cd a2 a2 95 49 23 f0 f6 .A.6........I#..
00e0 - 79 40 3a b2 a7 81 ff cf-0b 35 10 32 0d b1 3e e9 y@:......5.2..>.
00f0 - 73 8a c1 6f 27 8e 96 53-3d 8d 12 7d 45 94 18 3c s..o'..S=..}E..<

Start Time: 1595887003
Timeout : 7200 (sec)
Verify return code: 0 (ok)
Extended master secret: no
Max Early Data: 0
---
read R BLOCK
closed
% openssl s_client -connect clementfevrier.fr:443
CONNECTED(00000003)
depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
verify return:1
depth=0 CN = forumanalogue.fr
verify return:1
---
Certificate chain
0 s:/CN=forumanalogue.fr
i:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
1 s:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
i:/O=Digital Signature Trust Co./CN=DST Root CA X3
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIGbjCCBVagAwIBAgISBJpK5d6fFdQjt8g9YwVRHQi4MA0GCSqGSIb3DQEBCwUA
MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0yMDA2MTAwODUzMjNaFw0y
MDA5MDgwODUzMjNaMBsxGTAXBgNVBAMTEGZvcnVtYW5hbG9ndWUuZnIwggIiMA0G
CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2r4Xal8UI93cg0paqi2E185pfodRr
iMrLlqPq80XV0fttsCLsoASmKCB/XMb1dTNYwDc1sm5js0I4la2boBeN+qnlNda0
bs3ycH7tClM7mKKl3puDpl2YTTlfcBlXq21/l2bLt3peX6DjrOl4a2TLf51pqgea
NaKHLJva6k2wyDxUEHsFmNfw3oCJZaIy27VV+UcfJOtsw8UoaP1N9JTvHBdjZQUn
awNaHNuWaxG0IWyljmNtZJIrn2oGq5H9jHirC3KEg3X6D0l3SlO5PA5AZCUg0wlY
i65tVt4Hd319yD+etMiDcLZyGcN6dscYYwV2NZe9mSiY2OYAOwia5GIiBO7WOjxB
GYWH7jI1nyLZa1N/lozW/084o61W02Q76fiU20CBcQC20CaNZ6uKhXawc3KhMMnC
ZfkWA0/U+nJLu9sGYLvnaOdKEpFtBjHEB9nY2MZ75C8IpT/dM5OOkWDju7BasN1U
YqoB2L+Tb93QAioCXsmdkajUdM05n4RJcs2gFzeB+0ip661/IoeQhTzyprpW6++C
Z2HyrSDyvMaEtP3dQjmpi4CW8JBJhzj0671zhOdvIZVETo3LmDGOw2m68lc5ZVHU
RNt9e4fJHChaCIs9e6NP+cEOvJMSVbqG3g5EgiHN8rNc374B+uWTlIinhXJ2ngqI
iLCpBs8MnxWhvQIDAQABo4ICezCCAncwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQW
MBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBTf
ZuBN3lyieTg9hUMHchYLipExyjAfBgNVHSMEGDAWgBSoSmpjBH3duubRObemRWXv
86jsoTBvBggrBgEFBQcBAQRjMGEwLgYIKwYBBQUHMAGGImh0dHA6Ly9vY3NwLmlu
dC14My5sZXRzZW5jcnlwdC5vcmcwLwYIKwYBBQUHMAKGI2h0dHA6Ly9jZXJ0Lmlu
dC14My5sZXRzZW5jcnlwdC5vcmcvMC8GA1UdEQQoMCaCEiouZm9ydW1hbmFsb2d1
ZS5mcoIQZm9ydW1hbmFsb2d1ZS5mcjBMBgNVHSAERTBDMAgGBmeBDAECATA3Bgsr
BgEEAYLfEwEBATAoMCYGCCsGAQUFBwIBFhpodHRwOi8vY3BzLmxldHNlbmNyeXB0
Lm9yZzCCAQYGCisGAQQB1nkCBAIEgfcEgfQA8gB3AF6nc/nfVsDntTZIfdBJ4DJ6
kZoMhKESEoQYdZaBcUVYAAABcp2mB3kAAAQDAEgwRgIhAI8BZ9sHZfyfXvHrurVg
aey40vkWsPt+0yIguqz5R1qcAiEAhnowj6V6S8L7OK5o4XUiA9dSKuBtZgRapm8A
2rVUfnsAdwAHt1wb5X1o//Gwxh0jFce65ld8V5S3au68YToaadOiHAAAAXKdpgej
AAAEAwBIMEYCIQCgpRxyo7WgNIVorX4ZD0SmOTTbbPamr7iUtgwA0372OgIhALKP
4e969RZk9LfQnTpqYv6EzgxHeBqr38TltkNTnXngMA0GCSqGSIb3DQEBCwUAA4IB
AQBB6eZGn/iEFiNxdEMD/uQlXlHL7skYIKRPWKHXqyVXF1Z6srZnM+XbecOLpCxr
ZWuZRV9O2uvkgxdXxIt2vXpxasvW0WQm2n92o2i8Mfi23e3sqqXAHgdevCRn1WDK
/k4cq0XvmISusCJWZyeOUqhZPqUby6zGFQxKPzKTpg9xIpHEXKS0PYEEw86QJPch
P2LHrdD1GPnwOvOPG1J+Q3sSKH7D+sU7XuJxFn+wbSAZz8IWMJ/XAB5YoZkQve+p
bYBiHds0RWfsKDSlybcRRZukx5vncCFQ2zye0sHUSacLs7JcspSdCALAKBHUV6PN
thR4aLG54Kp1XUGghHSskHKJ
-----END CERTIFICATE-----
subject=/CN=forumanalogue.fr
issuer=/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
---
No client certificate CA names sent
Peer signing digest: SHA512
Server Temp Key: ECDH, P-256, 256 bits
---
SSL handshake has read 3769 bytes and written 433 bytes
---
New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES256-GCM-SHA384
Server public key is 4096 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
Protocol : TLSv1.2
Cipher : ECDHE-RSA-AES256-GCM-SHA384
Session-ID: 35C2D13A9EF98911E09237E588C6BDB54B83B32C6F453CF60E7C4821C53A3148
Session-ID-ctx:
Master-Key: 35ACDCD6ED409A658425D8B8D4135DD3B4FAAD565E1AB03DAB0B1227B9D55046C8F17E450519D937282C82270D4A7BD1
Key-Arg : None
PSK identity: None
PSK identity hint: None
SRP username: None
TLS session ticket lifetime hint: 300 (seconds)
TLS session ticket:
0000 - 7c 56 31 2e 2c 34 71 38-1a d8 ab 01 6c 69 0a 58 |V1.,4q8....li.X
0010 - 47 9b 56 88 a7 52 73 5a-8d 9e 29 87 c9 3c 49 18 G.V..RsZ..).. 0020 - e3 f9 9e ef 58 cb 4e 29-43 b1 2a 92 d4 a4 d5 ef ....X.N)C.*.....
0030 - b8 4f ac c6 8f 81 c1 5a-76 b0 1b 63 65 a7 95 0b .O.....Zv..ce...
0040 - 73 f2 38 5a 04 f3 53 24-f7 b0 07 c9 75 25 ef 29 s.8Z..S$....u%.)
0050 - b8 61 b9 4d 42 24 88 ae-36 40 b9 6a 8d 1f 28 57 .a.MB$..6@.j..(W
0060 - b4 9a 7d 10 45 18 e7 7b-ea 77 fc c8 8d 2a e9 00 ..}.E..{.w...*..
0070 - e4 7a 10 64 88 62 a6 0b-9b 24 2c c8 2a 62 aa e7 .z.d.b...$,.*b..
0080 - bb 4d 43 50 f2 48 80 20-0b 40 83 1d 90 79 b5 8a .MCP.H. .@...y..
0090 - 6a d5 b0 7b cf a9 96 96-72 0f c8 a7 a5 1c 17 29 j..{....r......)
00a0 - ed 33 b4 4a 2f b9 d2 a3-b7 ae 73 70 bd f3 6f 3a .3.J/.....sp..o:
00b0 - 6c 02 29 fe b0 02 90 fd-64 5a bb fd 91 77 bb ab l.).....dZ...w..

Start Time: 1595887288
Timeout : 300 (sec)
Verify return code: 0 (ok)
---
closed
Comme on peut l'observer dans la deuxième réponse, le champs CN ne correspond pas au nom du serveur indiqué à OpenSSL. Il s'avère que Apache HTTP Server renvoie aléatoirement un certificat parmi ceux des virtual hosts. Pour s'assurer d'avoir le bon certificat, il faut utiliser l'extension Server Name Indication du protocole TLS. Avec openssl, il suffit d'utiliser l'option -servername.
% openssl s_client -connect clementfevrier.fr:443 -servername clementfevrier.fr
CONNECTED(00000003)
depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
verify return:1
depth=0 CN = clementfevrier.fr
verify return:1
---
Certificate chain
0 s:/CN=clementfevrier.fr
i:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
1 s:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
i:/O=Digital Signature Trust Co./CN=DST Root CA X3
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIGbzCCBVegAwIBAgISA5hZCLbOyHsuTxNLqVmT2Ux+MA0GCSqGSIb3DQEBCwUA
MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0yMDA2MTAwOTA3MjBaFw0y
MDA5MDgwOTA3MjBaMBwxGjAYBgNVBAMTEWNsZW1lbnRmZXZyaWVyLmZyMIICIjAN
BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAt6arsvarIBaP0LmwOYpg3J2sFH69
g23kgUXPHEg+icDl16O0yLsNZy/3OmnBS+pL1ZXT1IyfX7YC6GwOYWoBb8dfwS6V
TncKhtwTPG28FJSuXezMlcjCOSdq0cxyrmt4SHajdeaaNNGPRqRjsOAtYT1KMsTM
FhxfSAT+gbSA0iqY632m22329P3OEVpjbBgkNAXE3Nv5x5AqIrAK+GsppX2A8wr0
a5n3sF0fYb8byCoaCwVvV1Bgwa20adJHUjCTBSYOoGR1wpo3LDys/GATLAUfYSOy
bSzTP4b8DWAxspFDcm0aQuO9/PzYlOP+jeq6ShYM+3OybQe/yrmvEpckX2Jz00O/
5mx0nJLd77jaBNkC02hEdL0z5G59qq4G/mgm2em4tjHk8wvPuQ8yohnLr0lk7BPZ
bedEyFb6OM8WJYufBaR/wqo31VTRzUGzNwXJqzzVW2yZUrcYKF3/nAfhq3fivPNx
J2CqpSE7wopf1jJ2lkKITlAJXGXAnePwDpMxx1DEofhLnxvAE1xWlb81qSuyKlAQ
V2jiwflvFUoY0Y1cGJyINBzLuMBiSSJtTlpELGxw7zbQKTdWQizQxL5YEcq0zCoj
KnZMlmYD79JKQ5HfCIv6kPjyllh/r6DVS6WuKd/B0YaRoU6H+9jkb+CE3I2QU0OV
VtCIq8K5zRmJrGkCAwEAAaOCAnswggJ3MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUE
FjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU
L8eqTvf8KwSRnt5TaPS1y2vuufEwHwYDVR0jBBgwFoAUqEpqYwR93brm0Tm3pkVl
7/Oo7KEwbwYIKwYBBQUHAQEEYzBhMC4GCCsGAQUFBzABhiJodHRwOi8vb2NzcC5p
bnQteDMubGV0c2VuY3J5cHQub3JnMC8GCCsGAQUFBzAChiNodHRwOi8vY2VydC5p
bnQteDMubGV0c2VuY3J5cHQub3JnLzAxBgNVHREEKjAoghMqLmNsZW1lbnRmZXZy
aWVyLmZyghFjbGVtZW50ZmV2cmllci5mcjBMBgNVHSAERTBDMAgGBmeBDAECATA3
BgsrBgEEAYLfEwEBATAoMCYGCCsGAQUFBwIBFhpodHRwOi8vY3BzLmxldHNlbmNy
eXB0Lm9yZzCCAQQGCisGAQQB1nkCBAIEgfUEgfIA8AB1ALIeBcyLos2KIE6HZvkr
uYolIGdr2vpw57JJUy3vi5BeAAABcp2yzLwAAAQDAEYwRAIgaR2cyhJ0XGOo6t5j
ONvKPspMdGAp9wFf3mGj4kfAN10CIBdLdswoMfdwZ/qveOJjpLJiTRjq8LeTZzMv
UZZUwBX3AHcAb1N2rDHwMRnYmQCkURX/dxUcEdkCwQApBo2yCJo32RMAAAFynbLM
5gAABAMASDBGAiEAu3mmQ6lFg6EvA32qSvRNRoXhviRmb1cYJNi2gqn0ShICIQDR
UvdT/vhSgH7O3B8L+TkGKyHwWibis3FpdrkEH1MERDANBgkqhkiG9w0BAQsFAAOC
AQEAgOfa0V7+sn2WULujrQy3Ob837nV+oMDmQgv59SKUR9aOxU3CBAcGsXOXzS6Z
aY1AUFT9b8D4YKNCjVi/0jruEXNGEk49IviHmU+7r2blf2MuvQfoQIABjGUvKH5+
u2dP+8Y+kqwfZc/lZ04KjMCJv1+osQMzBHhzz5HQ9SR+XgBG+Ah+5XxClfzm1odu
1IGWDrC7qDzv4leqWk69uazZLjEPWDxodFsgPAlviCnYBT1Q58x8UcOoqbRVT6Fo
3Gyi0wUeMG3wx4bbzhLKpeyJEd9BxX0U1MMR3moublihWvnIh06OXday6QjxWR/r
bYOkfH/5V04jDm8tSnC3lK9C/Q==
-----END CERTIFICATE-----
subject=/CN=clementfevrier.fr
issuer=/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
---
No client certificate CA names sent
Peer signing digest: SHA512
Server Temp Key: ECDH, P-256, 256 bits
---
SSL handshake has read 3790 bytes and written 459 bytes
---
New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES256-GCM-SHA384
Server public key is 4096 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
Protocol : TLSv1.2
Cipher : ECDHE-RSA-AES256-GCM-SHA384
Session-ID: 7D1F8AD8FC80D74FD7E47AD4D3B0102C9BDD438AE84EEAB0BC50F240020BD23F
Session-ID-ctx:
Master-Key: 09CA79EE5D635DF7B718DD89CBED5D0CA4226AEEFB4B532FA677487EA06480D85B0CD0DCED6971B2CCBD0685DFBBC0C9
Key-Arg : None
PSK identity: None
PSK identity hint: None
SRP username: None
TLS session ticket lifetime hint: 300 (seconds)
TLS session ticket:
0000 - 7c 56 31 2e 2c 34 71 38-1a d8 ab 01 6c 69 0a 58 |V1.,4q8....li.X
0010 - a0 79 b0 db eb e7 5e 82-c7 98 17 38 b5 f4 1f 49 .y....^....8...I
0020 - b0 11 0b a0 ce 4c 29 e9-8e 99 0e eb 8b f7 fd 57 .....L)........W
0030 - cc 60 a3 ea 16 2b 85 98-8c a8 b7 15 7c 2f e5 bf .`...+......|/..
0040 - f3 3a 6e 3d 2e d3 fa 66-92 26 f2 56 ad dd 46 9f .:n=...f.&.V..F.
0050 - bc 50 70 84 39 d4 c0 93-e2 f6 c0 41 2d 1a be 78 .Pp.9......A-..x
0060 - 3d e6 46 5c 11 03 4a 87-1a b1 f3 86 7a 7f 01 08 =.F\..J.....z...
0070 - 34 55 52 f5 da ef f6 45-85 e7 05 9d cc 6e 67 95 4UR....E.....ng.
0080 - bc 80 7d 2a 83 ff 9b bb-97 e3 d7 56 8b e4 f8 4a ..}*.......V...J
0090 - e1 6b 4a 1a d0 f6 a8 f3-8a e3 73 e7 cf b4 0f 9e .kJ.......s.....
00a0 - 1e 18 bd 6c ad 6b e3 4f-02 84 eb 07 41 9a 4d 83 ...l.k.O....A.M.
00b0 - 56 7b 01 7f 62 19 89 98-94 2b 77 73 06 13 2a 67 V{..b....+ws..*g
00c0 - 5b c6 11 3c d8 c5 c8 75-de 2e 15 d5 c6 86 43 f2 [..<...u......C.

Start Time: 1595887739
Timeout : 300 (sec)
Verify return code: 0 (ok)
---
closed

Comment changer disposition des touches du clavier sur Ubuntu ?

Monday Jul 27, 2020 20:07, last edition on Monday Jul 27, 2020 20:21

J'ai récemment acheté un clavier dont la disposition des touches du clavier est différente de mon précédent clavier. Je branche mon clavier sur mon poste avec Ubuntu 18.04 LTS (Bionic Beaver). Comment faire pour changer la disposition des touches ? Ce poste est la démarche en directe.

La documentation officielle

Premier réflexe, lire la documentation officielle. Je regarde donc les tutoriels, mais aucun ne correspond. Je passe donc à la documentation. Il n'y a rien coté serveur. Pour la version desktop, je trouve la page Use alternative keyboard layouts. Il semble que la manipulation décrite ne s'applique pas à mon cas car il doit me manquer des paquets. En effet, je n'ai pas le paquet ubuntu-desktop d'installé car il dépend de network-manager que je ne souhaite pas utiliser. Ce dernier est sensé être optionnel, mais en pratique, ce n'est pas le cas.

% sudo apt install --no-install-recommends ubuntu-desktop
[sudo] password for clement:
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following packages were automatically installed and are no longer required:
libllvm9 libllvm9:i386
Use 'sudo apt autoremove' to remove them.
The following additional packages will be installed:
gnome-control-center libcolord-gtk1 libndp0 libteamdctl0 network-manager network-manager-gnome
Suggested packages:
gnome-user-share realmd rygel | rygel-tracker libcanberra-gtk-module libteam-utils network-manager-openconnect-gnome network-manager-openvpn-gnome
network-manager-vpnc-gnome network-manager-pptp-gnome
Recommended packages:
libnss-myhostname dnsmasq-base network-manager-pptp iputils-arping mobile-broadband-provider-info network-manager-config-connectivity-ubuntu network-manager-pptp-gnome
The following NEW packages will be installed:
gnome-control-center libcolord-gtk1 libndp0 libteamdctl0 network-manager network-manager-gnome ubuntu-desktop
0 upgraded, 7 newly installed, 0 to remove and 34 not upgraded.
Need to get 3 494 kB of archives.
After this operation, 13,1 MB of additional disk space will be used.
Do you want to continue? [Y/n] n
Abort.

Le wiki communautaire

N'ayant rien trouvé dans la documentation officielle, je cherche dans le wiki communautaire. Il n'y a rien dans la section dédiée : InputDevices.

Je me tourne donc vers la documentation de Ubuntu-fr dédiée à la configuration du clavier. La première section ne semble pas être à jour. C'est une conséquence des changements fréquents de la part de Ubuntu. En effet, cela rend fastidieux la mise à jour de la documentation. J'arrive à la section En ligne de commande, notamment, la section 2.3.2 Définitivement.

sudo dpkg-reconfigure keyboard-configuration

Quel clavier dois-je sélectionner ?

Durant l'installation de Ubuntu, il est demandé de presser quelques touches pour détection la disposition cliavier. C'est un outil très pratique bien que imparfait. Avec la commande précédente, je me retrouve avec une liste de clavier, mais je ne sais pas lequel sélectionner. J'ai un Logitech K270. Celui-ci n’apparaît pas dans la liste. Je suppose que je dois me tourner vers un générique, mais là encore, je ne sais pas le nombre de touche, ni si c'est un intl.. Grace à la FAQ, je peux voir que j'ai la disposition Anglais (International). Il semble que la mention intl. corresponde à international en cherchant un peu sur le web. Je choisis celui avec 105 touches en me disant qui peut le plus, peut le moins.

keyboard configuration
Ensuite, je sélectionne English (US).
keyboard configuration
J'arrive à nouveau avec une liste choix où je me sens un peu perdu. Je vois une entrée English (US) - English (US, euro on 5). Étant donné que j'ai un signe euro sur la touche 5, je pense que c'est la bonne disposition. Essayons.
keyboard configuration
Une fois encore, un menu avec une liste où il faut choisir et où les explication sont trop succinctes pour faire un choix éclairé. J'ai une touche "Menu key", si je comprends bien ce qui est entendu par là, donc je sélectionne cette option.
keyboard configuration
Un nouveau choix se présente à moi. Je trouve ça interminable, et je commence à penser au nombre de combinaisons à réaliser avant de trouver la bonne disposition. J'ai l'impression qu'il faut être un expert pour changer de clavier. Je laisse l'option par défaut ne sachant pas quoi sélectionner.
keyboard configuration
Un nouveau choix se présente à moi, mais pour une fois, je le comprends et je sais quoi répondre.
keyboard configuration
Enfin, c'est fini, sauf que... sauf que ça prend du temps à configurer, et je ne connaîtrai le résultat qu'au prochain démarrage. C'est très lourd comme démarche.
% sudo dpkg-reconfigure keyboard-configuration
[sudo] password for clement:
Your console font configuration will be updated the next time your system
boots. If you want to update it now, run 'setupcon' from a virtual console.
update-initramfs: deferring update (trigger activated)
Processing triggers for initramfs-tools (0.130ubuntu3.9) ...
update-initramfs: Generating /boot/initrd.img-4.15.0-112-generic
J'essaye de lancer la commande setupcon mais cela ne semble pas fonctionner.
% setupcon
setupcon: We are not on the console, the console is left unconfigured.

Pour éviter le travail laborieux d’essayer toutes les combinaisons jusqu'à trouver la bonne, je cherche une alternative. Sur cette même page de wiki, on trouve la commande setxkbmap qui change pour quelques minutes la disposition des touches du clavier. En lisant le man, je ne trouve pas de moyen d'afficher les arguments valides, mais, il y a une référence vers un fichier

FILES
/usr/share/X11/xkb
En parcourant les fichiers, je finis par comprendre que l'information qui m'intéresse se trouve dans /usr/share/X11/xkb/symbols/us. Je comprends que le nom du fichier correspond au premier argument à passer à la commande, mais cela ne me donne pas encore la bonne disposition du clavier. Dans le fichier, il y a des des variables name[Group1]= dont je remarque qu'elles correspondent au valeur de la méthode permanente et que le le second argument à passer est la valeur de la variable xkb_symbols qui y est associée.
% grep xkb_symbols /usr/share/X11/xkb/symbols/us
xkb_symbols "basic" {
xkb_symbols "euro" {
xkb_symbols "ibm238l" {
xkb_symbols "intl" {
xkb_symbols "alt-intl" {
xkb_symbols "dvorak" {
xkb_symbols "dvorak-intl" {
xkb_symbols "dvorak-alt-intl" {
xkb_symbols "dvorak-l" {
xkb_symbols "dvorak-r" {
xkb_symbols "dvorak-classic" {
xkb_symbols "dvp" {
xkb_symbols "rus" {
xkb_symbols "mac" {
xkb_symbols "colemak" {
xkb_symbols "altgr-intl" {
xkb_symbols "classmate" {
xkb_symbols "classmate-intl" {
xkb_symbols "classmate-alt-intl" {
xkb_symbols "classmate-altgr-intl" {
xkb_symbols "olpc" {
xkb_symbols "olpc2" {
xkb_symbols "olpcm" {
xkb_symbols "chr" {
xkb_symbols "hbs" {
xkb_symbols "htcdream" {
xkb_symbols "workman" {
xkb_symbols "workman-intl" {
xkb_symbols "norman" {
xkb_symbols "carpalx" {
xkb_symbols "carpalx-intl" {
xkb_symbols "carpalx-altgr-intl" {
xkb_symbols "carpalx-full" {
xkb_symbols "carpalx-full-intl" {
xkb_symbols "carpalx-full-altgr-intl" {
xkb_symbols "cz_sk_de" {
xkb_symbols "scn" {
xkb_symbols "intl-unicode" {
xkb_symbols "alt-intl-unicode" {
xkb_symbols "ats" {
xkb_symbols "crd" {
xkb_symbols "sun_type6" {
Il reste de nombreuses possibilités, mais certains noms sont suffisamment explicites pour être exclu, par exemple dvorak. Je finis par me convaincre que la bonne disposition du clavier est donnée par
% setxkbmap us altgr-intl

Le travail n'est pas terminé. Il me reste encore à comprendre quelle combinaisons d'options va me permettre de rendre ce changement permanent. Le travail effectué au paragraphe précédent va juste me permettre de réduire les possibilités. Désormais, je sais que je dois choisir English (US) - English (intl., with AltGr dead keys) à la place de English (US) - English (US, euro on 5).

keyboard configuration
J'ai donc avancé d'une étape. Concernant le menu suivant, une fois de plus, je ne suis pas certain du choix. Je sélectionne Right Alt (AltGr), en gardant en tête que le premier choix, The default for the keyboard layout est peut-être le bon.
keyboard configuration
Pour le menu suivant, je laisse par défaut car cela me semble avoir un impact faible.
keyboard configuration
Je sais quoi répondre à la dernière question.
keyboard configuration
% sudo dpkg-reconfigure keyboard-configuration
[sudo] password for clement:
Your console font configuration will be updated the next time your system
boots. If you want to update it now, run 'setupcon' from a virtual console.
update-initramfs: deferring update (trigger activated)
Processing triggers for initramfs-tools (0.130ubuntu3.9) ...
update-initramfs: Generating /boot/initrd.img-4.15.0-112-generic
Il ne me reste plus qu'à redémarrer pour tester.

Échec

J'ai testé grub, les changements ont bien été pris en compte. J'ai aussi pu rentrer mon mot de passe avec la bonne disposition du clavier. Cela veut dire que cela est pris en compte par LightDM. Une première étape est donc franchie. Cependant, à l'ouverture de la session, la disposition du clavier est à nouveau avec l'ancienne disposition.

Où trouver de l'aide ?

Étant à court d'idée, je cherche de l'aide. Il y a de nombreux moyen d'obtenir de l'aide. Il y a notamment IRC disponible dans de nombreuses langues, dont anglais et français. En anglais, il y a le forum et Ask Ubuntu. En français, il y a le forum. J'ai l'impression que la liste de distribution a disparue.

De manière générale, je n'aime pas IRC ou les listes de distribution pour résoudre un problème notamment car il n'est pas possible d'éditer ses messages et car cela ne laisse pas une bonne trace pour la communauté. Je commence par Ask Ubuntu, tout simplement car je trouve l'interface plus agréable. Je tombe rapidement sur How do I change keyboards from the command line?. La réponse acceptée ne me satisfait pas car elle ne change pas la disposition du clavier par défaut. Cependant, parmi toutes les réponses, une répond à ma problématique. En effet, j'arrive à identifier le problème

% gsettings get org.gnome.desktop.input-sources sources
[('xkb', 'fr+latin9')]
J'essaye de voir si altgr-intl est présent dans le fichier /usr/share/X11/xkb/rules/base.lst
% grep altgr-intl /usr/share/X11/xkb/rules/base.lst altgr-intl us: English (intl., with AltGr dead keys)
J'essaye donc
% gsettings set org.gnome.desktop.input-sources sources "[('xkb', 'us+altgr-intl')]"
ça semble avoir bien été pris en compte
% gsettings get org.gnome.desktop.input-sources sources [('xkb', 'us+altgr-intl')]
Je redémare pour voir si tout fonctionne correctement.

Conclusion

Tout fonctionne correctement, grub, LighDM, GNOME. Mais cela m'a pris plus de 8h pour changer la disposition de mon clavier. La force d'Ubuntu est d'avoir pu répondre à la demande du grand public Je veux que ça fonctionne et Ubuntu y était parvenu avec brio pendant des années mais je sens un relâchement depuis plusieurs LTS. J'ai l'impression que Ubuntu et Canonical se concentrent de plus en plus vers l'industrie et d'autres champs d'application que l'ordinateur de bureau. C'est regrettable pour le grand public et ça me semble mauvais sur le plan stratégique car l'industrie n'aura pas tendance à accorder sa confiance à un partenaire qui bacle ses produits et Ubuntu est la plus grande vitrine pour Canonical.

La difficulté pour faire une action qui me semblait si simple vient de plusieurs facteurs.

Il y a de réelles problématiques techniques, par exemple le fait que ça impacte grub, c'est à dire avant que le système ne soit lancé.

Je n'ai pas simplifié la tache avec ma configuration personnalisée, sans network-manager. En un sens, c'est le prix de la liberté, mais cela vient tout de même d'un système qui est trop contraint à la base. En effet, pourquoi je ne peux pas changer la disposition de mon clavier si je ne souhaite pas utiliser le gestionnaire réseau par défaut.

Les changements trop fréquents de la part d'Ubuntu. En effet, la documentation n'est pas à jour, impossible de dire si les bugs sont encore d'actualité, les questions sur les plateformes d'entraide sont pertinentes seulement si elles sont suffisamment récentes et de nombreux membres de la communauté n'arrivent plus à aider car ils ne sont pas au courant de tel ou tel changement arrivé récemment.

Cela me fait revenir sur l'éternel compromis entre la liberté de forker, ce qui permet la créativité, et faire un effort commun pour se concentrer sur une solution pour l'améliorer et la rendre accessible au plus grand nombre.

Captain's Log #5

Monday Jul 27, 2020 12:05
Feedback on LXD

I had an issue with LXD where its database got corrupted. In that case, there is nothing we can do. All Linux containers on every physical servers are gone. I managed to restore most of the containers using rsync, but the internal file-system management of LXD is completely screwed. I cannot export not publish my containers to backup them, nor restart my LXD configuration from scratch by exporting and importing them back. My only option is to get another physical server, I have three so far, so adding a fourth one, make a new LXD server, outside of the current cluster. Then, recreate from scratch all my containers, which will be a a task requiring a tremendous amount of time. After this, deleting the current LXD cluster, creating a new one with the three physical servers, export the containers from the temporary LXD server and finally importing the containers to the cluster. It is necessary that I perform this task as quickly as possible because I cannot perform backup.

Spam, again

Adding 212.83.46.232 to iptables (INPUT, DROP) has not enough. I added other IPs and few range of IPs, up to /16. It was not enough and it was a fastidious task. So I added a new field to the comment section. You need to answer yes. It is not case sensitive. This simple trick appears to do the job so far.

Git

My git repo were not working anymore. I forgot to enable the mods in Apache HTTP Server when I migrate from Xen to LXD.

a2enmod cgi alias env
It is now fixed. For more information, see Smart HTTP.

Statistics

Statistics were not working anymore. I use a custom version of Awstats in order to integrate smoothly the statistics in my website. Part of this script rely on the package provided by Ubuntu. When I upgrade the virtual machine from Ubuntu 16.04 LTS (Xenial Xerus) to Ubuntu 18.04 LTS (Bionic Beaver), some modifications in Awstats broke my customization. I realize that maintaining this part will be complex as it is a 22000+ lines Perl file which is difficult to edit automatically. I made a quick fix. It will most-likely broke again when I will migrate from Ubuntu 18.04 LTS (Bionic Beaver) to Ubuntu 20.04 LTS (Focal Fossa).

To Do List
TootLine

I am working on TootLine, the PHP code that allows you to share your TootLine on your blog, like the one there is on the right or bottom, depending on the size of your screen. I have couple of issues to address before publishing it, which are proper word wrapping, create a cache for the media in order to solve CSP issue, handle the NSFW content that is displayed so far.

Translations

I would like to make a French version of this blog, with most of the articles translated.

More restrictive CSP headers

I want to rewrite some part of the web site to be able to provide more secure CSP headers.

Comments

I am planning on adding a RSS feed for each commentary section so it will be easy to follow. I will also add a cookie to auto fill the fields Name and Website. I will put a check box if you want to add the cookie when you comment.

Tags

I will add the list of all tags on the right panel.

SEO

I will add proper Open Graph protocol and Twitter cards in the headers. I already updated the MySQL database, so everything is ready on this side, I just need to rewrite the headers that I include to make them dynamic.

Better looking links

I already changed the URL of some links to make them better looking, but I did not finish yet. The rewriting rules are not as simple as I expected, if you want to make them SEO compliant.

Better CMS

My work-flow is not the most efficient. Each article points to an actual file, which is not so good, because I need to create a file each I add an entry in this blog. I will improve this soon. It is one of the reason why I stopped writing here. It is too complex.

Migrating the last virtual from Xen to LXD

I need to migrate completely my photo galleries (Piwigo) from XEN to the new ones on LXD.

Home made modem/router/NAS

I bought few items in order to build my own modem/router/NAS.

RSS

Although RSS feed appears to work fine, there are PHP errors in the logs. I need to investigate.

Le jour où l’hôpital public est devenu Aliexpress.

Friday Jul 24, 2020 21:36, last edition on Thursday Jul 30, 2020 16:10

Le 15 juillet de cette année, j’ai acheté un BPI-R2 sur Aliexpress. C’est mon premier achat sur cette plateforme. Hier, j’ai reçu un message de cette plateforme m’invitant à donner mon avis. J’ai répondu au questionnaire dont la dernière question était une phrase, en anglais, du genre « Recommanderiez-vous Aliexpress à vos amis ? ».

Your opinion is extremely important to us.
 
 
AliExpress
Smarter Shopping, Better Living!
 
Having trouble seeing this email? Click here
 
 
Tell us about your AliExpress experience!

Dear Customer,

Thank you for shopping on AliExpress.com!

In order to improve AliExpress services, we'd like to invite you to participate in a 5-10 minute survey. All questions are related to your shopping experience and the products you purchased on AliExpress.

Your feedback will be greatly appreciated and your answers will be kept strictly confidential.


Take survey now

Or copy and paste the following URL to your browser:

https://www.research.net/

Sincerely,

AliExpress.com

 
CONNECT WITH:        
 
Homepage | My AliExpress | Help Center | Buyer Protection | Forgot your password?
This email was sent to
You are receiving this email because you are a registered member of www.AliExpress.com.
To unsubscribe from future similar promotional emails, click here.
Read our Terms of Use if you have any questions.
AliExpress Service Center
Alibaba.com Hong Kong Limited
26/F Tower One, Times Square, 1 Matheson Street, Causeway Bay, Hong Kong
Aliexpress

Le 9 juillet de cette année, j’ai été hospitalisé en chirurgie ambulatoire du CHU Grenoble Alpes à cause d’un conflit fémoro-acétabulaire. Les jours qui ont précédé l’intervention, j’ai reçu une sommation de la part de l’hôpital de fournir mon adresse email, ainsi que ma carte de mutuelle, mais c’est une autre histoire de l’absurdité bureaucratique dont nous sommes si fier que je conterai peut-être plus tard, pour compléter mon dossier avant le jour de l’intervention, sans quoi je ne pourrai pas être pris en charge. J’ai reçu ce courrier l’avant veille de mon hospitalisation. J’ai donc découvert ce courrier en rentrant chez moi après le travail. Étant donné que tous les services administratif de l’hôpital ferment à 15h50, je n’avais donc que la veille de l’opération pour me rendre sur place pour fournir mon adresse email. Cet un ajout de stress complètement inutile, d’autant plus que cette adresse email ne sert exclusivement qu’à envoyer un sondage. Faire une menace de refus d’hospitalisation car on peut pas faire une enquête de satisfaction est tout simplement inadmissible. Deux semaines plus tard, c’est à dire hier, je reçois un email de la part de l’hôpital pour une répondre a une enquête de satisfaction. Mon hospitalisation ne s’étant pas bien passée à cause entre autre d’une lourdeur administrative pré- et per-opératoire inutile, l’hôpital ayant ignoré les pièces justificatives que j’ai fourni pour inventer des mutuelles, notons que ce n’est pas la première fois que le CHU Grenoble Alpes fait cette erreur, c’était déjà le cas il y a deux ans lorsque je me suis fait une bursite à l’épaule droite en faisant du bloc, accueil ignoble par le personnel administratif le jour de l’intervention, oubli d’ordonnance à ma sortie, et ordonnances insuffisantes pour faire les pansements après l’opération, invention d’une mutuelle, ce qui veut dire qu’ils ont ignoré la carte de mutuelle que je leur ai fourni à maintes reprises avec des heures attentes, je n’ai pas vu le chirurgien que j’avais vu qui a programmé l’intervention, mon rendez-vous avec ce dernier a été annulé sans me prévenir, il ne veut pas faire le suivi de mon opération, le chirurgien à qui le suivi est délégué sera en vacances lorsque mon arrêt de travail s’achèvera, je n’aurai donc pas aucun suivi de la part de l’hôpital, l’hôpital ne veut pas prolonger mon arrêt de travail jusqu’à ce que je puisse voir un chirurgien, leur solution, que je prenne rendez-vous avec un autre médecin pour qu’il me prescrive un prolongement de mon arrêt de travail jusqu’à ce que je puisse voir un chirurgien, notons que le chirurgien qui a programmé l’intervention n’est pas en vacances mais ne souhaite pas faire de suivi post-opératoire sur ce type de chirurgie, pas d’appel le lendemain de l’hôpital comme convenu, j’ai pourtant souffert de plusieurs complications post-opératoires dont certaines nerveuses « rares » et irréparables si elles ne se résorbent pas d’elles mêmes mais connue, le chirurgien suppléant m’a dit que j’avais été prévenu de ce risque, en effet, par une ligne dans un dossier faisant 58 pages avec des mots techniques, pas de suivi de la part du service hospitalisation de l’hôpital pour mes complications post-opératoires. En bref, l’hôpital ne m’a pas mis dans des bonnes conditions pour mon opération, ce qui est pourtant de leur devoir étant donne que c’est un facteur lors d’une chirurgie avec anesthésie générale et il m’a abandonné après mon opération. J’ai donc répondu au questionnaire de satisfaction, comme je le ferrai pour un site marchant. La dernière question de ce question fut « Recommanderiez-vous cet hôpital à vos amis ? ».

          

Enquête nationale de mesure de la satisfaction et de l'expérience des patients hospitalisés

HÔPITAL NORD - CHU38

Madame, Monsieur,

Vous avez été hospitalisé du 09/07/2020 au 09/07/2020. Votre avis nous intéresse :

https://e-satis.fr/

(Questionnaire accessible pendant 69 jours)

Ce questionnaire est anonyme et ne vous prendra que quelques minutes.
Vos réponses sont importantes. Elles permettront à votre hôpital ou clinique de connaître les points positifs de votre séjour et ceux qu’il peut améliorer, mais aussi de lui attribuer une note de satisfaction, consultable sur le site Scope Santé.

Nous vous remercions de votre participation.

Cas particuliers:

  • Si c’est votre enfant qui a été hospitalisé et qu’il a moins de 14 ans, vous pouvez répondre au questionnaire à sa place. S’il a entre 14 et 17 ans, vous pouvez répondre avec lui ou à sa place.
  • Si vous êtes un proche d’une personne qui a été hospitalisée mais qui ne peut répondre au questionnaire, vous pouvez répondre avec elle ou à sa place.

Une question ?

C'est la Haute Autorité de Santé (HAS) qui mène cette enquête nationale de mesure de la satisfaction des patients hospitalisés. Vous pouvez la contacter à l'adresse e-Satis@has-sante.fr .

HÔPITAL NORD - CHU38

Si vous ne souhaitez pas répondre au questionnaire, cliquez ici pour vous désinscrire.

Les données personnelles vous concernant (adresse mail, sexe, âge, date d’entrée et de sortie de l’établissement) collectées à l’occasion de cette enquête ont pour unique objet l’évaluation de la satisfaction des usagers ayant fait l’objet d’une hospitalisation afin d’améliorer la qualité du service rendu aux patients. Ces données ne sont transmises qu’aux agents de l’Agence Technique de l'Information sur l'Hospitalisation (ATIH) et à la Haute Autorité de Santé (HAS) en charge de cette enquête. Votre adresse e-mail est supprimée un an après réception de cet e-mail. Les autres données recueillies sont conservées pour la durée nécessaire à l’exploitation de l’enquête. Conformément à la loi «Informatique et libertés», vous pouvez exercer votre droit d’accès, d’opposition, de rectification et de suppression des données vous concernant : Désinscription

Nous sommes donc le jour où le Ministère des Solidarités et de la Santé utilise les mêmes critères que Aliexpress pour évaluer sa performance, puis-je utiliser gratuitement mes clients pour vendre mon produit.

Captain's Log #4

Friday Jul 24, 2020 12:48, last edition on Monday Jul 27, 2020 11:19
Migration to LXD

I pretty much migrate all my virtual servers from Xen to LXD. Only one virtual server is left on Xen because I made a mistake configuring it in LXD and it requires a rather complex merge of two databases, so it's on hold for now.

Spam

Comment section has been subject to a lot of spam. I blindly deleted all comments from November 26, 2017. I first comment the PHP section of this website which allow to comment, but it did not stop anything. Looking at apache's log, I identified an IP, 212.83.46.232, which I added in iptables. I hope that it will solve the issue. The comment section is now open again.

To Do List
TootLine

I am working on TootLine, the PHP code that allows you to share your TootLine on your blog, like the one there is on the right or bottom, depending on the size of your screen. I have couple of issues to address before publishing it, which are proper word wrapping, create a cache for the media in order to solve CSP issue, handle the NSFW content that is displayed so far.

Translations

I would like to make a French version of this blog, with most of the articles translated.

I addition to what remains on the To Do List, I want to add couple of improvement.

More restrictive CSP headers

I want to rewrite some part of the web site to be able to provide more secure CSP headers.

Comments

I am planning on adding a RSS feed for each commentary section so it will be easy to follow. I will also add a cookie to auto fill the fields Name and Website. I will put a check box if you want to add the cookie when you comment.

Tags

I will add the list of all tags on the right panel.

SEO

I will add proper Open Graph protocol and Twitter cards in the headers. I already updated the MySQL database, so everything is ready on this side, I just need to rewrite the headers that I include to make them dynamic.

Better looking links

I already changed the URL of some links to make them better looking, but I did not finish yet. The rewriting rules are not as simple as I expected, if you want to make them SEO compliant.

Better CMS

My work-flow is not the most efficient. Each article points to an actual file, which is not so good, because I need to create a file each I add an entry in this blog. I will improve this soon. It is one of the reason why I stopped writing here. It is too complex.

Migrating the last virtual from Xen to LXD

I need to migrate completely my photo galleries (Piwigo) from XEN to the new ones on LXD.

Home made modem/router/NAS

I bought few items in order to build my own modem/router/NAS.

Nous allons tuer la radio, et alors ?

Wednesday Jan 31, 2018 17:35

En regardant mes flux rss, je suis tombé sur une tribune parue sur le site de Libération le 22 janvier 2018 à 12h22, intitulée « Ils vont tuer la radio », de Fanch Langoët et Francine Leduc.

La première question que je me suis posé est « et alors ? » Du titre, j’ai imaginé deux scenarii. Le premier est que quelque chose vient de changer, un élément perturbateur, qui va injustement détruire ce média. Le second, plus probable compte tenu du titre généraliste, est qu’il est entrain de s’opérer un changement de paradigme, notamment compte tenu des changements de modèles économiques par le passage d’un modèle de rareté au modèle de quantité. Je vais résumer grossièrement ces deux notions. Dans le premier cas, le coup de production augmente avec la quantité, c’est par exemple le cas des livres, dont le principal coût de production est le papier, impliquant que pour un éditeur, produire deux livres coûte deux fois plus chers qu’en produire un seul. Dans le second cas, le coup de production est indépendant de la quantité, ce qui est typiquement le cas dans le monde numérique. Reprenons notre éditeur de livres. Le coût de mise à disposition d’un livre numérique à un lecteur, par exemple un fichier PDF sur un serveur web, revient au même prix que la mise à disposition de ce même fichier PDF à deux lecteurs.

« Ils » désigne les vilains qui cherchent à assassiner un média rendu obsolète par l’avènement des nouvelles technologies, ce sont donc toutes les personnes qui publient du contenu en ligne. Cette tribune est de mauvaise foi et les arguments exposés sont facilement réfutables.

« Au nom de la mutation technologique, du progrès et de la globalisation, les prêcheurs du tout-numérique prônent l’obsolescence du média radiophonique. » On sent tout de suite l’amertume, la subjectivité et la partialité du propos, notamment avec l’utilisation de « prêcheur », mot connoté négativement et qui laisse penser que la transition vers le numérique est un dogme, tout comme la désignation de la transition vers le numérique de « religion ».

Les auteurs de cette tribune nous parlent de « destruction massive » du média radiophonique et de ses « ravages », un registre de langage bien particulier et qui laisse entrevoir que les auteurs parlent avec les émotions. C’est ainsi que dès la fin du premier paragraphe, on peut se rendre compte que les auteurs se sont trompés de colère, pour paraphraser un auteur qui éprouvait un ressentiment difficilement caché à l’égard de son cancer. Je reprends donc le passage clé, les « un plan implacable de destruction massive qui [...] se pare des vertus supposées du tout-numérique, pour ubériser le secteur radio ». Je ne reviens pas sur les « vertus supposées du tout-numérique » étant donné qu’il y a beaucoup à dire, mais le « ubériser le secteur radio » n’est pas correct. Les auteurs blâment le vecteur au lieu de la cause. Nous n’accusons pas le facteur d’être la raison de notre malheur lorsque celui-ci nous apporte de mauvaises nouvelles. Premièrement, considérons que la radio est un média sujet à l’économique de la rareté. En effet, le nombre de stations radio disponibles est limité par le nombre de bandes de fréquences, appelées aussi porteuses en théorie du signal, disponibles et par le fait que l’onde hertzienne transmette un signal à un instant donné et que, encore une fois pour faire simple, nous ne pouvons pas réécouter une émission ou un chanson à partir de notre poste radio. Au contraire, sur l’Internet, il n’y a pas de limitation du nombre de diffuseurs, j’en suis moi-même un, ni de la disponibilité à n’importe quel instant d’un média publié. Si un diffuseur de contenu met en ligne un fichier audio, par exemple une chanson ou un podcast, alors il n’y a pas de raison technique pour empêcher que ce contenu soit à tout moment disponible, donc ré-écoutable à l’infini. Notons que ceci est générique, donc le fait qu’il y ait un changement de paradigme économique est indépendant du média impacté.
Il y a différents modèles économiques émergents pour rendre économiquement viable les diffuseurs dans cette nouvelle ère, par exemple les dons, la publicité, la revente des données personnelles des utilisateurs, etc. mais il n’y en n’a pas un unique comme celui « l’offre et la demande » de l’ère de la rareté. Le fait que cette tribune arrive aujourd’hui me fait penser que le secteur de la radio n’a pas assez anticipé ce changement et se retrouve donc dans une impasse financière avec très certainement des emplois en danger. « L’ubérisation » n’est pas dû à l’aspect numérique mais, dans le contexte d’un paradigme économique de la quantité, aux modèles économiques appliqués. C’est une conséquence en particulier du modèle néolibéral qui, en enlevant les droits des salariés, les rends précaires. C’est aussi une conséquences des choix des maisons de radio qui, comme les principaux journaux papiers, ont choisit les annonceurs comme investisseurs.

« S’il doit s’aligner sur le projet d’une radio intégralement délinéarisée (où chaque programme sera accessible à tout moment), ce big-bang sera, sans surprise, un rouleau compresseur qui transformera radio et télé en producteurs de contenus conçus dans les règles et l’esprit de la libre concurrence des réseaux sociaux. » Ceci est une mauvaise interprétation de la conséquence des réseaux sociaux sur les médias. Dans tous les cas, si nous admettons l’influence importante des réseaux sociaux sur l’économie des diffuseurs de médias, ce qui semble être une hypothèse raisonnable, les réseaux sociaux auront un impact. Si une station de radio est plus partagée sur les réseaux sociaux qu’une autre, alors son audience augmentera certainement. Les stations de radio étaient déjà des producteurs de contenu avant l’Internet, c’est pour cette raison que chaque station à un public cible qu’elle essaye de contenter pour garder et augmenter son audience. Il est certain qu’une station de radio qui permettra la rediffusion de contenu sera capable de proposer un autre modèle économique, et sera donc plus pérenne financièrement. Pour éviter « l’ubérisation », il conviendra à la station radio de choisir un bon modèle économique ou d’en créer un, car je suis persuadé que l’on peut trouver de meilleurs solutions que celles appliquées aujourd’hui.

« cette mutation technologique ne va pas sans un renouveau éditorial et semble paramétrée pour lisser les voix et les idées. » C’est faux, ce n’est pas à cause de la technologie. Ce sont les modèles dominants de cette transition qui en sont la cause, comme le « clic bait » qui change la manière de titrer, de résumer et de créer des aperçu des contenus pour attirer les utilisateurs sur des pages non pas pour le contenu, mais pour les annonceurs. C’est donc bien le néolibéralisme qui est la cause et en particulier le choix de l’investissement par des annonceurs.

Pour le troisième paragraphe, je me vois obligé d’être sarcastique car les auteurs voient la débauche ultime dans le mixte du son et de l’image, couramment appelé à l’époque moderne, la vidéo. Je n’imagine pas l’indignation des auteurs lors de l’apparition des premiers films sonores dans les années 30. L’époque nostalgique où il fallait savoir lire pour regarder un film, dans quelle époque antidémocratique vivons nous où les médias sont plus accessible de jamais ? Bref, je trouve l’argumentaire de ce paragraphe simplement stupide. Avec l’augmentation des débit de connexion à l’Internet, nous avons pu voir l’intérêt du monde pour la vidéo. J’ai trouvé l’idée de France Inter de filmer les émissions pour ensuite les mettre en lignes intéressante. Logiquement, je me dis « qui peut le plus, peu le moins », donc si une émission de radio est accompagnée de vidéo, on peut tout aussi bien écouter l’émission sans regarder la vidéo, ce que, à titre personnel, je fais la grande majorité du temps. « Les critères marketing se substituent à tous les autres et menacent doucement mais sûrement d’emporter le patrimoine radiophonique » Encore une fois, les auteurs confondent l’Internet avec le néolibéralisme.

Je trouve intéressant l’utilisation de « garde-fou », qui sont-ils ? Est-ce « eux », les animateurs radio ? C’est d’une part très prétentieux et d’autre part dangereux de se représenter en gardien de la société et de la débauche.

Dans le quatrième paragraphe, les auteurs partent dans des fabulations. À moins qu’ils aient connaissance d’un plan secret de déploiement de radio diffusée uniquement en 3G à la place de la diffusion hertzienne, car, je cite, les auteurs nous parlent de « la disparition de la radio hertzienne au profit d’une diffusion intégralement 3G », ils sont dans l’invention la plus complète. Cela montre une grande méconnaissance technique et de ce que sont les réseaux. Ils ne sont même pas au courant que la radio est aujourd’hui diffusée sur l’Internet. Ironiquement, leur propos étaient presque plus cohérent dans la version original de l’article où ils parlaient de « radio numérique terrestre ». Mais cela me simplifie la tâche étant donné que cela rend le reste du paragraphe complètement erroné alors qu’autrement il y aurait eu des choses à dire. Par exemple, les auteurs s’imaginent que les français prennent une connexion au réseau mobile pour écouter la radio et que « donc » il faudra poser des antennes 3G sur tout le territoire et équiper tout le monde de nouveau appareils capables de recevoir cette fameuse « radio numérique ». Comme si les il y avait des antennes 3G mobile et des antennes 3G « radio numérique » et des appareils spécifique pour la recevoir. Il semble qu’il y ait un amalgame de la part des auteurs entre la diffusion du contenu sur le réseau, ce qui est le cas de la radio, avec la création d’un nouveau système, comme ça a été le cas avec la TNT où il avait effectivement besoin de construire un réseau et appareils capable de recevoir le signal. Mis bout à bout, entre les réseaux mobiles et les connexions à l’Internet, l’accès à la radio numérique est certainement plus grand que si on le compare au nombre de foyers qui ont un poste radio à la maison (je n’ai pas réussi à trouver cette information, mais je n’ai pas beaucoup cherché non plus). Il y a une confusion évidente entre l’Internet et le réseau mobile, ce qu’ils font, et en quoi c’est fondamentalement différent de la radio, ou de la télévision.

Le dernier paragraphe montre bien les confusions entre le numérique et les modèles économique qui lui sont appliqués, ne voient pas que d’autres voies sont possibles, blâment le numérique pour les nouveaux formats au lieu du néolibéralisme.

« Le faux progressisme des prêcheurs du tout-numérique n’est d’ailleurs pas très loin d’une étrange «radiophobie» » Et cette tribune n’est d’ailleurs pas très loin d’une étrange technophobie.

Je suis conscient que mon propos est bourré de généralités et d’approximations, mais ayant déjà écrit un pavé, je ne voulais pas noyé mon propos dans trop de détails.

Captain's Log #3

Wednesday Jan 31, 2018 09:53
EnableSendfile Directive

I enabled the EnableSendfile Directive in Apache HTTP Server by adding EnableSendfile On to the Virtual Host.

To Do List
TootLine

I am working on TootLine, the PHP code that allows you to share your TootLine on your blog, like the one there is on the right or bottom, depending on the size of your screen. I have couple of issues to address before publishing it, which are proper word wrapping, create a cache for the media in order to solve CSP issue, handle the NSFW content that is displayed so far.

Translations

I would like to make a French version of this blog, with most of the articles translated.

I addition to what remains on the To Do List, I want to add couple of improvement.

More restrictive CSP headers

I want to rewrite some part of the web site to be able to provide more secure CSP headers.

Comments

I am planning on adding a RSS feed for each commentary section so it will be easy to follow. I will also add a cookie to auto fill the fields Name and Website. I will put a check box if you want to add the cookie when you comment.

Tags

I will add the list of all tags on the right panel.

SEO

I will add proper Open Graph protocol and Twitter cards in the headers. I already updated the MySQL database, so everything is ready on this side, I just need to rewrite the headers that I include to make them dynamic.

Better looking links

I already changed the URL of some links to make them better looking, but I did not finish yet. The rewriting rules are not as simple as I expected, if you want to make them SEO compliant.

Better CMS

My work-flow is not the most efficient. Each article points to an actual file, which is not so good, because I need to create a file each I add an entry in this blog. I will improve this soon.

Migration to LXD

I am not entirely sure that I will do it, but I am considering to migrate from Xen to LXD.

How to diagonalize a matrix of 4,722,366,482,869,645,213,696 elements? Part 2

Friday Nov 24, 2017 01:12
Mind your type #2

In the previous part, I was talk about how one shall be careful at the size of integer types. There are more considerations to take into account, in particular integral promotion. I have been been surprised to see that the return type of arithmetic operations are not the type of type of the two operands. For example, in the following code

unsigned char a;
unsigned char b;
auto c = a + b;
c is not an unsigned char. This is surprising because if both operands have the same type, then no further conversion is needed. However, and Andrey Chubukov, whom I had as a teacher during a workshop, was telling us that All great stories begin with However. Notice that it is not bijective. However,

"Arithmetic operators do not accept types smaller than int as arguments, and integral promotions are automatically applied after lvalue-to-rvalue conversion, if applicable."

cppreference.com

And indeed, one can check that c is an int.

A concluding word

Implicit conversions makes the use of auto more complicated because for types smaller than int the prototype is not

T T::operator+(const T2 & b) const;
but
int T::operator+(const int & b) const;
In our case, it can be problematic because memory consumption is the limiting factor.

Sparse symmetric matrix

Let us consider the antiferromagnetic Heisenberg model on one triangle at zero-field. The matrix representation of the Hamiltonian is

Antiferromagnetic Heisenberg model on one triangle

Sparse matrix

Apart from the diagonal terms, only few off-diagonal terms are non zero

Antiferromagnetic Heisenberg model on one triangle
It is a sparse matrix. We can use this property to save memory by storing only finite elements.

Let us consider that we need maximum machine precision, then, all elements are long double. The size of the matrix of is then 22×Ns×sizeof(long double), with Ns the number of sites. There are 3 sites on a triangle, and long double is 16Bytes, so, this matrix is 1kB (1024Bytes).

With a sparse matrix, one need only to store non-zero elements and their position. There are 8 diagonal terms, plus 6 on the upper triangle, and 6 on the lower triangle, so 20 non-zero elements. We know that eventually, we will deal with numbers up to 272 for the index in the matrix, so the index will be store on a 16Bytes integer type, called index in the following, that we will define later.
The size in memory is then 20×(sizeof(long double)+sizeof(index)) = 640Bytes. So we saved memory by a factor 1.6.

Notice that in this case, the indices can be stored in unsigned char and the values in signed char, which are both 1Bytes, thus this matrix can be stored in 40Bytes.

One can also notice that many elements share the same value, it can be useful to safe more memory by storing only different value. In addition, many values does not need to be stored in long double, but in smaller floating-point types to save even more memory. To achieve this, we can rewrite the Hamiltonian to favor signed char and then, apply a function to restore the actual physical values.

Sparse matrices take advance of the size. Indeed, the ratio between the memory consumption of the dense matrix and the sparse matrix increases with the size. In other words, sparse matrix will make you save relatively more space while the size increases, e.g. the ration is about 2.3 for Ns = 4.

Hermitian matrix

The Hamiltonian is an Hermitian operator. Thus, one need only the diagonal and either the upper or lower triangle of the matrix to have a complete knowledge of the matrix.

Antiferromagnetic Heisenberg model on one triangle
Now, one computes only these elements
Antiferromagnetic Heisenberg model on one triangle
and stores the non-zero ones, leading to a memory consumption of (8+6)×(sizeof(long double)+sizeof(index)) = 448Bytes, or 28Bytes will all optimizations, so about 2.3 times less memory.

Symmetries

The next step, is to use symmetries to block-diagonalize the Hamiltonian. It is introduced in Section 4.4.1 Symmetries of my PhD thesis. The short version is that one can diagonalize independently each block, and so save more memory because one works only in a subspace of the Hilbert space.

Antiferromagnetic Heisenberg model on one triangle

Algorithm

There are many algorithm to solve eigen-problems. But most of them need to know the matrix. So we want to focus on algorithm where the matrix can be implicit.

Power iteration

The power iteration is one of them. It is a very simple algorithm to implement and probably the one using the less memory because one need only to store one vector. Assuming elements are double, and applying the up/down symmetry, it takes 256GB of memory. Applying any other symmetry, e.g. translations or rotation C2, will make it fit. The problem is that it converge to the greatest (in absolute value) eigenvalue. We are looking for the ground state, which is the smallest eigenvalue, but there are always a degenerate state of higher absolute eigenvalue.

Locally Optimal Block Preconditioned Conjugate Gradient

Locally Optimal Block Preconditioned Conjugate Gradient (LOBPCG) is a pretty good candidate. One can directly compute the smallest eigenvalue. The first step is to minimize the Rayleigh quotient, which can be done by only storing two floating-point variables, so at most 4Bytes. Then, one applies a simple iterative method to find the eigenvector. I did not try yet this method, but it looks quite promising. My main concern, and I guess that is why it is not used for very large matrix, is that one need to minimize the eigenvalue over 2Ns variables, in my case, 68,719,476,736 independent variables. So it will definitely takes a very long time to converge, but I will give it a try eventually.

Lanczos algorithm

Lanczos algorithm is wildly use in condensed matter physics to find the ground state of a system. It is a very fast algorithm. But one may need to store more informations. I said may because now that I am having a fresh look at the algorithm, it may be possible to store only one vector. I have to think about it.

In any case, a common way, because very easy, to write the routine is

  1. Build the reduced sparse matrix (sparse matrix + Hermitian + symmetries)
  2. Send the matrix to the routine
  3. In the routine, at each iteration, apply the Lanczos vector to the matrix
This is what I did during my PhD thesis. Now, I want to use the fact that one can build the vector v with just a function such that v ↦ H v, where H is the Hamiltonian. In this case, one do not need to store the Hamiltonian anymore. I did not finish yet to rewrite my code, so I will come back to this algorithm later.

Random numbers

Lanczos algorithm begins by initializing a random vector.

Broken random numbers generators on Apple products
Two weeks ago, I wrote about bad practices in random number generation, where the actual good practices are inside the code sources and slightly documented. I wrote

"After 107374182350 iterations, the probabilities are still 0. I launched it on my laptop, a MacBook Pro from my lab (without Mac OS, but Ubuntu instead), but it does not have a hardware random generator. Maybe the issue comes from here. Latter, I will try on my server which have one."

rand()%range, or the wrong way to generate random numbers

It turned out that it always gave 0. The reason behind is beyond the scope of this post but I discover after some web research that it is a well-known issue that Apple products have a zero-probably for some numbers, e.g. the range [0, 7], on their implementation of what is suppose to be a uniform distribution. So, never use an Apple product to perform scientific computation involving rand()!

On a homemade computer, which has a true random generator, using stochastic processes, I obtain good results.


As you can see, I did not wait for the true random generator part to end because even in an environment with a fair level of entropy, it took couple of days for these around 161061273600 iterations because the software pends all its time waiting for the hardware to accumulate enough entropy. In any case, the trend is already clear.
It proves that rand()%range is not uniform, shows that random generators of C++11 standard are indeed uniform, and demonstrates that MaxBook Pro have a broken random number generator.

Lanczos vector

Because the range of random numbers do not span the whole range of numbers that they are suppose to, the initial vector is de facto constrain to a subset of the Hilbert space. In some cases, maybe most of them, this effect will cancel by the iterative method, but it can also be too restive and stuck the iterative process. In particular, it will be problematic on very small systems.

How to diagonalize a matrix of 4,722,366,482,869,645,213,696 elements? Part 1

Wednesday Nov 22, 2017 23:22, last edition on Thursday Nov 23, 2017 00:20
Introduction

I am trying to diagonalize a very large matrix (4,722,366,482,869,645,213,696 elements) in C++ and it leads to some issues. I noticed that I solved most of the issues that I encounter by myself by just pretending to explain the problem to someone. So I decided that for now on, I will share these notes. I will not explain everything, just the technical difficulties. I will give references for the rest, especially my PhD thesis.

Mind your type
Today, I will present you one of the first technical issue that I faced. It is linked to the type of variable.

A simple example is the results of 2N. In my code, I need to compute 236. The most straight forward way to achieve is by using bitwise operations. In fact, 2N can be written 1 << N, for N∈*. Indeed, the operator << move to the right all the bits by the number on the right hand. Few examples:
1 << 0. 1 is not changed, so 1 << 0 = 12 = 110 ≠ 20.
1 << 1 moved the 1 to the right, so 1 << 1 = 102 = 210 = 21
1 << 2 moved the 1 two times to the right, so 1 << 2 = 1002 = 410 = 22.
Here the issue. For C++, 1 is a int, which means that it is at least 16 bits, but the actual number of bits is not specified and is implementation dependent. Let us assume that sizeof(int) is equal to 4. It is the number of bytes, so it means that int is 32 bits (sizeof(int)×8).
××××××××××××××××××××××××××××××××
Only the first 31 bits (sizeof(int)×8-1) represent a positive number, which means that one can only move a bit up to 30 times (sizeof(int)×8-1-1) to the right and still get a positive number.
1 << 30 = 010000000000000000000000000000002 = 107374182410 = 230
1 << 31 = 100000000000000000000000000000002 = -214748364810 ≠ 231
1 << 32 = 000000000000000000000000000000002 = 010 ≠ 232

If you try to compile a code with the last case, you will have a warning

main.cpp: In function ‘int main()’:
main.cpp:10:17: warning: left shift count >= width of type [-Wshift-count-overflow]
  auto val = 1<<32;
                 ^

As you can see auto does not become long long int but will be int, i.e. the return type of 1 << 32.

What can we do?

The case 1 << 31 is pretty easy. We just need to explicitly declare 1 << 31 to be unsigned int. In this case, the last bit is not for the sign, so (unsigned int)1 << 31 = 2147483648 = 231

What about 1 << 32? Can I write (unsigned long long int)1 << 32? According to C++ standard, unsigned long long int is at least 64 bits, so one can think that (unsigned long long int)1 << 32 will do the job. Let us see what happens. It is first 1 << 32 that is computed, which is an int, so it returns 0, which is cast into an unsigned long long int. The result is then 0, so, no, it is not a workaround.
Notice that in this case, the compiler will not give you a warning, which is a bug, I think.

The solution is to actually to recast 1 into a type that stores enough bits for the bitwise operation and then apply the operator. Let us do it step by step
1 is an int, so its binary representation is
000000000000000000000000000000012
Now, we add enough bits with the cast ((unsigned long long int) 1). It has the following binary representation
00000000000000000000000000000000000000000000000000000000000000012
((unsigned long long int) 1) << 32 moves the first 1 32 times
00000000000000000000000000000001000000000000000000000000000000002 = 429496729610 = 232.
Output of 1 << 32 and ((unsigned long long int) 1) << 32

We now have a safe 2N for N∈[1, 63]. It is enough for 236, which was the first thing that I had difficulties with.

Notice the largest number in C++ is 264-1 = 18446744073709551615, which is smaller than the number of elements in my matrix, 4722366482869645213696 = 272. We will see that it will be another problem to tackle.

What's next?

The main problem that I am facing is the memory consumption. I am using Lanczos algorithm do solve the eigen-problem. Right now, I am rewriting my code to use a very nice property of this method, which is the fact that the matrix can be defined implicitly.

Edit: The source code that I used for the tests. To compile

% g++ -std=gnu++14 main.cpp

main.cpp
     1 #include <string>   // std::string
     2 #include <iostream> // ostream (std::ostream, std::endl)
     3                     // std::cout
     4 #include <typeinfo> // typeid
     5 #include <bitset>   // std::bitset
     6 #include <array>    // std::array
     7 #include <memory>   // std::shared_ptr
     8 
     9 // Reviewed
    10 const std::string exec(const auto * cmd)
+   -   11 +-- 14 lines: {
11 {
|   12  std::array<char, 128> buffer;
|   13  std::string result;
|   14  std::shared_ptr< FILE > pipe(popen(cmd, "r"), pclose);
|   15  if(!pipe) throw std::runtime_error("popen() failed!");
|   16  while(!feof(pipe.get()))
|+  |-  17 +---  6 lines: {
17  {
||  18   if(fgets(buffer.data(), 128, pipe.get()) != nullptr)
||+ ||- 19 +----  3 lines: {
19   {
||| 20    result += buffer.data();
||| 21   }
||  22  }
|   23  return result;
|   24 }
    25 
    26 // Reviewed
    27 // No auto for std::ostream
    28 constexpr void display_type(
    29  const auto & name,
    30  const auto & var,
    31  std::ostream & s = std::cout
    32 )
+   -   33 +--  8 lines: {
33 {
|   34  // No auto
|   35  std::string command = "c++filt -t ";
|   36  command += typeid(var).name();
|   37  s<<"Type of \""<<name<<"\""<<std::endl;
|   38  auto stype = exec(command.data());
|   39  s<<stype<<std::endl;
|   40 }
    41 
    42 int main()
+   -   43 +-- 31 lines: {
43 {
|   44  std::cout<<"* 1<<32"<<std::endl;
|   45  auto val1 = 1<<32;
|   46  display_type("1<<32", val1);
|   47  std::cout<<"1<<32 in base 2";
|   48  std::<<std::endl;
|   49  unsigned char * binary1 = reinterpret_cast< decltype(binary1) >(&val1);
|   50  for(auto i = (signed) sizeof(val1) - 1; i >= 0; --i)
|+  |-  51 +---  3 lines: {
51  {
||  52   std::cout<<std::bitset< 8 >(binary1[i]);
||  53  }
|   54  std::cout<<std::endl;
|   55  std::cout<<"1<<32 in base 10";
|   56  std::cout<<std::endl<<val1<<std::endl;
|   57 
|   58  std::cout<<std::endl;
|   59  std::cout<<"* ((unsigned long long int) 1)<<32"<<std::endl;
|   60  auto val2 = ((unsigned long long int) 1)<<32;
|   61  display_type("((unsigned long long int) 1)<<32", val2);
|   62  std::cout<<"((unsigned long long int) 1)<<32 in base 2";
|   63  std::cout<<std::endl;
|   64  unsigned char * binary2 = reinterpret_cast< decltype(binary2) >(&val2);
|   65  for(auto i = (signed) sizeof(val2) - 1; i >= 0; --i)
|+  |-  66 +---  3 lines: {
66  {
||  67   std::cout<<std::bitset< 8 >(binary2[i]);
||  68  }
|   69  std::cout<<std::endl;
|   70  std::cout<<"((unsigned long long int) 1)<<32 in base 10";
|   71  std::cout<<std::endl<<val2<<std::endl;
|   72  return 0;
|   73 }

Captain's Log #2

Tuesday Nov 21, 2017 17:38
To Do List
TootLine

I am working on TootLine, the PHP code that allows you to share your TootLine on your blog, like the one there is on the right or bottom, depending on the size of your screen. I have couple of issues to address before publishing it, which are proper word wrapping, create a cache for the media in order to solve CSP issue, handle the NSFW content that is displayed so far.

Tags' categories

I am planning on adding click-able tags to fetch all articles with matching tags.
Done

Translation

I already published a note in French and I began to write couple of drafts in French, so I would like to make a French version of this blog, with most of the articles translated.

Content Security Policy (CSP) headers

I added Content Security Policy (CSP) headers.

RSS feed

I added few elements to MySQLiToRSS, I add proper end of file to the generated RSS feed and I used the fact that I made tags click-able to add domain to the category element.

Better looking links

I changed the URL of some links to make them better looking.

Future

I addition to what remains on the To Do List, I want to add couple of improvement.

More restrictive CSP headers

I want to rewrite some part of the web site to be able to provide more secure CSP headers.

Comments

I am planning on adding a RSS feed for each commentary section so it will be easy to follow. I will also add a cookie to auto fill the fields Name and Website. I will put a check box if you want to add the cookie when you comment.

Tags

I will add the list of all tags on the right panel.

SEO

I will add proper Open Graph protocol and Twitter cards in the headers. I already updated the MySQL database, so everything is ready on this side, I just need to rewrite the headers that I include to make them dynamic.

Better looking links

I already changed the URL of some links to make them better looking, but I did not finish yet. The rewriting rules are not as simple as I expected, if you want to make them SEO compliant.

Better CMS

My work-flow is not the most efficient. Each article points to an actual file, which is not so good, because I need to create a file each I add an entry in this blog. I will improve this soon.

Trackback, impossible?

I tried to add trackback, but the most up to date page about it is more than 5 years old and all links are dead links, including the sample codes to make it work. If someone can explain me how to implement it, I will be pleased :)

How to set up Content Security Policy headers?

Tuesday Nov 21, 2017 04:45

I think a have a simple methodology to build Content Security Policy (CSP) headers. I did it with Apache HTTP Server and Firefox, but it is a generic methodology. I assume that you know what are CSP headers.

Before we start
Add-ons

First, you might want to disable most of your extensions. Indeed, some will add scripts or rewrite part of the displayed HTML code making it hard to distinguish warnings and errors form your code than from the extensions. I kept Test Pilot , Multi-Account Containers and Firefox Lightbeam by Mozilla, Privacy Badger and HTTPS Everywhere by the Electronic Frontier Foundation, and DuckDuckGo Plus by DuckDuckGo.

A useful tool

Laboratory by April King is an extension that allows you to record your website in order to provide a ready CSP header. But it is no fun and it does not push you think about how to rewrite some parts of website in order to improve security. You can also enforce CSP, which is useful if you add another component, for example if you add your Twitter timeline, you will need to adjust your CSP headers. With this tool, it is easy to check, try, add CSP headers, that you can later add to you web server. But for the purpose of this small how to, do not use this extension. If installed, please make sure that none of the check boxes are enabled and that Generated CSP configuration: is set to default-src 'none' if not, click on Delete All Settings or it will be a nightmare.

Laboratory extension

Always keep Developer Tools opened

Another step to avoid spend plenty of time looking at irrelevant answers on Stack Exchange is to open the Developer Tools, go on the options tab and check Disable HTTP Cache (when toolbox is open), and then keep it open at all time. Otherwise, some requests can be cached and you will not understand why your brand new configuration is not taking into account.

Building your CSP headers without blocking content
Report only

We will use the Content-Security-Policy-Report-Only header. When the web browser receive the content of a web page, it will display warnings for each violated CSP directive. We will see later that it can be used in a better way.

Be verbose

I strongly advise to add all possible directives to the header because any warning or error not related to an explicitly defined directive will be reported as violating default-src. This is because directives inherit from default-src if not explicitly set. If you only have something like default-src 'none'; style-src 'self';, then an unsafe-inline for script-src will be reported as violating default-src.

So our starting point will be default-src 'none'; child-src 'none'; connect-src 'none'; font-src 'none'; frame-src 'none'; img-src 'none'; manifest-src 'none'; media-src 'none'; object-src 'none'; script-src 'none'; style-src 'none'; worker-src 'none'; base-uri 'none'; frame-ancestors 'self'; and from this, we will allow one by one what we need.

Send report to your website

We will use a very nice feature of CSP, report-uri. It makes web browsers send a JavaScript Object Notation (JSON) file to the web server at the specified Uniform Resource Identifier (URI). This file will give you the basic instructions to build the correct CSP header. In my case, I created a folder /csp/ with the proper ownership and write rights containing one file index.php

<?php
// Start configure
$log_file dirname(__FILE__) . '/csp-violations.log';
$log_file_size_limit 1000000// bytes - once exceeded no further entries are added
// End configuration
$current_domain $_SERVER['SERVER_NAME'];
http_response_code(204); // HTTP 204 No Content
$json_data file_get_contents('php://input');
// We pretty print the JSON before adding it to the log file
if ($json_data json_decode($json_data)) {
  
$json_data json_encode($json_dataJSON_PRETTY_PRINT JSON_UNESCAPED_SLASHES);
  
// Do not write is file size exceeded
  
if (filesize($log_file) > $log_file_size_limit) {
    exit(
0);
  }
  
file_put_contents($log_file$json_dataFILE_APPEND LOCK_EX);
}
?>
It is a simplified and adapted version of the code you can find here. It will log errors and warnings in /csp/csp-violations.log.

All together

In your virtual host, add the following line

Header set Content-Security-Policy-Report-Only "report-uri /csp/; default-src 'none'; child-src 'none'; connect-src 'none'; font-src 'none'; frame-src 'none'; img-src 'none'; manifest-src 'none'; media-src 'none'; object-src 'none'; script-src 'none'; style-src 'none'; worker-src 'none'; base-uri 'none'; frame-ancestors 'self';"
Mind the ' and the ". The set of directives must start and end with ". All arguments of each directive must be surrounded by ' if, and only if, they are keywords. The corollary is do not use ' to surround Uniform Resource Locator (URL) and URI.

Restart Apache HTTP Server

# systemctl restart apache2

Debugging

Visit your website. You should see in the Console tab of the Developer Tools.

In the /csp/ folder of you virtual host, you should see the csp-violations.log file. It contains lines like

{
     "csp-report": {
         "blocked-uri": "self",
         "document-uri": "https://clementfevrier.fr/images/r3.svg",
         "original-policy": "report-uri https://clementfevrier.fr/csp/ https://clementfevrier.fr/images/default-src https://clementfevrier.fr/images/'none'; child-src 'none'; connect-src 'none'; font-src 'none'; frame-src 'none'; img-src 'none'; manifest-src 'none'; media-src 'none'; object-src 'none'; script-src 'none'; style-src 'none'; worker-src 'none'",
         "referrer": "https://clementfevrier.fr/articles/11_rand.php",
         "script-sample": "onclick attribute on g element",
         "source-file": "https://clementfevrier.fr/images/r3.svg",
         "violated-directive": "script-src 'none'"
     }
 }
original-policy displays the CSP header. It is useful to ensure that it matches what you set in our web server. violated-directive tells you with directive you should adjust, in this example script-src and it also remind you its arguments 'none' because it is our starting point. blocked-uri tells you what it blocked, here it is self. So, you just need to replace script-src 'none' by script-src 'self' and the warning will disappear.

Repeat this for each violated directive.

Notice that without explicitly setting all directives, violated-directive will always report to default-src which makes it more difficult to debug.

For each directive that I set, I restart the web server, delete the log file, reload a page from my website in my web browser, and look at the new log.

Don't forget to check different pages of your web site to check all cases.

Your CSP log file does not report anymore violated directive? Let us add the real header.

Apply your CSP

Your header should look like

Header set Content-Security-Policy-Report-Only "report-uri /csp/; default-src 'none'; connect-src 'self'; font-src 'self'; frame-src 'none'; img-src 'self' data: https://toot.forumanalogue.fr; manifest-src 'none'; media-src 'self'; object-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; worker-src 'none'; base-uri 'none'; frame-ancestors 'self';
Just remove the -Report-Only and you are done.
Header set Content-Security-Policy "report-uri /csp/; default-src 'none'; connect-src 'self'; font-src 'self'; frame-src 'none'; img-src 'self' data: https://toot.forumanalogue.fr; manifest-src 'none'; media-src 'self'; object-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; worker-src 'none'; base-uri 'none'; frame-ancestors 'self';

Restart Apache HTTP Server

# systemctl restart apache2

Final checks

First, check that your website renders as you wish.

Then, there are couple of useful tools to perform checks on you CSP headers.

Check their recommendations and the links, they are full of useful informations.

As you can see, I still have to work to achieve a good CSP, but I know you to eliminate most of the so-called insecure inline code. I say so-called because for most of it, if not all of it, it is perfectly secure since I am not in the cases where it can be potentially insecure.

Changing you website and modifying your CSP headers

You can have both Content-Security-Policy-Report-Only and Content-Security-Policy at the time. It is useful to make a more restrictive CSP without blocking content. You can have one report-uri for the block content and one for the report only, which will simplify debugging.

Further reading

MDN Web Docs, by Mozilla, is the only website that I found with proper explanation and reference of CSP.

Captain's Log

Sunday Nov 19, 2017 01:30

Couple of news about my blog.

MySQLiToRSS

First, I fixed the error in the git repository for MySQLiToRSS. The git link actually linked to MySQLiToRSS repository and not to SHA1BruteForce anymore.

Comments

Second, I added a commentary section. I started my intellectual development by arguing with people on a forum, the Forum Analogue, so it is important for me to have people's reviews. I am planning on adding a RSS feed for each commentary section so it will be easy to follow. I will also add a cookie to auto fill the fields Name and Website. I will put a check box if you want to add the cookie when you comment.

Mastodon

In order to promote Mastodon, I added two buttons at the bottom of each article, one to follow me, the other one to share the article.


Mastodon Follow me Mastodon Share
<style>
.mastodon-intent-btn {
  display: inline-block;
  color: #fff; 
  text-decoration: none; 
  font-size: 14px; 
  line-height: 32px; 
  font-weight: 500; 
  background: #2b90d9; 
  border-radius: 4px; 
  padding: 0 18px; 
  padding-left: 16px; 
  font-family: Roboto, sans-serif; 
 box-sizing: content-box;
}
.mastodon-intent-btn img {
    width: 48px; 
    height: 48px; 
    vertical-align: middle; 
    padding-top: 10px; 
    padding-bottom: 10px; 
  }
</style>

<script>
[].forEach.call(document.querySelectorAll('.mastodon-intent-btn'), function (el) {
    el.addEventListener('click', function(e) {
    e.preventDefault();
    window.open(e.target.href, 'mastodon-intent', 'width=400,height=400,resizable=no,menubar=no,status=no,scrollbars=yes');
  });
});
</script>

<a href='web+mastodon://follow?uri=acct:me@myinstance.tld' class='mastodon-intent-btn' target="_blank">
  <img src='data:image/svg+xml;charset=utf-8;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MS4wNzY5NTRtbSIgaGVpZ2h0PSI2NS40NzgzMW1tIiB2aWV3Qm94PSIwIDAgMjE2LjQxNDQgMjMyLjAwOTc2Ij48cGF0aCBkPSJNMjExLjgwNzM0IDEzOS4wODc1Yy0zLjE4MTI1IDE2LjM2NjI1LTI4LjQ5MjUgMzQuMjc3NS01Ny41NjI1IDM3Ljc0ODc1LTE1LjE1ODc1IDEuODA4NzUtMzAuMDgzNzUgMy40NzEyNS00NS45OTg3NSAyLjc0MTI1LTI2LjAyNzUtMS4xOTI1LTQ2LjU2NS02LjIxMjUtNDYuNTY1LTYuMjEyNSAwIDIuNTMzNzUuMTU2MjUgNC45NDYyNS40Njg3NSA3LjIwMjUgMy4zODM3NSAyNS42ODYyNSAyNS40NyAyNy4yMjUgNDYuMzkxMjUgMjcuOTQyNSAyMS4xMTYyNS43MjI1IDM5LjkxODc1LTUuMjA2MjUgMzkuOTE4NzUtNS4yMDYyNWwuODY3NSAxOS4wOXMtMTQuNzcgNy45MzEyNS00MS4wODEyNSA5LjM5Yy0xNC41MDg3NS43OTc1LTMyLjUyMzc1LS4zNjUtNTMuNTA2MjUtNS45MTg3NUM5LjIzMjM0IDIxMy44MiAxLjQwNjA5IDE2NS4zMTEyNS4yMDg1OSAxMTYuMDkxMjVjLS4zNjUtMTQuNjEzNzUtLjE0LTI4LjM5Mzc1LS4xNC0zOS45MTg3NSAwLTUwLjMzIDMyLjk3NjI1LTY1LjA4MjUgMzIuOTc2MjUtNjUuMDgyNUM0OS42NzIzNCAzLjQ1Mzc1IDc4LjIwMzU5LjI0MjUgMTA3Ljg2NDg0IDBoLjcyODc1YzI5LjY2MTI1LjI0MjUgNTguMjExMjUgMy40NTM3NSA3NC44Mzc1IDExLjA5IDAgMCAzMi45NzUgMTQuNzUyNSAzMi45NzUgNjUuMDgyNSAwIDAgLjQxMzc1IDM3LjEzMzc1LTQuNTk4NzUgNjIuOTE1IiBmaWxsPSIjZmZmIi8+PHBhdGggZD0iTTE3Ny41MDk4NCA4MC4wNzd2NjAuOTQxMjVoLTI0LjE0Mzc1di01OS4xNWMwLTEyLjQ2ODc1LTUuMjQ2MjUtMTguNzk3NS0xNS43NC0xOC43OTc1LTExLjYwMjUgMC0xNy40MTc1IDcuNTA3NS0xNy40MTc1IDIyLjM1MjV2MzIuMzc2MjVIOTYuMjA3MzRWODUuNDIzMjVjMC0xNC44NDUtNS44MTYyNS0yMi4zNTI1LTE3LjQxODc1LTIyLjM1MjUtMTAuNDkzNzUgMC0xNS43NCA2LjMyODc1LTE1Ljc0IDE4Ljc5NzV2NTkuMTVIMzguOTA0ODRWODAuMDc3YzAtMTIuNDU1IDMuMTcxMjUtMjIuMzUyNSA5LjU0MTI1LTI5LjY3NSA2LjU2ODc1LTcuMzIyNSAxNS4xNzEyNS0xMS4wNzYyNSAyNS44NS0xMS4wNzYyNSAxMi4zNTUgMCAyMS43MTEyNSA0Ljc0ODc1IDI3Ljg5NzUgMTQuMjQ3NWw2LjAxMzc1IDEwLjA4MTI1IDYuMDE1LTEwLjA4MTI1YzYuMTg1LTkuNDk4NzUgMTUuNTQxMjUtMTQuMjQ3NSAyNy44OTc1LTE0LjI0NzUgMTAuNjc3NSAwIDE5LjI4IDMuNzUzNzUgMjUuODUgMTEuMDc2MjUgNi4zNjg3NSA3LjMyMjUgOS41NCAxNy4yMiA5LjU0IDI5LjY3NSIgZmlsbD0iIzMwODhkNCIvPjwvc3ZnPg==' alt='Mastodon'>
  Follow me
</a>

<?php
$title 
"My title";
$url "https://mydomain.tld/myarticle.php";
$mastodon "<a href='web+mastodon://share?text=";
$mastodonText $title;
$mastodonText .= " " $url;

$url_reserved_char = array("!""#""$""&""'""("")""*""+"",""/"":"";""=""?""@""[""]");
$url_subtitute = array("%21""%23""%24""%26""%27""%28""%29""%2A""%2B""%2C""%2F""%3A""%3B""%3D""%3F""%40""%5B""%5D");
for (
$x 0$x <= 10$x++)
{
 
$mastodonText str_replace($url_reserved_char[$x], $url_subtitute[$x], $mastodonText);
}

$mastodonText str_replace(" ""+"$mastodonText);
$mastodon .= $mastodonText;
$mastodon .= "' class='mastodon-intent-btn' target=\"_blank\" >";
echo 
$mastodon
?>

<img src='data:image/svg+xml;charset=utf-8;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MS4wNzY5NTRtbSIgaGVpZ2h0PSI2NS40NzgzMW1tIiB2aWV3Qm94PSIwIDAgMjE2LjQxNDQgMjMyLjAwOTc2Ij48cGF0aCBkPSJNMjExLjgwNzM0IDEzOS4wODc1Yy0zLjE4MTI1IDE2LjM2NjI1LTI4LjQ5MjUgMzQuMjc3NS01Ny41NjI1IDM3Ljc0ODc1LTE1LjE1ODc1IDEuODA4NzUtMzAuMDgzNzUgMy40NzEyNS00NS45OTg3NSAyLjc0MTI1LTI2LjAyNzUtMS4xOTI1LTQ2LjU2NS02LjIxMjUtNDYuNTY1LTYuMjEyNSAwIDIuNTMzNzUuMTU2MjUgNC45NDYyNS40Njg3NSA3LjIwMjUgMy4zODM3NSAyNS42ODYyNSAyNS40NyAyNy4yMjUgNDYuMzkxMjUgMjcuOTQyNSAyMS4xMTYyNS43MjI1IDM5LjkxODc1LTUuMjA2MjUgMzkuOTE4NzUtNS4yMDYyNWwuODY3NSAxOS4wOXMtMTQuNzcgNy45MzEyNS00MS4wODEyNSA5LjM5Yy0xNC41MDg3NS43OTc1LTMyLjUyMzc1LS4zNjUtNTMuNTA2MjUtNS45MTg3NUM5LjIzMjM0IDIxMy44MiAxLjQwNjA5IDE2NS4zMTEyNS4yMDg1OSAxMTYuMDkxMjVjLS4zNjUtMTQuNjEzNzUtLjE0LTI4LjM5Mzc1LS4xNC0zOS45MTg3NSAwLTUwLjMzIDMyLjk3NjI1LTY1LjA4MjUgMzIuOTc2MjUtNjUuMDgyNUM0OS42NzIzNCAzLjQ1Mzc1IDc4LjIwMzU5LjI0MjUgMTA3Ljg2NDg0IDBoLjcyODc1YzI5LjY2MTI1LjI0MjUgNTguMjExMjUgMy40NTM3NSA3NC44Mzc1IDExLjA5IDAgMCAzMi45NzUgMTQuNzUyNSAzMi45NzUgNjUuMDgyNSAwIDAgLjQxMzc1IDM3LjEzMzc1LTQuNTk4NzUgNjIuOTE1IiBmaWxsPSIjZmZmIi8+PHBhdGggZD0iTTE3Ny41MDk4NCA4MC4wNzd2NjAuOTQxMjVoLTI0LjE0Mzc1di01OS4xNWMwLTEyLjQ2ODc1LTUuMjQ2MjUtMTguNzk3NS0xNS43NC0xOC43OTc1LTExLjYwMjUgMC0xNy40MTc1IDcuNTA3NS0xNy40MTc1IDIyLjM1MjV2MzIuMzc2MjVIOTYuMjA3MzRWODUuNDIzMjVjMC0xNC44NDUtNS44MTYyNS0yMi4zNTI1LTE3LjQxODc1LTIyLjM1MjUtMTAuNDkzNzUgMC0xNS43NCA2LjMyODc1LTE1Ljc0IDE4Ljc5NzV2NTkuMTVIMzguOTA0ODRWODAuMDc3YzAtMTIuNDU1IDMuMTcxMjUtMjIuMzUyNSA5LjU0MTI1LTI5LjY3NSA2LjU2ODc1LTcuMzIyNSAxNS4xNzEyNS0xMS4wNzYyNSAyNS44NS0xMS4wNzYyNSAxMi4zNTUgMCAyMS43MTEyNSA0Ljc0ODc1IDI3Ljg5NzUgMTQuMjQ3NWw2LjAxMzc1IDEwLjA4MTI1IDYuMDE1LTEwLjA4MTI1YzYuMTg1LTkuNDk4NzUgMTUuNTQxMjUtMTQuMjQ3NSAyNy44OTc1LTE0LjI0NzUgMTAuNjc3NSAwIDE5LjI4IDMuNzUzNzUgMjUuODUgMTEuMDc2MjUgNi4zNjg3NSA3LjMyMjUgOS41NCAxNy4yMiA5LjU0IDI5LjY3NSIgZmlsbD0iIzMwODhkNCIvPjwvc3ZnPg==' alt='Mastodon'>
  Share
</a>
Favicon

I added a favicon to the blog.

Tags

I added tags for each articles, currently at the top of the article.

PhD thesis

I manage to get rid of the iframe to display my PhD thesis. I generate the html base using pdf2htmlEX, which needs new maintainers. After a bit of rewriting, I think that I achieved something better integrated to this blog.

If anyone is interested, I can publish the code, but because it is based on an unmaintained software, I do not know if it is worth the trouble.

Statistics

Last, but not least, I spend two days to rewrite AWStats from Perl to PHP and adding W3CSS. I manage to get rid of the iframe to integrate the statistics to the blog. Overall, I made it a lot more modular than the original script, or maybe I have this feeling because I know my own code better or because I am more comfortable in PHP.



I think one of the nicest improvements are the filters. They are using GET, which I kept but I do not display by default. In my version, I use JavaScript to make an on-the-fly filter.



Fonts

I fix few serious font issues. For now on, they should be displayed problem.

Future
TootLine

I am working on TootLine, the PHP code that allows you to share your TootLine on your blog, like the one there is on the right or bottom, depending on the size of your screen. I have couple of issues to address before publishing it, which are proper word wrapping, create a cache for the media in order to solve CSP issue, handle the NSFW content that is displayed so far.

Tags' categories

I am planning on adding clickable tags to fetch all articles with matching tags.

Translation

I already published a note in French and I began to write couple of drafts in French, so I would like to make a French version of this blog, with most of the articles translated.

rand()%range, or the wrong way to generate random numbers

Saturday Nov 11, 2017 03:44
The mathematics

In C++, rand() returns a random number between 0 and RAND_MAX, included. It is a uniform distribution, meaning that the probability Pn to have n ∈ [0, RAND_MAX] is Pn = 1∕(RAND_MAX+1) = P. Now, a common practice is to generate random numbers using the modulo operator %. rand()%range returns a number x ∈ [0, range-1]. The distribution is not uniform and favors smaller numbers. Indeed, the probabilities become

Px = n=0RAND_MAX Pn δn%range, x
Px = P × (floor(RAND_MAX∕range) + 1), for x ≤ RAND_MAX%range
P × floor(RAND_MAX∕range), otherwise.
One can see that Px is not a constant and the desired behavior is usually a uniform distribution with a probability Pu = 1/range.

Unrealistic working example

Let us assume that RAND_MAX = 2. rand() can return 0, 1 and 2. the probability P to have n ∈ [0, 2] is P = 1∕(2+1) = 1∕3. If range = 2, rand()%range has 3 cases.

  • rand() returns 0, 0%2 = 0.
  • rand() returns 1, 1%2 = 1.
  • rand() returns 2, 2%2 = 0.
Each with a probability P = 1∕3. So, Px=0 = Pn=0+Pn=2 = 2P = 2∕3 and Px=1 = Pn=1 = P = 1∕3, whereas a uniform probability would have been Pu = 1∕2. The ratio between the two probabilities is Px=0∕Px=1 = 2. It means that there is two times more chance to get 0 than 1. The relative error is ∣(Px=0-Px=1)∕Px=1∣ = 1.

Proof of concept

Here a small code that demonstrates the discussion above. It simulate the function rand() for RAND_MAX = 3.

main.cpp
    1 #include <cstdio>   // NULL
    2 #include <ctime>    // time
    3 #include <cstdlib>  // srand
    4 #include <random>   // std::random_device,
    5                     // std::uniform_int_distribution
    6                     // std::default_random_engine generator
    7 #include <iostream> // std::cout, ostream (std::endl)
    8 
    9 #include "functions.h"
   10 
   11 int main()
+  -  12 +-- 72 lines: {
12 {
|  13  // Value of rand_max
|  14  constexpr unsigned long long int rand_max = 2;
|  15  // Set range to maximize the error.
|  16  constexpr unsigned long int range = rand_max;
|  17  // Natural scale is rand_max + 1
|  18  constexpr unsigned long long int scale = rand_max + 1;
|  19  // Number of itrations to accumulate statistic
|  20  // In the unit of the natural scale
|  21  constexpr unsigned long long int Niterations = (unsigned long long int)500000 * scale;
|  22  // Random seed
|  23  srand(time(NULL));
|  24  // True random generator
|  25  std::random_device rd;
|  26  // Entropy of the true random generator
|  27  const auto entropy = rd.entropy();
|  28  std::cout<<"Entropy: "<<entropy<<std::endl;
|  29  // If the entropy is 0, it means there is no true random generator available (e.g. Apple computers)
|  30  // so a pseudo random number generator will be sused instead
|  31  if(entropy > 0)
|+ |- 32 +---  3 lines: {
32  {
|| 33   std::cout<<"True random generator"<<std::endl;
|| 34  }
|  35  else
|+ |- 36 +---  3 lines: {
36  {
|| 37   std::cout<<"Pseudo random generator"<<std::endl;
|| 38  }
|  39  // Uniform distribution to simultate rand() with our custom RAND_MAX
|  40  std::uniform_int_distribution< unsigned long int > distribution1(0, rand_max);
|  41  // Uniform distribution in the range [0, range-1]
|  42  std::uniform_int_distribution< unsigned long int > distribution2(0, range - 1);
|  43  std::cout<<"RAND_MAX: "<<rand_max<<std::endl;
|  44  std::cout<<"range:    "<<range<<std::endl;
|  45  std::cout<<"The "<<(rand_max % range) + 1;
|  46  std::cout<<" first probabilities are greater than the ";
|  47  std::cout<<range - ((rand_max % range) + 1);
|  48  std::cout<<" other ones by a factor:"<<std::endl;
|  49  std::cout<<"Predicted p(0)/p(range-1):                               ";
|  50  std::cout<<(((rand_max + 1) / range) + 1) / (float)(rand_max / range);
|  51  std::cout<<std::endl;
|  52  std::cout<<"Predicted relative error (p(0) - p(range-1))/p(range-1): ";
|  53  std::cout<<(((scale / range) + 1) - (scale / range)) / (float)(scale / range);
|  54  std::cout<<std::endl;
|  55 
|  56  std::cout<<" * Making statistic *"<<std::endl;
|  57 
|  58  std::cout<<" * rand()%range *"<<std::endl;
|  59  constexpr char nameMod [] = "results/mod3.dat";
|  60  if(entropy > 0)
|+ |- 61 +---  3 lines: {
61  {
|| 62   statistic1(rand_max, range, Niterations, nameMod, rd, distribution1, scale);
|| 63  }
|  64  else
|+ |- 65 +---  4 lines: {
65  {
|| 66   std::default_random_engine generator;
|| 67   statistic1(rand_max, range, Niterations, nameMod, generator, distribution1, scale);
|| 68  }
|  69 
|  70  std::cout<<" * uniform *"<<std::endl;
|  71  constexpr char nameUniform [] = "results/uniform3.dat";
|  72  if(entropy > 0)
|+ |- 73 +---  3 lines: {
73  {
|| 74   statistic2(rand_max, range, Niterations, nameUniform, rd, distribution2, scale);
|| 75  }
|  76  else
|+ |- 77 +---  4 lines: {
77  {
|| 78   std::default_random_engine generator;
|| 79   statistic2(rand_max, range, Niterations, nameUniform, generator, distribution2, scale);
|| 80  }
|  81 
|  82  return 0;
|  83 }
functions.h
       1 #ifndef _FUNCTIONS_H_
       2 #define _FUNCTIONS_H_
       3 
       4 #include <fstream>  // std::fstream
       5 #include <iostream> // std::cout, ostream (std::endl)
       6 #include <cmath>    // abs
       7 #include <cstdlib>  // rand
       8 
       9 void read(const auto name, auto & start, auto p)
+    -     10 +-- 23 lines: {
 10 {
|     11  for(unsigned char it = 0; it < 2; ++it)
|+   |-    12 +---  3 lines: {
 12  {
||    13   p[it] = 0;
||    14  }
|     15 
|     16  std::fstream file(name);
|     17  if(file.is_open())
|+   |-    18 +---  9 lines: {
 18  {
||    19   while(file.good())
||+  ||-   20 +----  5 lines: {
 20   {
|||   21    file>>start;
|||   22    file>>p[0];
|||   23    file>>p[1];
|||   24   }
||    25   file.clear();
||    26  }
|     27  file.close();
|     28 
|     29  std::cout<<"Start at trial number "<<start + 1;
|     30  std::cout<<" with probabilities "<<p[0] / (float)(start + 1);
|     31  std::cout<<" and "<<p[1] / (float)(start + 1)<<std::endl;
|     32 }
      33 
      34 void statistic1
      35 (
      36  const auto & rand_max,
      37  const auto & range,
      38  const auto & Niterations,
      39  const auto name,
      40  const auto & scale
      41 )
+    -     42 +-- 36 lines: {
 42 {
|     43  unsigned long long int * p = new unsigned long long int [2];
|     44  unsigned long int index = 0;
|     45  unsigned long long int start = 0;
|     46 
|     47  read(name, start, p);
|     48  std::ofstream file(name, std::ofstream::app);
|     49  for(unsigned long long int it = start + 1; it < Niterations; ++it)
|+   |-    50 +--- 21 lines: {
 50  {
||    51   index = rand() % range;
||    52   if(index == 0)
||+  ||-   53 +----  3 lines: {
 53   {
|||   54    ++p[0];
|||   55   }
||    56   else
||+  ||-   57 +----  6 lines: {
 57   {
|||   58    if(index == (range - 1))
|||+ |||-  59 +-----  3 lines: {
 59    {
||||  60     ++p[1];
||||  61    }
|||   62   }
||    63   if(it % scale == rand_max)
||+  ||-   64 +----  6 lines: {
 64   {
|||   65    if(p[0] != 0 && p[1] != 0)
|||+ |||-  66 +-----  3 lines: {
 66    {
||||  67     file<<it<<" "<<p[0]<<" "<<p[1]<<std::endl;
||||  68    }
|||   69   }
||    70  }
|     71  file.close();
|     72 
|     73  std::cout<<"Computed p(0)/p(range-1):                                ";
|     74  std::cout<<p[0]/(long double)p[1]<<std::endl;
|     75  std::cout<<"Computed relative error (p(0) - p(range-1))/p(range-1):  ";
|     76  std::cout<<std::abs((float)p[0] - p[1])/(long double)p[1]<<std::endl;
|     77 }
      78 
      79 void statistic2
      80 (
      81  const auto & rand_max,
      82  const auto & range,
      83  const auto & Niterations,
      84  const auto name,
      85  auto & generator,
      86  auto & distribution,
      87  const auto & scale
      88 )
+    -     89 +-- 36 lines: {
 89 {
|     90  unsigned long long int * p = new unsigned long long int [2];
|     91  unsigned long int index = 0;
|     92  unsigned long long int start = 0;
|     93 
|     94  read(name, start, p);
|     95  std::ofstream file(name, std::ofstream::app);
|     96  for(unsigned long long int it = start + 1; it < Niterations; ++it)
|+   |-    97 +--- 21 lines: {
 97  {
||    98   index = distribution(generator);
||    99   if(index == 0)
||+  ||-  100 +----  3 lines: {
100   {
|||  101    ++p[0];
|||  102   }
||   103   else
||+  ||-  104 +----  6 lines: {
104   {
|||  105    if(index == (range - 1))
|||+ |||- 106 +-----  3 lines: {
106    {
|||| 107     ++p[1];
|||| 108    }
|||  109   }
||   110   if(it % scale == rand_max)
||+  ||-  111 +----  6 lines: {
111   {
|||  112    if(p[0] != 0 && p[1] != 0)
|||+ |||- 113 +-----  3 lines: {
113    {
|||| 114     file<<it<<" "<<p[0]<<" "<<p[1]<<std::endl;
|||| 115    }
|||  116   }
||   117  }
|    118  file.close();
|    119 
|    120  std::cout<<"Computed p(0)/p(range-1):                                ";
|    121  std::cout<<p[0]/(long double)p[1]<<std::endl;
|    122  std::cout<<"Computed relative error (p(0) - p(range-1))/p(range-1):  ";
|    123  std::cout<<std::abs((float)p[0] - p[1])/(long double)p[1]<<std::endl;
|    124 }
     125 
     126 void statistic1
     127 (
     128  const auto & rand_max,
     129  const auto & range,
     130  const auto & Niterations,
     131  const auto name,
     132  auto & generator,
     133  auto & distribution,
     134  const auto & scale
     135 )
+    -    136 +-- 36 lines: {
136 {
|    137  unsigned long long int * p = new unsigned long long int [2];
|    138  unsigned long int index = 0;
|    139  unsigned long long int start = 0;
|    140 
|    141  read(name, start, p);
|    142  std::ofstream file(name, std::ofstream::app);
|    143  for(unsigned long long int it = start + 1; it < Niterations; ++it)
|+   |-   144 +--- 21 lines: {
144  {
||   145   index = distribution(generator) % range;
||   146   if(index == 0)
||+  ||-  147 +----  3 lines: {
147   {
|||  148    ++p[0];
|||  149   }
||   150   else
||+  ||-  151 +----  6 lines: {
151   {
|||  152    if(index == (range - 1))
|||+ |||- 153 +-----  3 lines: {
153    {
|||| 154     ++p[1];
|||| 155    }
|||  156   }
||   157   if(it % scale == rand_max)
||+  ||-  158 +----  6 lines: {
158   {
|||  159    if(p[0] != 0 && p[1] != 0)
|||+ |||- 160 +-----  3 lines: {
160    {
|||| 161     file<<it<<" "<<p[0]<<" "<<p[1]<<std::endl;
|||| 162    }
|||  163   }
||   164  }
|    165  file.close();
|    166 
|    167  std::cout<<"Computed p(0)/p(range-1):                                ";
|    168  std::cout<<p[0]/(long double)p[1]<<std::endl;
|    169  std::cout<<"Computed relative error (p(0) - p(range-1))/p(range-1):  ";
|    170  std::cout<<std::abs((float)p[0] - p[1])/(long double)p[1]<<std::endl;
|    171 }
     172 
     173 #endif
You can download the files by clicking on their name. To compile,
% g++ -std=gnu++14 main.cpp
Of course, you can add more options, like -Ofast and other that will speed up the code. Create a folder results before executing the code
% mkdir results
and finally, execute it
% ./a.out
It should last less than a second. It generate two files in the folder results. Each contains 3 columns, the number of iterations, Px=0, and Px=1. mod.dat contains the results when using rand()%RAND_MAX and uniform.dat the results for a uniform distribution.

Let us now look at the results. I plotted the expected probabilities for a uniform distribution Pu, P and 2P has explained in the previous section. I also plotted the probabilities Pm using the modulo operator and Pu using a uniform distribution. I plotted them in the natural scale in this context, (RAND_MAX+1).

After only few tens of iterations per (RAND_MAX+1), the probabilities are already stables and converged to the probabilities computed above. To ensure the stability, let us draw for a large number of iterations.

After 1500000 iterations, there is no doubt about the stability. It clearly shows that using modulo operator favors smaller number up to 2 times the largest.

Of course, each set of data will look different, but they will converge to the same results. I ran this code many times with the same outcome.

Here the gnuplot files to reproduce the plots

results3_200.gnu
set term svg enhanced mouse
set style fill transparent
set key at 190,0.66
set title 'Convergence after 600 iterations'
set xlabel 'Number of iterations / (RAND\_MAX + 1)'
set ylabel 'Probabilities'
set output "r3_200.svg"
set xrange[0:200]
set yrange[0.3:0.7]
plot 'results/mod3.dat' u ($1/3.):($2/$1) t 'P_m(x=0)' w lp, \
     'results/mod3.dat' u ($1/3.):($3/$1) t 'P_m(x=1)' w lp, \
     'results/uniform3.dat' u ($1/3.):($3/$1) t 'P_u(x=0)' w lp, \
     'results/uniform3.dat' u ($2/3.):($3/$1) t 'P_u(x=1)' w lp, \
     1./3. lw 4 t 'P', \
     2./3. lw 4 t '2P', \
     1./2. lw 4 t 'P_u'
results3.gnu
set term svg enhanced mouse
set style fill transparent
set key at 499000,0.66
set title 'Convergence after 1500000 iterations'
set xlabel 'Number of iterations / (RAND\_MAX + 1)'
set ylabel 'Probabilities'
set output "svg/r3.svg"
set xrange[0:500000]
set yrange[0.3:0.7]
plot 'results/mod3.dat' u ($1/3.):($2/$1) t 'P_m(x=0)' w l, \
     'results/mod3.dat' u ($1/3.):($3/$1) t 'P_m(x=1)' w l, \
     'results/uniform3.dat' u ($1/3.):($3/$1) t 'P_u(x=0)' w l, \
     'results/uniform3.dat' u ($2/3.):($3/$1) t 'P_u(x=1)' w l, \
     1./3. lw 1 t 'P', \
     2./3. lw 1 t '2P', \
     1./2. lw 1 t 'P_u'

General proof of concept

I entitled unrealistic example above because RAND_MAX is most likely defined as (232∕2)-1, i.e. the greatest int. The worst case happens when range = RAND_MAX. Indeed, the probability to have 0, Pm(x=0), is twice the any other probability Pm(x≠0). Using the same notation as above, Pm(x=0) = 2P and Pm(x≠0) = P.
Notice that P = Pu.

I chose to compare Pm(x=0) with Pm(x=RAND_MAX-1). In the code above, one can just change the variable rand_max by RAND_MAX on line 14, and call the proper function statistic1 that uses the actual rand() and that is enough. However, it will take too long to terminate (few years). So one should replace Niterations by a smaller number, for example (unsigned long long int)50 * scale = 107374182350. It should take couple of hours to run and should be enough to see the trend.

Let me show you the new main

main.cpp
    1 #include <cstdio>   // NULL
    2 #include <ctime>    // time
    3 #include <cstdlib>  // srand, RAND_MAX
    4 #include <random>   // std::random_device,
    5                     // std::uniform_int_distribution
    6                     // std::default_random_engine generator
    7 #include <iostream> // std::cout, ostream (std::endl)
    8 
    9 #include "functions.h"
   10 
   11 int main()
+  -  12 +-- 62 lines: {
12 {
|  13  // Value of rand_max
|  14  constexpr unsigned long long int rand_max = RAND_MAX;
|  15  // Set range to maximize the error.
|  16  constexpr unsigned long int range = rand_max;
|  17  // Natural scale is rand_max + 1
|  18  constexpr unsigned long long int scale = rand_max + 1;
|  19  // Number of itrations to accumulate statistic
|  20  // In the unit of the natural scale
|  21  constexpr unsigned long long int Niterations = (unsigned long long int)50 * scale;
|  22  // Random seed
|  23  srand(time(NULL));
|  24  // True random generator
|  25  std::random_device rd;
|  26  // Entropy of the true random generator
|  27  const auto entropy = rd.entropy();
|  28  std::cout<<"Entropy: "<<entropy<<std::endl;
|  29  // If the entropy is 0, it means there is no true random generator available (e.g. Apple computers)
|  30  // so a pseudo random number generator will be sused instead
|  31  if(entropy > 0)
|+ |- 32 +---  3 lines: {
32  {
|| 33   std::cout<<"True random generator"<<std::endl;
|| 34  }
|  35  else
|+ |- 36 +---  3 lines: {
36  {
|| 37   std::cout<<"Pseudo random generator"<<std::endl;
|| 38  }
|  39  // Uniform distribution in the range [0, range-1]
|  40  std::uniform_int_distribution< unsigned long int > distribution2(0, range - 1);
|  41  std::cout<<"RAND_MAX: "<<rand_max<<std::endl;
|  42  std::cout<<"range:    "<<range<<std::endl;
|  43  std::cout<<"The "<<(rand_max % range) + 1;
|  44  std::cout<<" first probabilities are greater than the ";
|  45  std::cout<<range - ((rand_max % range) + 1);
|  46  std::cout<<" other ones by a factor:"<<std::endl;
|  47  std::cout<<"Predicted p(0)/p(range-1):                               ";
|  48  std::cout<<(((rand_max + 1) / range) + 1) / (float)(rand_max / range);
|  49  std::cout<<std::endl;
|  50  std::cout<<"Predicted relative error (p(0) - p(range-1))/p(range-1): ";
|  51  std::cout<<(((scale / range) + 1) - (scale / range)) / (float)(scale / range);
|  52  std::cout<<std::endl;
|  53 
|  54  std::cout<<" * Making statistic *"<<std::endl;
|  55 
|  56  std::cout<<" * rand()%range *"<<std::endl;
|  57  constexpr char nameMod [] = "results/mod.dat";
|  58  statistic1(rand_max, range, Niterations, nameMod, scale);
|  59 
|  60  std::cout<<" * uniform *"<<std::endl;
|  61  constexpr char nameUniform [] = "results/uniform.dat";
|  62  if(entropy > 0)
|+ |- 63 +---  3 lines: {
63  {
|| 64   statistic2(rand_max, range, Niterations, nameUniform, rd, distribution2, scale);
|| 65  }
|  66  else
|+ |- 67 +---  4 lines: {
67  {
|| 68   std::default_random_engine generator;
|| 69   statistic2(rand_max, range, Niterations, nameUniform, generator, distribution2, scale);
|| 70  }
|  71 
|  72  return 0;
|  73 }

At the time of writing, I launched the code a bit more than two hour ago, so only the part for rand()%range is done. The second part seems to have difficulties to accumulate statistic. After 107374182350 iterations, the probabilities are still 0. I launched it on my laptop, a MacBook Pro from my lab (without Mac OS, but Ubuntu instead), but it does not have a hardware random generator. Maybe the issue comes from here. Latter, I will try on my server which have one.

Anyway, let us look at what we obtained so far.

Well, it looks good. The probabilities are converging to the expected one.

It shows that even in the case of a real life RAND_MAX, in this case, there are two times more chance to obtain 0 than any other number.

Here the gnuplot file to reproduce the plot

results.gnu
set term svg enhanced mouse
set style fill transparent
#set key at 499000,0.66
set title 'Convergence after 107374182350 iterations'
set xlabel 'Number of iterations / (RAND\_MAX + 1)'
set ylabel 'Probabilities (10^-^9)'
set output "r.svg"
set xrange[0:50]
#set yrange[0.3:0.7]
plot 'results/mod.dat' u ($1/2147483648.):($2/$1*1000000000.) t 'P_m(x=0)' w lp lc 1, \
     'results/mod.dat' u ($1/2147483648.):($3/$1*1000000000.) t 'P_m(x=RAND\_MAX-1)' w lp lc 2, \
     'results/uniform.dat' u ($1/2147483648.):($2/$1*1000000000.) t 'P_u(x=0)' w lp lc 3, \
     'results/uniform.dat' u ($1/2147483648.):($3/$1*1000000000.) t 'P_u(x=1)' w lp lc 4, \
     1./2147483648.*1000000000. lw 1 t 'P, P_u', \
     2./2147483648.*1000000000. lw 1 t '2P'

The worst and the best, a short story on prime numbers

Let us see what are the best and the worst cases.

The best

Let us assume that RAND_MAX is an odd number, which most likely the case because probably defined as (28×2n)∕2-1. It implies that RAND_MAX%2 = 1. So, Pm(x=0) = Pm(x=1). It means that for an odd RAND_MAX, it is always safe to generate random numbers x ∈[0, 1]. It is not the only case. As a general rule, it is always safe to generate random numbers when (RAND_MAX+1)%range = 0.

The worst

The worst is if RAND_MAX+1 is a prime number. Indeed, the condition (RAND_MAX+1)%range = 0 can be never be satisfied to generate random numbers using the modulo operator.
In practice, it is unlikely to happen because of the definition above implies that RAND_MAX+1 will be even.

But as a general rule, I use two criteria, the rarity and the ratio between the two different possible probabilities. With these two criteria, the worst is considered when a single number has a bigger probability than the other ones. In fact, it will be always 0 and it happens each time the following condition is fulfilled RAND_MAX%range = 0. The ratio increases as range increases and thus is maximum for range = RAND_MAX.

A concluding word

I hope that you will be careful next time that you will generate random numbers. C++, and especially C++11, provides great useful tools to tackles this problems. Using former standards or C, you will just need to write a simple function that will make your distribution uniform again. I advice you to look at the default one, It is pretty simple, easy to understand, and quick to code.

I hope that you enjoyed it. There is comment section yet, I am writing my own, but feel free to contact me for review, comment, thoughts, using social media like Mastodon, emails, XMPP, etc.
Share if you liked it :)

MySQLiToRSS

Wednesday Nov 08, 2017 00:54

I wrote a new piece of code to generate a RSS feed from a MySQL database. I named it MySQLiToRSS. It is a PHP file that generate a RSS 2.0 feed. It is licensed under GPLv3. It handles sorting by date, the use of HTML in the description of an item, which allow to render the article as it appears in the feed reader, excepted for the CSS sheets, and multitag articles. It is based on Version 2.0.11 of the RSS 2.0 specification, the most up to date at the time of writing this software. Some optional items are missing because I do not use them. I might add them later (some or all). I will be pleased to add optional items if requested.

SHA1BruteForce

Wednesday Nov 08, 2017 00:05

I'm proud to announce my first (free) software, SHA1BruteForce, that performs brute-force attack to crack SHA-1 hash.
Page of the project

Why?

After my 10yo Firefox session crashed, I lost a password stored in it. But, I managed to find the hash and it turns out to be a SHA-1 hash (software installed in 2009 on my server). I could change it, I guess, but I knew that SHA-1 is now considered as a weak encryption (although the first real collision is from February), so I challenged myself to recover it by writing a piece of code that do the job. It took me a bit more than a day to achieve a working code.
After, I began to optimized it and to have fundamental questioning about C++.

It is pretty simple and it seems to perform well. It takes about 4h to crack any 6 characters password on my computer. So I decided to publish it on my server, which was not as simple as I expected.
But I also have account in the main git platforms.
So I also published it on GitHub, GitLab and FramaGit, more know by the French.

It is licensed under GPL3.

It performs the tasks on the CPU only. GPU implementation does not seems possible at the time using only free software. Indeed, CUDA required the proprietary drivers and OpenCL does not seems to work properly with Nouveau (last version of the Linux kernel, i.e.4.13, on Ubuntu 16.04). But I want to use only free software (and I cannot install Nvidia drivers anyway, they do not work on my system).

It is not a revolutionary tools that intends to bit existing ones. I did it for myself and share it for anyone interested.

It is my first published code, so there are most likely some improvements to do on how to write the manual, how to write the code so it can be used by others, how I should comment it, and so on. The same goes for the code itself. Feel free to comment, share, submit commits, report bugs, etc.

A × C = 8, ou pourquoi quand je me présente la réaction est j'ai vu un reportage sur Arte.

Monday Oct 30, 2017 22:30
Tu fais quoi dans la vie ?

Je suis docteur en physique théorique. Quand je dis que j'ai fait une thèse en physique, j'ai souvent comme réaction

≪ Ah oui, une fois j'ai vu un reportage en astrophysique sur Arte. ≫
Cela m'est encore arrivé ce vendredi. Je viens d'un domaine où expliquer ce que je fais ou étudie n'est pas directement accessible au public. Ce n'est généralement pas le cas dans les sciences humaines. Ces derniers peuvent souvent donner leur sujet de thèse et être compris, par exemple, Les recueils de poésie funèbre imprimés en Italie, en France et dans les Îles britanniques (1587-1644). Je n'ai jamais étudié la littérature comparée et pourtant je comprends ce titre de thèse. Mon titre de thèse est Nouvelles phases électroniques avec orbitales eg dans les réseaux triangulaires. Je ne le dis jamais car plus d'un mot sur deux est incompréhensible par le public. Je dis encore moins ce que je fais en pratique car cela rend le sujet encore plus obscur. En effet, je vais souvent faire des calculs du genre A × B = 8. Et c'est pourtant extrêmement simple dès qu'on explique par étape.

Le système

J'ai un réseau, c'est à dire que mon système est une collection de points, appelés sites. Par exemple, une ligne de 4 sites
× × × ×

L'objet

J'étudie des électrons. Ils ont la particularité de ne pas pouvoir se trouver au même endroit en même temps. Ici, endroit a une définition un peu particulière car ça ne se réfère pas à un lieu, mais à un état. Oublions cet aspect pour des raisons de simplicité. Cela veut dire que sur chaque site ×, je peux avoir soit 0, soit 1 électron. Voici toutes les possibilités :

××××
0000
0001
0010
0011
0100
0101
0110
0111
1000
1001
1010
1011
1100
1101
1110
1111
Chaque ligne représente ce que l'on appelle un état, différent de l'état d'un électron. L'ordre est arbitraire et j'ai fait le choix du binaire naturel. Il y en 16 et une manière de les représenter est de leur assigner un symbole, par exemple les 10 chiffres puis les premières lettres de l'alphabet :
0000=0
0001=1
0010=2
0011=3
0100=4
0101=5
0110=6
0111=7
1000=8
1001=9
1010=A
1011=B
1100=C
1101=D
1110=E
1111=F
C'est la convention utilisée en hexadécimal.

La problématique

On considère deux états, par exemple 1010 (A) et 1100 (C), et on se demande quels sont les sites occupés par les deux états. Pour cela, on se demande pour chaque site s'il y a un électron sur A et C. et se comporte comme on peut si attendre.

  • 0 et 0 ne donne rien (0).
  • 0 et 1 ne donne rien (0).
  • 1 et 0 ne donne rien (0).
  • 1 et 1 donne quelque chose (1).
C'est de l'algèbre de Boole. Ces quatre lignes, que l'on appelle table de vérité, car on associe généralement 0 à Faux et 1 à Vrai, se comportent exactement comme une multiplication.
0×0=0
0×1=0
1×0=0
1×1=1
En répétant cette opération pour chaque site, on peut écrire A × C = 1010 × 1100.
1010
× 1100
= 1000
Seul le site le plus à gauche est occupé par les deux états, 1000. En regardant la liste plus haut, on voit que cet état, 1000, correspond à 8. Nous avons donc bien A × C = 8. Rien de mystique ou de compliqué là dedans.

Le scientifique dans la société

En fait, même des sujets qui apparaissent compliqués sont seulement une association de concepts simples comme celui que je viens de présenter. Malgré cela, la représentation pour le grand public des sciences dures est bien loin de la vérité et perdure avec des documentaires et des divertissements avec pleins de représentations artistiques des travaux et d'équations compliquées. Cela donne par exemple dans un épisode de The Big Bang Theory

Bien que d'apparence compliquée, cela est assez simple. Il y a premièrement une erreur dans la question.

≪ Solve the equation! ≫
Vous noterez l'intonation quasi prophétique. Ce n'est pas une équation. Une équation comporte un signe égal et au moins une inconnue à trouver. Ici, ce qu'il faut comprendre, c'est calculer l'intégrale. L'intégrale en question est du niveau d'un première année de master en physique. Une intégrale est juste une sorte de somme. Quelqu'un comme Sheldon Cooper, le personnage au maillot jaune dans la série, ne devrait pas paraître si surpris. Si on reprend rapidement ensemble cette somme, on peut vite la comprendre.
The Big Bang Theory
On a un électron, à gauche, qui interagit avec un muon, à droite, grâce à un photon, au milieu. Si on prend le carré du module de cette somme, on obtient la probabilité d'interaction entre un électron et un muon, appelée section efficace. Prendre le carré veut dire multiplier le résultat par lui-même, par exemple x × x. Le module est la distance par rapport à 0, par exemple 1 est à 1 de 0 et -2 à 2 de 0. Lorsque les objets sont très petits, les règles changent et les choses ne se passent pas toujours comme notre entendement peut le percevoir. On ne sait pas si deux particules vont interagir, on calcule donc leur probabilité d'interaction. C'est ce à quoi cette somme sert. Il y a quelques règles à respecter en physique comme la conversation de l'énergie et de l'impulsion, c'est le terme entouré en bleu sur la seconde ligne. Un étudiant en physique passera environ deux heures à calculer un tel terme la première fois. La partie supérieure avec le diagramme est juste une manière plus élégante et courte d'écrire la somme qui se trouve en bas. Pourtant ces écritures sont biens équivalentes. Tout cela pour vous dire que tout cela paraît compliqué car c'est juste écrit dans une autre langue, la physique, mais que la traduction est compréhensible.

Server Git repository with Apache HTTP Server - Smart HTTP

Wednesday Oct 25, 2017 18:59, last edition on Wednesday Oct 25, 2017 20:17
There is a lot of outdated documentations about how to make your git repositories available through HTTP, even in the official Reference Manual. There are not working, not well documented, and trying to adjust them can lead to serious security issues like allowing anonymous users to push commits. After hours of reading the official manual, discussions about people struggling with the configuration, I finally managed to have a working set up with the expected behavior. What I want to do is sharing one of my repositories through HTTP with Apache HTTP Server with anonymous users allowed to pull and clone, and only register users allowed to push, which is the expected behavior in most cases. This for Apache HTTP Server version 2.4 because the configuration changed compare to version 2.2. The first step is to enable the required mods
# a2enmod cgi alias env
# systemctl restart apache2
With mpm event instead of prefork, which the case is you enables HTTP/2 on Ubuntu Xenial, you will have a warning about the fact it enable cgid, not cgi, but it does not affect this configuration. The second step is to change your virtual host. You need to choose a method to authenticate the users. Because I will be the only one to push commit, I will use the most simple configuration which is AuthType Basic. You can choose other ones, but I will not cover it. You need to create a file that contains users and their password, if not already done. To create the user USER in the file /etc/htpasswd/.htpasswd
# mkdir -p /etc/htpasswd/
# htpasswd -c /etc/htpasswd/.htpasswd USER
Now, if you want to server repositories stored in /var/www/git with the URL mydomain.tld/git/ change your virtual host by adding the following lines
SetEnv GIT_PROJECT_ROOT /var/www/git
SetEnv GIT_HTTP_EXPORT_ALL
ScriptAlias /git/ /usr/lib/git-core/git-http-backend/
<Files "git-http-backend">
 AuthType Basic
 AuthName "Git Access"
 AuthUserFile /etc/htpasswd/.htpasswd
 Require expr !(%{QUERY_STRING} -strmatch '*service=git-receive-pack*' || %{REQUEST_URI} =~ m#/git-receive-pack$#)
 Require valid-user
</Files>
Restart Apache HTTP Server and your are done!
# systemctl restart apache2
This is done!
To go a bit further about git, let us consider that you have a local repository called MyProject that you want to share. On the webserver, you need to initialize the repository
# mkdir -p /var/git/MyProject.git
# cd /var/git/MyProject.git
# git init --bare
# chown -R www-data:www-data /var/git/
The last command set the proper ownership on the files. If you don't do it, you will be able to push locally but not remotely. For the next repository, you will not need to perform the command on the whole directory. Just do
# mkdir /var/git/MyNEWProject.git
# cd /var/git/MyNEWProject.git
# git init --bare
# chown -R www-data:www-data /var/git/MyNEWProject.git
Now, push your project from your computer to the web server
% git remote set-url origin --push --add https://USER:PASSWORD@mydomain.tld/git/MyProject.git
% git remote -v
origin https://USER:PASSWORD@mydomain.tld/git/MyProject.git
% git push Delta compression using up to 8 threads.
Compressing objects: 100% (9/9), done.
Writing objects: 100% (9/9), 20.15 KiB | 0 bytes/s, done.
Total 9 (delta 1), reused 0 (delta 0)
To https://USER:PASSWORD@mydomain.tld/git/MyProject.git
 * [new branch]      master -> master
The second line just check that the previous command worked. On another computer, you can clone the project on other computers with
% git clone https://mydomain.tld/git/MyProject.git
If you try to push from the second computer, you will need to authenticate
% git push
Username for 'https://mydomain.tld': USER
Password for 'https://USER@mydomain.tld':
Counting objects: 2, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (2/2), 222 bytes | 0 bytes/s, done.
Total 2 (delta 1), reused 0 (delta 0)
To https://mydomain.tld/git/MyProject.git
   bc49af8..f7121b5  master -> master
To add the authentication
% git remote set-url origin --push --delete https://mydomain.tld/git/MyProject.git
% git remote set-url origin --push --add https://USER:PASSWORD@mydomain.tld/git/MyProject.git
and you are done!

Are ^ and != operators equivalent on unsigned char in C++?

Wednesday Oct 25, 2017 03:51, last edition on Wednesday Oct 25, 2017 03:57

I was trying to optimize a C++ code where I check if two unsigned char are different. So the first thing that I wrote was n1 != n2. unsigned char are an integer type, and an efficient way to perform this operation is an exclusive or using bitwise operators, which is ^ in C++. So I could simply change my code to n1 ^ n2. But I was wondering if there are equivalent or if one of them is more efficient. I wrote the simplest functions for each operation in separate files.

% cat neq.cpp
bool f(unsigned char n1, unsigned char n2)
{
 return n1 != n2;
}
% cat xor.cpp
bool f(unsigned char n1, unsigned char n2)
{
 return n1 ^ n2;
}
Then, I compiled them to produce assembler code with the -S option of GCC
% g++ -S neq.cpp xor.cpp
For each source file .cpp, the corresponding assembler code is store in a .s file. If we compare the two file, they are equivalent, of course apart for the file name of the source code
% diff neq.s xor.s
1c1
< .file "neq.cpp"
---
> .file "xor.cpp"
Using ^ or != are strictly equivalent for unsigned char.

My initial goal was to optimize my code but there is nothing that we can do to improve it in C++. To perform optimizations, we will use the compiler. Let us take a look at the assembler code, where the first line is skipped because irrelevant

.text .globl _Z1fhh .type _Z1fhh, @function _Z1fhh: .LFB0: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 movl %edi, %edx movl %esi, %eax movb %dl, -4(%rbp) movb %al, -8(%rbp) movzbl -4(%rbp), %eax cmpb -8(%rbp), %al setne %al popq %rbp .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE0: .size _Z1fhh, .-_Z1fhh .ident "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.5) 5.4.0 20160609" .section .note.GNU-stack,"",@progbits
Let us compile with different sets of flats, -O, or -O1 which is equivalent, will drastically reduce the number of instruction passed to the CPU. Indeed, the block between .cfi_startproc and .cfi_endproc will be reduced to 3 instructions, against 15 without flag.
.text .globl _Z1fhh .type _Z1fhh, @function _Z1fhh: .LFB0: .cfi_startproc cmpb %sil, %dil setne %al ret .cfi_endproc .LFE0: .size _Z1fhh, .-_Z1fhh .ident "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.5) 5.4.0 20160609" .section .note.GNU-stack,"",@progbits
-O2 can be used, -O3 and -Ofast will not affect the assembler code. In my case, the option -march (-march=bdver2) also affects the generate assembler code when combine with -O2. There is also -Os to optimize for size. Because I cannot judge which one is the best based on the assembler code, let us benchmark the operator with a dummy program
% cat main.cpp
int main()
{
 for(unsigned char n1 = 0; n1 < 255; ++n1)
 {
  for(unsigned char n2 = 0; n2 < 255; ++n2)
  {
   for(unsigned short int i = 0; i < 65535; ++i)
   {
    n1 ^ n2;
   }
  }
 }
 unsigned char n1 = 255;
 for(unsigned char n2 = 0; n2 < 255; ++n2)
 {
  for(unsigned short int i = 0; i < 65535; ++i)
  {
   n1 ^ n2;
  }
 }
}
Then, let us write a script to display the computation time in each case
% cat script.sh
#!/bin/bash

printf "g++ main.cpp; time ./a.out"
g++ main.cpp; time ./a.out
printf "\n"
printf "g++ -O1 main.cpp -o o1; time ./o1"
g++ -O1 main.cpp -o o1; time ./o1
printf "\n"
printf "g++ -O2 main.cpp -o o2; time ./o2"
g++ -O2 main.cpp -o o2; time ./o2
printf "\n"
printf "g++ -O2 -march=bdver2 main.cpp -o march; time ./march"
g++ -O2 -march=bdver2 main.cpp -o march; time ./march
printf "\n"
printf "g++ -Os main.cpp -o os; time ./os"
g++ -Os main.cpp -o os; time ./os
We now makethis script executable
% chmod +x script.sh
and we execute it
% ./script.sh g++ main.cpp; time ./a.out real 0m11.138s user 0m11.138s sys 0m0.000s g++ -O1 main.cpp -o o1; time ./o1 real 0m2.649s user 0m2.645s sys 0m0.004s g++ -O2 main.cpp -o o2; time ./o2 real 0m0.002s user 0m0.001s sys 0m0.000s g++ -O2 -march=bdver2 main.cpp -o march; time ./march real 0m0.002s user 0m0.001s sys 0m0.000s g++ -Os main.cpp -o os; time ./os real 0m0.002s user 0m0.001s sys 0m0.000s
With no doubt, the flags optimizes the code. But we don't have enough data to distinguish between -O2, -O2 -march=bdver2 and -Os, so let us change the code to deasable some optimizations closer to real life case and perform it only on these three last cases because the first two cases might take a very long time.
 % cat main2.cpp
#include <iostream> // std::cout
#include <ostream> // std::endl

bool f(const unsigned char & n1, const unsigned char & n2)
{
 return n1 ^ n2;
}

int main()
{
 bool * tmp = new bool [256];
 for(unsigned short int i = 0; i < 256; ++i)
 {
  tmp[i] = false;
 }
 for(unsigned char n1 = 0; n1 < 255; ++n1)
 {
  for(unsigned char n2 = 0; n2 < 255; ++n2)
  {
   {
    for(unsigned short int i = 0; i < 65535; ++i)
    {
     tmp[n1] += f(n1, n2);
    }
   }
  }
 }
 unsigned char n1 = 255;
 for(unsigned char n2 = 0; n2 < 255; ++n2)
 {
  {
   for(unsigned short int i = 0; i < 65535; ++i)
   {
    tmp[n1] += f(n1, n2);
   }
  }
 }
 std::cout<  return 0;
}
Here the new version of the script to test only the relevent flags
% cat script2.sh
#!/bin/bash

printf "g++ -O2 main2.cpp -o o2; time ./o2"
g++ -O2 main2.cpp -o o2; time ./o2
printf "\n"
printf "g++ -O2 -march=bdver2 main2.cpp -o march; time ./march"
g++ -O2 -march=bdver2 main2.cpp -o march; time ./march
printf "\n"
printf "g++ -Os main2.cpp -o os; time ./os"
g++ -Os main2.cpp -o os; time ./os
Now, let us execute this script
% ./script2.sh g++ -O2 main2.cpp -o o2; time ./o2 0x13cfc20 real 0m3.803s user 0m3.803s sys 0m0.001s g++ -O2 -march=bdver2 main2.cpp -o march; time ./march 0x16d0c20 real 0m3.843s user 0m3.841s sys 0m0.000s g++ -Os main2.cpp -o os; time ./os 0x1cc1c20 real 0m4.962s user 0m4.953s sys 0m0.008s
Running several times gives similar results. -Os made a code a little bit slower than the ones produced by -O2 and -O2 -march=bdver2. Notice that forcing inlining of f improves the computation time for -Os and give similar results than for the other flags.

About 50% of the time-O2 is faster -O2 -march=bdver2, but the relative difference is less than 1%. There is no clear gain from -march=bdver2 in this case.

.section .text.unlikely,"ax",@progbits .LCOLDB0: .text .LHOTB0: .p2align 4,,15 .globl _Z1fhh .type _Z1fhh, @function _Z1fhh: .LFB0: .cfi_startproc cmpb %sil, %dil setne %al ret .cfi_endproc .LFE0: .size _Z1fhh, .-_Z1fhh .section .text.unlikely .LCOLDE0: .text .LHOTE0: .ident "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.5) 5.4.0 20160609" .section .note.GNU-stack,"",@progbits
Here the difference in the f function
% diff o2.s march.s
6c6,7
< .p2align 4,,15
---
> .p2align 4,,10
> .p2align 3
To conclude, we first showed that ^ and != are strictly equivalent for unsigned char, then that the maximum of optimization for this operator is achived with -O2 and finally that -march=bdver2 does not provide noticeable improvement. In a real life code, other optimizations can make -Os performing better than -O2 and other flags, such as -O3, might affect the executable.

View server certificate in Thunderbird, a 11yo request.

Friday Oct 20, 2017 18:43, last edition on Friday Oct 20, 2017 19:23

While I was configuring the certificate for my mail server, I wanted to check if everything works fine in Thunderbird. It turns out that one cannot check the server certificates in Thunderbird. With a simple web search, I found a post from August 2006, i.e. more than 11 years ago, with the same question. The answer was that it was not possible and no extension doing it exists. I asked to see if things changed since them and the answer is no. This process is very simple in Firefox.

Check certificate #1
Check certificate #2
Check certificate #3
Check certificate #4

In my opinion, this should be a critical feature to have.

SVG with GZIP Compression in Apache HTTP Server

Friday Oct 20, 2017 16:45, last edition on Friday Oct 20, 2017 17:42

To save bandwidth with Apache HTTP Server, you can compress SVG files. On Ubuntu 16.04.3, Apache HTTP Server comes with version 2.4.27 which enable GZIP Compression by default.

# apache2 -v
Server version: Apache/2.4.27 (Ubuntu)
Server built: 2017-09-28T00:00:00
If not enable, you can do it with mod_deflate
# a2enmod deflate
For SVG Compression, edit the file /etc/apache2/mods-available/deflate.conf and add AddOutputFilterByType DEFLATE image/svg+xml between the IfModule. It should look like this
# cat /etc/apache2/mods-available/deflate.conf
<IfModule mod_deflate.c>
 <IfModule mod_filter.c>
  AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css
  AddOutputFilterByType DEFLATE application/x-javascript application/javascript application/ecmascript
  AddOutputFilterByType DEFLATE application/rss+xml
  AddOutputFilterByType DEFLATE application/xml
  AddOutputFilterByType DEFLATE image/svg+xml
 </IfModule>
</IfModule>
Restart Apache HTTP Server
# systemctl restart apache2
Now, let us check if it is working with curl and its -I argument to query only the headers.
% curl -I https://clementfevrier.fr/images/CC-BY-SA_icon.svg
HTTP/1.1 200 OK
Date: Fri, 20 Oct 2017 14:23:11 GMT
Server: Apache/2.4.27 (Ubuntu)
Upgrade: h2
Connection: Upgrade
Last-Modified: Mon, 07 Oct 2013 03:09:42 GMT
ETag: "1bf8-4e81dfbbce980"
Accept-Ranges: bytes
Content-Length: 7160
Vary: Accept-Encoding
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
X-Frame-Options: sameorigin
X-Download-Options: noopen
X-Permitted-Cross-Domain-Policies: none
Referrer-Policy: strict-origin-when-cross-origin
Content-Type: image/svg+xml
and now with -H 'Accept-Encoding: gzip,deflate' to let know Apache HTTP Server that it can serve the file using compression
% curl -I -H 'Accept-Encoding: gzip,deflate' https://clementfevrier.fr/images/CC-BY-SA_icon.svg
HTTP/1.1 200 OK
Date: Fri, 20 Oct 2017 14:25:19 GMT Server: Apache/2.4.27 (Ubuntu) Upgrade: h2 Connection: Upgrade Last-Modified: Mon, 07 Oct 2013 03:09:42 GMT
ETag: "1bf8-4e81dfbbce980-gzip"
Accept-Ranges: bytes
Vary: Accept-Encoding
Content-Encoding: gzip
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
X-Frame-Options: sameorigin
X-Download-Options: noopen
X-Permitted-Cross-Domain-Policies: none
Referrer-Policy: strict-origin-when-cross-origin
Content-Length: 3077
Content-Type: image/svg+xml
In this case, the file is more than 2 times smaller (7160÷3077 ~ 2.326941826). Enjoy!

Identity

Friday Oct 20, 2017 13:40, last edition on Thursday Oct 26, 2017 13:56

Someone's identity evolves with time and can be multiple. For example, someone's identity for someone met in work place will be usually the name given by their parents. Sometimes, it can be the husband's family name. Whereas your friend or family can call you with a nickname.
On the web, this identity is a pseudo or an avatar. It is an email address. Each time a new account is created on a server, a new identity for this server is created. It means that a person can have multiple identities in one location, that is usually not the case in the real world.

Building identity

There are two paths to build virtual identities. If someone decides to take different pseudo for each created account, then this person gain a new identity each time. It is a simple way to protect your privacy. The second choice is to keep the same pseudo, avatar, email address, and so on, to build a strong and consistent identity, and not necessarily the same as in the real world.

My identity

I have many virtual identities. Some correspond to the real world one, this website is a perfect example as it includes my name a picture of myself. Others are not related at all and can be difficult to link to me. Let me give you some of my virtual identities.

As Clément Février or related

Mastodon
Twitter
Facebook
LinkedIn
Physical Review Journals
arXiv.org
Launchpad, although it was clement.analogue for more than 9 years.

As Analogue or related

Mozilla Add-ons
Mozilla Support
GitHub, but my real name is displayed.
FramaGit, but my real name is displayed.
GitLab, but a nickname is displayed.
Documentation Ubuntu-fr
Forum Ubuntu-fr

Others

Clèm on StackExchange
clement on Forum Analogue
Dr Clèm on this blog

and I can continue like that for a while.

The trend in my case is to use my real name when I need to be a public figure, which as needed when I run as deputy deputy for the parliamentary elections, or for work, the pseudo Analogue or related when it is linked to software, and my first name and nickname for more personal accounts.

Edit on October 25, 2917: Add new identities, update identiy from FramaGit and GitHub.
Edit on October 26, 2917: Add new identities (Ubuntu-fr)

Welcome

Friday Oct 20, 2017 10:55

Hello,
Welcome on my blog. I decided to create this website to have a place to express myself. I write it from scratch to learn web-development. You can find a quick presentation on the right panel or bellow, depending on the size of your screen and your window, and my Mastodon feed bellow. On the footer, you can find some of my other websites, my profile on few social medias, the contact information, and legal notice. The only tab, so far, on the navigation bar is my Ph.D. thesis. I use PHP to develop this website. The latter is served exclusively through HTTPS, with strong encryption if your device support it and medium encryption for older devices, like Android smartphone as they don't received update, even for critical security issues. The web-server is Apache HTTP Server, using protocol HTTP/2. The template is a reproduction of La France Insoumise's website but using W3.CSS for styling instead of Bootstrap as it is smaller, faster, and easier to use.


Dr Clément Février

Bonjour, Je suis Clément Février, docteur en physique théorique de l’université de Grenoble Alpes, ingénieur Recherche et Développement dans le domaine de l’imagerie médicale et de la chirurgie mini-invasive chez Surgivisio et soutien du mouvement La France Insoumise.


Dites les velotaffeur, vous avez entendu parler d'un casque qui a un feu avant, un feu arrière et des clignotants sur les cotés / avant arrière ? (Enfin un simple bandeau led de chaque coté se gère hein)
Genre un truc pour que les voitures voient qu'on tourne à droite ou gauche sans qu'on ai besoin de tendre le bras ?

Parce que bon, j'ai testé ce soir, passer sur les marquages au sol + les rails du tramway avec un bras levé sous la pluie, niveau stabilité on repassera ^^'

J'arrive pas à trouver :/ et les solutions existantes de clignotants sont seulement pour l'arrière

Si le coeur vous en dit vous pouvez partager ;)

#velotaff #boostappréciés :)

The only thing that really matter is, at the end of the day, to choose the correct method automatically without conditional statement at runtime. I really wonder is a workaround is possible.
I already tried to add "std::tuple< d1*, d2 > b_tuple" to class b, using some forward declaration, but, of course, std::get< i >(b_tuple) cannot compile since it will be known at runtime only.

But I allow complete refactoring code, even the b and d1 & d2. Templates, new classes and sub classes and even are fine (I already put 100-lines define to add iterator to enum and another one to allow enum inheritance, and my coworkers begin to hate me ^^)
For example, method "create" can become a class, or class b can be construct using a macro to make somehow the base class aware of derived ones
BASE(b, ...) std::tuple< __VA_ARGS__ > g_ ## b; class b

How to choose a function at run time using overloaded resolution in ?
I feel it's an old known issue without (obvious) answer, but many things changed since c++98
stackoverflow.com/questions/64

I add the new following constrain to my original question, it can be up to C++14, no more (although if a solution in c++17 or C++20 exist, I'm interested) because of compiler limitation (appears to be based on gcc 5.14 from what I understood).