GaMa a écrit 447 commentaires

  • [^] # Re: Ont-ils bien modélisé les milliers de morts dus à l'Hydroxychloroquine ?

    Posté par  (site web personnel) . En réponse au journal jeu libre Covid-25 !. Évalué à 7 (+6/-1).

    Ha ben non. Le point commun c'est la mort. Je connais pas mal de gens en vie encore vivant. Alors que je connais aucun mort encore vivant !

    Matthieu Gautier|irc:starmad

  • # Flatpak

    Posté par  (site web personnel) . En réponse au journal Sandboxer des applications avec bubblewrap (2/3) : applications de bureau. Évalué à 3 (+1/-0).

    Merci pour ce journal. Très intéressant comme le précédent. J'attends le 3ème avec impatience.

    Je n'aime pas flatpak en tant que solution de distribution, mais il faut rendre hommage aux personnes derrière le projet : ils font du bon travail)

    Par curiosité, qu'est-ce que tu reproches à Flatpak ? Et du coup, quels seraient tes critères pour une "bonne" solution de distribution ?

    Matthieu Gautier|irc:starmad

  • [^] # Re: Pincettes

    Posté par  (site web personnel) . En réponse au lien Alzheimer : les anti-vaccins en PLS ? :-). Évalué à 2.

    C'est les suggestions sur la cause qu'il reste à confirmer.

    La corrélation elle semble être confirmée.

    Matthieu Gautier|irc:starmad

  • [^] # Re: Comportement toxique ou personne toxique ?

    Posté par  (site web personnel) . En réponse au lien Travail - Patrons toxiques : il faut en finir avec la “culture des connards”. Évalué à 10.

    Le capitalisme tel qu'appliqué dans les démocraties occidentales est imparfait, mais c'est le meilleur système qu'on ait trouvé jusqu'ici.

    Le meilleur selon quels critères ?
    Quels seraient les buts/bénéfices d'un système "parfait" ?

    (Sans avoir répondu à ces questions, et probablement d'autres, difficile de savoir si c'est le meilleur)

    Matthieu Gautier|irc:starmad

  • # prestation ?

    Posté par  (site web personnel) . En réponse au message Problème sur mon site de posters. Évalué à 3.

    Ceci est un forum d'entraide sur linux.

    Je ne pense pas que tu trouveras grand monde pour t'aider gratuitement à corriger la mise en page de ton site commercial.

    Matthieu Gautier|irc:starmad

  • [^] # Re: Effet loupé

    Posté par  (site web personnel) . En réponse au journal Du format et de la taille des images. Évalué à 5.

    Chez moi aussi, je vois bien le gris sur l'image du journal.

    Par contre, dans l'article d'origine (https://www.patreon.com/posts/color-grid-28734535), ça marche assez bien (je suppose parce que l'image est plus petite).

    Et la vidéo est assez bluffante.

    Matthieu Gautier|irc:starmad

  • [^] # Re: Sous le coup de la Loi ?

    Posté par  (site web personnel) . En réponse au lien Google demande aux applications d'utiliser un niveau d'API Android de moins de deux ans. Évalué à 5.

    Oui, de plus qu'à la fin de l'article de google :

    Current users of older apps who have previously installed the app from Google Play will continue to be able to discover, re-install, and use the app on any device running any Android OS version that the app supports.

    Donc en gros, c'est l'installation de nouvelle appli qui nécessite une API récente.
    Les utilisateurs existant ne sont pas impactés.

    C'est la découverte d'appli qui est visé. Les utilisateurs peuvent toujours utiliser l'appli, même à travers le store, sur un ancien téléphone.
    En l’occurrence, j'arrive à installer kiwix sur un pixel 2 (2017) avec Android Nougat 7.1 API 25 (fin 2016).
    L'API 24 ne passe pas parce que c'est une limite chez nous, pas chez Android.

    Matthieu Gautier|irc:starmad

  • [^] # Re: fork

    Posté par  (site web personnel) . En réponse au lien Pétition de Mozilla pour empêcher la France d’obliger les navigateurs tels que Firefox à censurer . Évalué à 10.

    Ce raisonnement n'a pas vraiment de cohérence.

    • Il y a des gens d'un "milieux bien pensant de la geekoshpère" qui font un pétition pour ne pas avoir d'obligation à censurer.
    • Tu refuses de signer cette pétition
    • Tu critiques les gens des "milieux bien pensant de la geekoshpère" qui serait d'accord qu'on censure les premiers sites visés parce qu'ils sont contre ce qui y est dit.

    Moi je vois que même en étant contre ce qui est dit sur certains sites, on est encore plus contre l'idée de les censurer.

    En attendant, toi, tu as envies que la loi passe…

    Matthieu Gautier|irc:starmad

  • [^] # Re: Flatseal

    Posté par  (site web personnel) . En réponse au journal "dérives sécuritaires" : inconvénients des flatpacks, snap ou environnements sandbox.. Évalué à 6.

    Non. Comme à chaque fois, différents utilisateurs entrainent différents cas d'usage.

    Je sais pas trop pourquoi je continue ici alors que tu sembles tout amalgamer mais bon:
    - Les utilisateurs de Corée du Nord, ils téléchargent rien (et il vaut mieux pour leur vie), ils prennent je sais pas quoi (appimage je suppose)
    - Les opérateurs, ils utilisent probablement kiwix-serve qui pop un server web et pas une appli graphique
    - Les gens qui remontent des bugs parce qu'ils arrivent pas à lire l'archive de 40Go qu'ils viennent de dl, ils prennent effectivement la nightly avec le bug corrigé.

    Mon point dans tout ça, c'est de dire que c'est pas aussi facile que Yakafairedespaquets.
    Les paquets des distrib fonctionnent bien pour pas mal de monde, et ça tombe bien, il y en a. Pour les autres, ils y a d'autres solutions.

    Matthieu Gautier|irc:starmad

  • [^] # Re: Flatseal

    Posté par  (site web personnel) . En réponse au journal "dérives sécuritaires" : inconvénients des flatpacks, snap ou environnements sandbox.. Évalué à 3.

    Et ceux qui veulent absolument la version native prennent le package de leur distrib.

    Les packages n'existent pas pour les version nightly.
    On publie les nigthly de kiwix-desktop tout les jours. En flatpak et appimage.

    Et pour revenir un peu sur le sujet d'origine:
    - Le appimage fait 146Mo
    - Le flatpak fait 52Mo (et on se base sur le même runtime, donc rien de plus à dl)

    Matthieu Gautier|irc:starmad

  • [^] # Re: Flatseal

    Posté par  (site web personnel) . En réponse au journal "dérives sécuritaires" : inconvénients des flatpacks, snap ou environnements sandbox.. Évalué à 10.

    Ben justement, les gens normaux utilisent les paquets de leur distrib il me semble, non?

    Ça dépends.
    Le but du projet Kiwix, c'est fournir du contenu web hors ligne. En gros tu télécharges des gros snapshot des site web et tu les lis localement sans connexion.

    Du coup nos utilisateurs (c'est très difficile de savoir en vrai), c'est des gens pas en occidents, qui parlent souvent pas anglais, sans connexions de qualité (quand ils en ont).
    Ils sont sous linux pas obligatoirement pour le libre mais parce que c'est pas cher.
    Où ils utilisent l'ordi qui a été utilisé par l'ONG ou le seul mec de la région qui s'y connait en informatique.
    Ils se passent les binaires sur clés usb.

    Tu retrouves du kiwix à Cuba, au fin fond du Népal, dans les prisons française, dans les camps de réfugier, sur les terrains de catastrophes naturelles ou non, en Russie (pas mal depuis le début de la guerre en Ukraine), en Chine, ou globalement dans tout les pays où internet est contrôlé/censuré.

    Dans les retours d'usage on a:
    - Les gens dans des villages d'Afrique qui font une journée de route pour aller à la grande ville pour mettre à jours les zims et les binaires et qui rentre au village pour tout mettre dans un réseau local.
    - Quelqu'un qui récupère des clés usb en Corée du sud, mets du kiwix et du wikipedia dessus et ensuite vas "perdre" (sans se faire prendre) ces mêmes clés en Corée du nord en espérant que des gens les récupèrent et regarde ce qu'il y a dessus
    - Ou encore des opérateurs en Afrique qui mette du kiwix en interne pour fournir "un accès à wikipedia en illimité" à leurs clients, parce qu'un seul câble qui sort du pays

    C'est gens là, tu peux pas leur dire d'utiliser le paquets de leur distrib, de passer par wine ou de compiler eux même. Ce sont pas souvent des informaticiens et ils se débrouillent souvent avec ce qu'ils ont. Il faut que ça "juste marche" (et c'est hélas pas tout le temps le cas)
    Avoir des paquets pour les grandes distrib c'est nécessaire (quoique) mais pas du tout suffisant.

    On a tendance à facilement oublier qu'on est dans un petit entre-soi finalement. Mais la moitié des gens dans le monde n'ont pas accès à internet de manière régulière.

    Matthieu Gautier|irc:starmad

  • [^] # Re: Flatseal

    Posté par  (site web personnel) . En réponse au journal "dérives sécuritaires" : inconvénients des flatpacks, snap ou environnements sandbox.. Évalué à 6.

    Elle a pas beaucoup changé non. Mais c'est surtout le reste qui change.
    Les problèmes qu'on a, c'est principalement avec des distrib récentes. C'est elles qui ont mise à jours leur lib (openssl, drivers, …).
    Qt a évolué aussi, on pourrait builder avec la dernière version de Qt (ce qui corrigerait probablement les problèmes avec les distrib récentes). Mais c'est pas dispo en pré-compilé sur les anciennes distrib. Et on veut compiler sur une ancienne distrib pour avoir une vieille version des glibc et stdlibc++.
    Alors on pourrait effectivement recompiler Qt dans notre CI sur en vieille machine. Mais ça passerait pas dans notre CI (on fait quand même des builds toutes les nuits et on publie les nigthly)
    On pourrait avoir notre propre runner au lieu d'utiliser celui fournit par github mais il faut des €€ pour ça (et rajouter de la maintenance d'une nouvelle machine)
    Ou alors je fais un build en local chez moi et on utilise ça dans notre CI… mais quid de la sécu et de la reproductibilité ?
    Ou alors je change de métier et je deviens packageur (et plus développeur) et je m'amuse a maintenir une version récente de Qt sur des vieille distrib.
    Ou alors …

    Et puis il y a pas que Qt. gtest impose C++14 maintenant, mais on est encore en C++11. Il faut qu'on change on est d'accord. Mais en attendant on compile avec une vieille version de gtest. Sauf que les packageurs (merci à eux pour leur travail), ils utilisent le gtest de la distrib et bim, ça compile plus sur les machines récentes.
    C'est pas compliqué à changer, c'est une ligne de config (et les packageurs patche cette ligne). Mais il faut vérifier que tous les compilo qu'on utilise font correctement du C++14 avant.

    Au milieu de tout ça, il faut faire du code review, répondre aux issues sur github, faire la maintenance de tous les jours et rajouter des fonctionnalités et améliorer les perfs.
    À un moment il faut faire des choix.

    Le problème c'est qu'on est dans un monde qui bouge et on doit bouger avec lui. (Même si je préfèrerait faire les trucs dans mon coin sans jamais mettre à jour les dépendances).

    J'ai l'impression que des fois vouloir avoir un binaire qui satisfait à toutes les distribs est plus compliqué que profiter des infras comme le opensuse build service qui te permet de faire des paquets individuels pour toutes les grandes distribs.

    J'ai jamais utilisé. Mais j'ai peur que ça soit là aussi pas la panacée. On va se retrouver avec plusieurs paquets, compilés avec différentes version des dépendances et différentes options. Et on sait qu'on a des bugs dans nos dépendances qui sont fixé avec des versions récentes. Donc on sait que nos logiciels vont se comporter différemment d'un paquet à l'autre. Il va falloir suivre tout ça. On va pas pouvoir tout tester, donc on va fournir des paquets pour une distrib spécifique sans vraiment savoir si ça fonctionne. Il va falloir comprendre ce qu'il se passe au prochain rapport de bug… et au final c'est la même chose que maintenant mais avec une couche de plus.

    Mon métier c'est développeur. Pas packageur. C'est pas à moi de faire le packaging. Mais on fait quand même un binaire pour que les gens normaux (pas les gens qui participent à cette discussion ici) puisse utiliser kiwix sans avoir à tout recompiler.

    Et du coup, on a des gens qui viennent nous dire qu'on est fainéant parce que le binaire est trop gros alors qu'on pourrait ne rien faire. D'ailleurs on leur impose rien, ils peuvent toujours recompiler, on fournit même kiwix-build pour ça.

    Matthieu Gautier|irc:starmad

  • [^] # Re: Flatseal

    Posté par  (site web personnel) . En réponse au journal "dérives sécuritaires" : inconvénients des flatpacks, snap ou environnements sandbox.. Évalué à 5.

    kiwix c'est un dev payé 2 jours par semaine (moi) et qq bénévoles (principalement des étudiants qui disparaissent au bout de qq mois).

    Firefox c'est … beaucoup plus.

    Matthieu Gautier|irc:starmad

  • [^] # Re: Flatseal

    Posté par  (site web personnel) . En réponse au journal "dérives sécuritaires" : inconvénients des flatpacks, snap ou environnements sandbox.. Évalué à 4.

    Que flatpak soit plus simple à générer, c'est possible, ceci étant, je parlais plus haut du fait que pour l'utilisateur final les AppImages sont pratiques, cela fonctionne comme une appli native, et même si le binaire est un peu plus gros qu'un .deb c'est quand même moins pire qu'un flatpak : l'exemple donné sur https://ludocode.com/blog/flatpak-is-not-the-future est édifiant : pour un programme de calculatrice, un appImage fait 150 Mo tandis que le même fera 900 Mo avec flatpak. D'un autre côté MuseScore en AppImage fait aussi 160 Mo donc ça reste acceptable.

    Il est vrai.
    Mais le appImage n'embarque pas tout. Il a besoin d'un ensemble de libs déjà présentent dans ton système (sinon on aurait pas les problèmes de compat que j'ai cité).
    Quelle est la taille de ces libs ?
    Tu me répondras qu'on s'en fout parce que c'est déjà là et que c'est partagé avec les autres programmes. Mais c'est exactement la réponse qui est donnée dans cet article: Le flatpak est gros parce qu'il vient avec un sdk, mais ce sdk sera partagé par d'autres appli aussi.

    Et c'est un vrai problème quand tu packages un logiciel. Il faut décider d'une limite à partir de laquelle tu assumes que c'est un "standard" de ton système (et si il est versionné ou non).
    Si la limite est trop basse, tu assumes trop et ton logiciel ne fonctionne que sur un petit nombre de distrib
    Si la limite est trop haute, tu embarques beaucoup de choses qui vont être des duplications de ce qu'il y a dans le système (ou entre plusieurs packages).

    AppImage te laisse choisir (pour le pire et le meilleur).

    Flatpak prend un chemin intermédiaire:
    - Prendre une limite haute et avoir des sdk qui "refont" un système.
    - Avoir des applis qui se base sur ces sdk (et donc avoir une limite "basse" du point de vue appli)
    - Parier sur la déduplication des données pour ne pas exploser en taille avec la multiplication des sdk.

    Sur ce dernier point, je trouve aussi que c'est un peu limite. Flatpak prend effectivement beaucoup de place. Mais il reste quand même que ça "juste marche" contrairement aux autres solutions plus légères.

    Matthieu Gautier|irc:starmad

  • [^] # Re: Flatseal

    Posté par  (site web personnel) . En réponse au journal "dérives sécuritaires" : inconvénients des flatpacks, snap ou environnements sandbox.. Évalué à 2.

    Appimage sert juste à générer un (gros) exécutable, il ne prends pas en compte l'intégration avec la distrib.

    C'est justement ce qu'on lui reproche*. Ça sert à faire un gros binaire et au dev de faire le boulot pour s'assurer que ce binaire fonctionne correctement.

    Mais c'est un peu facile de venir poser la question de est-ce Flatpak réponds vraiment à des besoins impossible à gérer avec l'existant qui marche (appimage + sandbox) ? et ensuite dire que "c'est juste un truc à générer des binaires, il faut pas comparer" quand on te montre que appimage + sandbox, ça marche pas si bien que ça.

    [*] Enfin, on lui reproche rien. C'est juste que c'est une limitation et que les outils comme flatpak ou snap prennent une autre approche pour essayer de combler cette limitation. (Et on est d'accord que cette approche a aussi des défauts)

    Matthieu Gautier|irc:starmad

  • [^] # Re: Flatseal

    Posté par  (site web personnel) . En réponse au journal "dérives sécuritaires" : inconvénients des flatpacks, snap ou environnements sandbox.. Évalué à 10.

    Vous me faites rire avec "Flatpak c'est de la me**e, appimage ça marche très bien".

    Chez kiwix, on fait les deux.

    Pour flatpak, on a un fichier de config(https://github.com/flathub/org.kiwix.desktop/blob/master/org.kiwix.desktop.json) et c'est terminé (et encore, on génère ce fichier à partir de notre outils de build, donc c'est mis à jours tout seul)

    Pour AppImage, ça se fait effectivement "facilement". Il faut tout (mais pas trop) copier dans un dossier et lancer un "linuxqtdeploy" (mais deux fois, parce qu'il faut patcher le RPATH de QTWebEngineProcess entre les deux). Le script est là: https://github.com/kiwix/kiwix-build/blob/main/scripts/create_kiwix-desktop_appImage.sh

    Mais une fois que tu as ton appimage, c'est pas fini :

    • https://github.com/kiwix/kiwix-desktop/issues/871 : la connexion ssl ne s’établit pas sur certaine distrib à cause de différence de version de openssl. Pas possible d'embarquer la lib openssl parce que les chemins vers les certificats sont hard codé dans le binaire et ils changent d'une distrib à l'autre.

    • https://github.com/probonopd/linuxdeployqt/issues/554 : Pas d'affichage de la webview à cause de … on sait pas. Il y a un workaround qui désactive le rendu gpu, mais c'est un workaround.

    • Ou encore celui là : https://github.com/kiwix/kiwix-desktop/issues/393, si tu embarques la libstdc++ dans ton appimage, mesa n'arrive pas à charger les drivers opengl. Si tu n'embarques pas la libstdc++, il faut que tu utilises une vieille distrib avec une vieille version de qt (ou recompiler tout qt), mais qui potentiellement n'a pas les plugins pour les dernières variantes des drivers gl….

    Et tu peux aller voir les issues, elles sont liées à pas mal d'autres d'autres projets qui ont les mêmes problèmes encore et encore. Alors oui, pour trois truc simple, appimage ça marche bien. Mais dès que c'est un peu complexe, que tu veux des dépendances à jours et que ça tourne sur toutes les distribs (y compris les vieilles), appimage c'est compliqué. Et chaque projet dois refaire le processus de trouver ce qu'il faut faire.

    Alors c'est peut-être pas appimage le problème, c'est peut-être le packaging de qt dans appimage, ou l’outil linuxdeployqt ou encore un autre truc. Mais en attendant, ça se termine souvent en : "Utilisez flatpak, ou les paquets de votre distrib, si ils existent".

    PS, je veux bien que vous me fixiez les deux premières issues.

    Matthieu Gautier|irc:starmad

  • [^] # Re: Intersection de sphères et changement de repère.

    Posté par  (site web personnel) . En réponse au message hauteur tétraèdre irrégulier et jeu spatial. Évalué à 2.

    Le changement de repère n'est pas là parce que tu connais pas les coordonnées, il est là pour simplifier les calculs.
    Si tu veux t'en passer tu vas avoir des équations de ce style:

    • (Dx-Ax)² + (Dy-Ay)² + (Dz-Az)² = DA²
    • (Dx-Bx)² + (Dy-By)² + (Dz-Bz)² = DB²
    • (Dx-Cx)² + (Dy-Cy)² + (Dz-Cz)² = DC²

    Et là, à résoudre c'est pas facile du tout.

    (Après tu peux faire les opérations changement de répère, résolution, changement de repère inverse sur le papier et trouver les formules finales, que tu appliques après dans ton programme)

    Matthieu Gautier|irc:starmad

  • # Intersection de sphères et changement de repère.

    Posté par  (site web personnel) . En réponse au message hauteur tétraèdre irrégulier et jeu spatial. Évalué à 6.

    Intersection de 3 sphères.

    On a donc 3 étoiles A, B, C.

    Choisissons un repère que nous arrange bien tel que :
    A: (0, 0, 0)
    B: (1, 0, 0)
    C: (K, L, 0)

    Nos trois étoiles sont dans le même plan X/Y et B est alignée sur X

    Soit D: (x, y, z)
    Si on connais AD, BD, CD (Les distances entre A et D, B et D, …), D est a l'intersection de 3 sphères de centre A, B, C et de rayon AD, BD et CD. Donc:

    • x² + y² + z² = AD²
    • (x-1)² + y² + z² = BD²
    • (x-K)² + (y-L)² + z² = CD²

    On trouve facilement que x² - (x-1)² = AD²-BD² => X = (AD²-BD² + 1)/2

    On peut "simplifier" les équations en :
    - y² + z² = AD² + x² = M (par que ça simplifie les écritures)
    - (y-L)² + z² = CD² - (x-K)² = N

    Donc que y² - (y-L)² = M - N => y = (M - N + L²)/2L

    Et donc que z² = AD² - x² - y².
    Donc deux solutions pour z, ce qui est cohérent avec ce qu'on attendait (D est au dessus ou en dessous du plan)

    Changement de repère.

    "C'est bien gentil les intersections de trois sphères mais mes 3 étoiles connues, elles ont pas ces coordonnées" tu vas me dire.
    Et je te répondrais: "On s'en fout, on applique une matrice de changement de repère pour être dans le repère qui nous intéresse (facilite la vie), on résout notre problème, et on applique la matrice inverse pour avoir notre solution dans notre repère d'origine."

    Du coup la question, c'est "Mais qu'elle est cette matrice de changement de repère ?".

    On va devoir la calculer (mais je vais pas le faire ici, j'ai pas vraiment le temps je t'avoue :)) mais en gros:
    - C'est une matrice 4x4
    - C'est la composition des transformations élémentaires suivante:
    . Translation de -(Ax, Ay, Az) pour se "placer A en zéro"
    . Rotation de l'angle ABX, avec pour axe la normale au plan ABX => ça va pivoter notre repère pour placer l'étoile B sur l'axe X
    . Rotation de l'angle ACY, avec pour axe la normale au plan ACY (=X) => ça va pivoter notre repère pour placer l'étoile C sur le plan XY
    . Un changement d'échelle de 1/AB pour placer B en coordonnée 1 sur X

    Je te conseille fortement d'utiliser des lib de transformations matricielles dans ton langage favori, tu n'as probablement pas envie de réimplémenter tout ça.

    Matthieu Gautier|irc:starmad

  • [^] # Re: lmgtfy

    Posté par  (site web personnel) . En réponse au journal Enregistrement de la plaque d'immatriculation aux péages. Évalué à 2.

    Les deux mon bon monsieur.

    Si ce que tu donnes comme info au péage (comment ? Le ticket je suppose) au sujet de où tu es rentré correspond à ce qu'ils ont, tout le monde est d'accord, on supprime.
    Du coup, tu n'as probablement pas de recours possible (ou alors sans s'appuyer sur les données techniques/perso) si tu n'es pas d'accord.

    Pour la classe du véhicule, les infos sont gardés plus longtemps. Ce qui doit te permettre de râler 2 semaines après parce que tu t'es rendu compte qu'il t'avais filé le tarif camion alors que t'es en moto.

    Pourquoi une différence de traitement ? Je sais pas. Mais au pif:
    - Tu ne donnes pas l'info de ta classe de véhicule, c'est eux qui la détecte. Donc plus de contestation possible ?
    - Obligations légales différentes ?
    - Contraintes techniques différentes ? (Un vidéo c'est lourd: 28 jours, les autres données c'est léger : 13 mois)

    D'ailleurs, quid des durées de conservation quand il n'y a pas cohérence entre les données présentées par le client et les données systèmes ?

    Matthieu Gautier|irc:starmad

  • [^] # Re: pourquoi ?

    Posté par  (site web personnel) . En réponse au journal C'était en 2020. Évalué à 10.

    C'est pas seulement la question de savoir si les morts sont effectivement morts, ou du nombre de personnes dans ta cohorte. C'est aussi de comment tu fais ton étude.

    Si tu veux prouver que le traitement[*] A est mieux que le traitement B, tu veux prendre des gens qui ont, en "moyenne", tout pareil sauf le traitement A vs B et comparer les résultats. Si il y a un traitement C qui traine au milieu, tu dois t'assurer que les deux groupes l'ont reçu dans les mêmes proportions (premier point où ton étude peut merder).

    [*] Et je parle de traitement ici, pas de médicament. Un médicament peut être un traitement, ne rien faire aussi. Ou envoyer les gens au bord de la mer et les sortir de la grisaille de Paris aussi

    Deuxièmement, tu dois énoncer une hypothèse réfutable. Genre "A est mieux que B selon ces critères". Tu peux pas chercher à prouver que "A a moins d'effets secondaires que B". Parce que c'est pas prouvable (tu ne peux pas prouver l'absence d'effet) (Deuxième point où ça peut merder)

    Ensuite tu dois définir dans quelles conditions tu comptes ou exclus les gens de la cohorte.
    Comme tu le dis, il faut pas filer un traitement A à des gens en phase terminale si c'est pas fait pour ça, on sait que ça va pas marcher. Mais tu dois le faire avant l'étude !
    C'est subtile, mais tu ne peux pas faire une étude et regarder ensuite à partir de quand ça marche et dire après coup, mes critères c'est ça. (Troisième point où ça peut merder).

    Si tu penses que ton traitement peut être efficace dans cette situation (définie à l'avance), tu l'administres. Ou sinon tu le fais pas rentrer (et du coup tu peux ne pas le compter). Si tu le fais rentrer, tu dois le compter quand il sort, peu importe comment. Si ton malade passe en phase terminale, tu le comptes dans tes résultats, c'est que ton traitement a pas marché. Tu peux pas le sortir discrètement parce qu'il ne correspond plus aux critères (Quatrième point où ça peut merder)

    De plus, indépendamment du résultat sur ton étude (les stat), si l'état de santé de ton malade se dégrade, tu te dois de le sortir de ton étude (médicalement parlant) et lui administrer un traitement un minimum connu par être efficace (pour des raisons éthique, pas scientifique). Sinon tu le tues pour essayer de prouver ton hypothèse. (Cinquième (gros) point où ça peut merder)

    Si tu te loupes sur un seul des quatre premiers points, ton étude est bancale, peut importe la taille de ta cohorte ou la véracité de tes chiffres brutes (nombre de morts/guéris). (Et je paris qu'il y a plein d'autres points ça peut merder)
    Si tu te loupes sur le cinquième point, c'est potentiellement devant la justice que tu te retrouves (et ce, même si toute ton étude est parfaite)

    Matthieu Gautier|irc:starmad

  • [^] # Re: sommes nous davantage que des synthétiseurs textuels ?

    Posté par  (site web personnel) . En réponse au journal Le vocable « intelligence artificielle » vs synthétiseur de texte ?. Évalué à 2.

    C'est complétement lunaire, la première résolution de ta discussion donne une estimation mais quand tu lui dit qu'ils doivent décélérer (et donc prendre plus de temps), il donne une réponse plus courte.

    Moi j'ai eu cette conversation : https://pastebin.com/wnCM43K8
    Il semble encore plus dans les choux. La compréhension du problème est bien moins bonne. Le comble il trouve que Roger a un temps de parcours plus long que XFgS5H et en déduit que XFgS5H doit partir avant ….

    Et pour savoir combien de temps d’écart, il refait un calcul complexe (et complétement faux) au lieu de faire une soustraction.

    Sa deuxième estimation me donne une durée de trajet de moins de 2 mois alors qu'avant il était en années…

    Je suis sur la version gratuite de chatGPT et j'ai droit qu'à 10 questions donc je peux pas aller plus loin (mais pas sûr d'avoir envie de toutes façons)

    Matthieu Gautier|irc:starmad

  • [^] # Re: sommes nous davantage que des synthétiseurs textuels ?

    Posté par  (site web personnel) . En réponse au journal Le vocable « intelligence artificielle » vs synthétiseur de texte ?. Évalué à 2.

    Il faudrait un problème plus original pour tester sa logique (spoiler : il n'en a sûrement pas).

    Défi relevé :

    Roger est un homme comme les autres, mais son métier est particulier, il est pilote de fusée.
    Il vit sur la troisième génération station spatial internationale (ISS3) qui orbite autour de la planète Vit3km (une planète de la voix lactée, colonisé par les humains à l'époque où se passe cette histoire). Vit3km à un diamètre de 10000km et orbite autour de son soleil en 200 rotations (appelées jours).

    La semaine dernière il a rencontré XFgS5H, un robot qui vit sur la planète ParHeure (diamètre de 12000km).
    Malgré que XFgS5H soit un robot, Roger en est totalement tombé amoureux (en même temps, il faut dire que les intelligences artificielles ont beaucoup progressé depuis la période de ChatGPT4).

    Ils décident de se rencontrer à nouveau, sur la planète LAmourFou (diamètre de 5000km), une planète qui rend follement amoureux toute personne (humaine ou non) à sa surface. Beaucoup de gens partent en we en amoureux là-bas.

    La distance Vit3km-ParHeure est de 5000 millions de kilomètres.
    La distance Vit3km-LAmourFou est de 4000 millions de kilomètres.
    La distance ParHeure-LAmourFou est de 4500 millions de kilomètres.
    La station ISS3 est à une altitude de 200km au dessus de la surface moyenne de Vit3km et orbite autour de Vit3km en 30h.

    La fusée de Roger est équipée d'un réacteur un peu ancien avec une poussée relativement faible. Elle a une accélération de 20km/h/h.
    La fusée de XFgS5H est plus récente et son accélération est de 40km/h/h.

    Lorsque Roger décollera, il le fera au bon moment pour avoir une vitesse initiale la plus avantageuse (en utilisant la vitesse de ISS3).
    XFgS5H lui, décollera directement de sa planète.
    Dans les deux cas, ils accéléreront constamment au début et, au bon moment, ils inverseront la poussé de leur réacteur pour arriver avec une vitesse nulle à la surface de LAmourFou.

    Ils veulent arriver en même temps à la surface de LAmourFou. En ignorant la gravité des planètes, qui doit partir en premier et combien de temps le deuxième doit attendre après le départ du premier avant de décoller à son tour ?

    (PS, je n'ai absolument pas essayer de résoudre cet exercice)
    (PS2, on peut changer l'énoncé pour avoir une vitesse constante au lieu d'une accélération si ChatGPT a du mal avec les intégrales, ça serait quand même un exercice intéressant)

    Matthieu Gautier|irc:starmad

  • [^] # Re: Et pourtant c'est simple

    Posté par  (site web personnel) . En réponse au journal Quizz Python : esp[èa]ce de nom. Évalué à 7. Dernière modification le 09 mars 2023 à 15:03.

    le bloc crée une variable x donc on retire x de la table

    Ha mais non, on supprime rien.

    C'est plutôt que la variable x dans le namespace de la class bar "masque" la variable x dans le namespace de foo.

    Le fonctionnement global est celui ci:

    Lors de la définition d'une fonction (ou d'une class ici), un "scope" (local) est créé.

    Lors de la résolution de nom (la recherche de l’objet qui correspond à x), on cherche d'abord dans ce scope local. Si on le trouve pas et si la définition de la fonction à lieu dans un scope (par exemple à l'intérieur de l’exécution de foo()), on cherche dans ce scope "parent". Si on le trouve toujours pas, on remonte à nouveau (si on peut). Enfin, on arrive au scope global (celui du module) et si on trouve toujours pas, on arrête avec une exception NameError.

    La subtilité, c'est qu'on attend pas de faire un x = 1 pour créer la variable x dans son scope. À la définition de la fonction, python "sait" qu'on va avoir besoin d'une variable x et donc il crée le slot (vide) dans le scope dès le début de l’exécution.

    Donc lors de la résolution de nom, il trouve x dans le scope local et donc arrête de chercher dans le scopes parents. Mais comme x n'est pas encore initialisé, bam !

    Donc c'est bien l'existence de la variable x dans le scope local qui masque x dans les scopes parent même si l'initialisation de x a lieu après la ligne qui plante.

    Ça donne des trucs rigolo :

    • Ça marche de manière récursive :
    a = 5 
    def foo():
        b = 10
        def bar():
           c = 15
           def baz():
               d = 20
               print(a + b + c + d)
           return baz
        return bar()
    
    print(foo()()) # Affiche 50
    • La résolution de nom à lieu à l’exécution du code, ce qui peut amener des surprises :
    def foo():
        for i in range(3):
            def bar():
                print(i)
            yield bar
    
    # Affiche 0, 1 et 2
    for f in foo():
        f()
    
    # Affiche 2, 2, 2
    functions = list(foo())
    for f in functions:
        # Lors de l'appel à `f`, la boucle dans foo a fini et donc i vaut tout le temps 2
        f()
    • Si on veut forcer la résolution des nom à la définition, il faut lire la valeur à la définition:
    def foo():
       for i in range(3):
           def bar(i=i):
               # i est dans le scope local (c'est un argument) et ça valeur par défaut
               # est la valeur de i (dans foo) *au moment de la définition de bar*
               print(i)
           yield bar
    
    # Affiche 0, 1 et 2
    functions = list(foo())
    for f in functions:
        f()
    • Le mot clé nonlocal permet de dire à python de ne pas créer de slot dans le scope local mais d'utiliser celui du scope parent (et seulement celui là). global fait la même chose mais dit d'utiliser le scope global :
    def foo():
        x = 5
        def bar():
           nonlocal x
           x = 6
           print(x)
        yield bar
        def baz():
           print(x)
        yield baz
    
    # Affiche 6 et 6
    for f in foo():
        f()

    Matthieu Gautier|irc:starmad

  • [^] # Re: J'un souci avec l'orthographe.

    Posté par  (site web personnel) . En réponse au journal Un souci…. Évalué à 7.

    Et d'ailleurs, c'est pour ça qu'il vaut mieux se faire relire par un autre.

    Petite astuce pour ceux et celles qui n'ont pas de relecteur à portée de main: Relire son texte à l'envers.

    En remontant le texte le cerveau ne peut pas se laisser porter par le sens du texte et il est plus facile de se concentrer sur la détection de fautes d'orthographe/accord.

    Matthieu Gautier|irc:starmad

  • # Sans lib, avec visualisation et deuxième partie non bourrine

    Posté par  (site web personnel) . En réponse au message Avent du Code, jour 12. Évalué à 2.

    J'ai beaucoup aimé l'exo du jour.

    Comme beaucoup (tout le monde), un petit algo de parcours de graph pour trouver le chemin le plus court.

    J'ai fait une première version "naïve" qui priorisait pas les chemin et donc avançait par "inondation" (D'où le nom de fonction flood_map). J'avais un "front" (le point de départ au début) et à chaque passe je calculais un nouveau front (les cases accessibles à partir du front actuel). Dès qu'on arrive à l'arrivée, on sait combien il faut d'étapes.
    Ça marche très bien, et ça a l'avantage d'être la valeur exacte.

    Et je me suis amuser à faire du A*, et donc explorer une seule case du front (au lieu de toutes) et de choisir la case à privilégier en fonction d'un heuristique.
    C'est beaucoup plus efficace en terme de performance (nb de case étudiées) mais ça ne donne pas forcement le résultat le plus optimal selon l'heuristique utilisé. (Heureusement que j'avais la première version)

    Pour la partie deux, l'astuce c'est de partir de la fin et de s'arrêter dès qu'on trouve une case 'a'. Ça évite de faire du brute force à partant de toutes les cases a.

    Voici la version A* :
    (Vous pouvez le lancer avec votre input pour avoir une petite animation)

    #!/usr/bin/python3
    
    from enum import Enum
    from time import sleep
    from math import sqrt
    import sys
    
    def yield_input():
        import sys
        with open(sys.argv[1]) as f:
            for l in f:
                l = l.strip()
                yield l
    
    class Seen(Enum):
        NONE = 0
        CURRENT = 1
        SEEN = 2
    
    current_color = None
    
    def print_color(color, out):
        global current_color
        if current_color != color:
            current_color = color
            print(color, end="")
        print(out, end="")
    
    class Cell:
        def __init__(self, height, coord):
            self.height = height
            self.coord = coord
            self.seen = Seen.NONE
            self.path_length = 0
            self.previous = None
            self.is_on_the_way = False
    
        # Yield other if we can go there from self
        def yield_check_up(self, other, what=Seen.NONE):
            #print(f"{other.seen} {other.height} {self.height}")
            if other.seen == what and other.height <= self.height + 1:
                other.path_length = self.path_length+1
                other.seen = Seen.CURRENT
                yield other
    
        def yield_check_down(self, other, what=Seen.NONE):
            #print(f"{other.seen} {other.height} {self.height}")
            if other.seen == what and other.height >= self.height - 1:
                other.path_length = self.path_length+1
                other.seen = Seen.CURRENT
                yield other
    
        def print(self):
            global current_color
            if self.seen == Seen.NONE:
                color = "\033[40m"
            elif self.seen == Seen.CURRENT:
                color = "\033[46m"
            else:
                color = "\033[44m"
            if self.is_on_the_way:
                color = "\033[41m"
            char = chr(ord('a')+self.height)
            print_color(color, char)
    
    def move_up(coord):
        return coord[0]-1, coord[1]
    
    def move_down(coord):
        return coord[0]+1, coord[1]
    
    def move_left(coord):
        return coord[0], coord[1]-1
    
    def move_right(coord):
        return coord[0], coord[1]+1
    
    
    class Map:
        def __init__(self):
            self.map = []
            for i, line in enumerate(yield_input()):
                map_line = []
                for j, h in enumerate(line):
                    if h == "S":
                        self.start = (i, j)
                        height = 0
                    elif h == "E":
                        self.end = (i, j)
                        height = 25
                    else:
                        height = ord(h) - ord('a')
                    map_line.append(Cell(height, (i,j)))
                self.map.append(map_line)
                self.nb_lines = len(self.map)
                self.nb_columns = len(self.map[0])
            print(self.nb_lines, self.nb_columns)
    
        def get(self, coord):
            return self.map[coord[0]][coord[1]]
    
        def clear(self):
            for line in self.map:
                for cell in line:
                    cell.seen = Seen.NONE
                    cell.path_length = 0
                    cell.previous = None
                    cell.is_on_the_way = False
    
        # Direction is up or down
        def see_arround(self, cell, direction, what=Seen.NONE):
            attr = f"yield_check_{direction}"
            coord = cell.coord
            if coord[0]> 0:
                yield from getattr(cell, attr)(self.get(move_up(coord)), what)
            if coord[0] < self.nb_lines-1:
                yield from getattr(cell, attr)(self.get(move_down(coord)), what)
            if coord[1] > 0:
                yield from getattr(cell, attr)(self.get(move_left(coord)), what)
            if coord[1] < self.nb_columns-1:
                yield from getattr(cell, attr)(self.get(move_right(coord)), what)
    
        def flood_map(self, start, scoring, check, direction):
            to_see = [self.get(start)]
            round = 0
            while True:
                cell, to_see = to_see[0], to_see[1:]
                if check(cell):
                    return cell, round
                cell.seen = Seen.SEEN
                for next_cell in list(self.see_arround(cell, direction)):
                    next_cell.previous = cell
                    to_see.append(next_cell)
                to_see.sort(key=scoring)
                round += 1
                self.print(round)
    
        def find_a_way_to_summit(self):
            # Scoring is important.
            # A* found quickly A solution, but it may not the best one.
    
            # This scoring is fast but not exact:
            # Result:422, round:1460
            scoring = lambda c: c.path_length + abs(c.coord[0]-self.end[0])**2 + abs(c.coord[1]-self.end[1])**2
    
            # This scoring give more importance to path_length and give the good result
            # Result:412, round:3722
    #        scoring = lambda c: c.path_length + sqrt(abs(c.coord[0]-self.end[0])**2 + abs(c.coord[1]-self.end[1])**2)
            return self.flood_map(self.start, scoring, lambda cell: cell.coord == self.end, "up")
    
        def find_path(self, end):
            current = end
            while current:
                #0print(current.coord)
                current.is_on_the_way = True
                current = current.previous
                self.print(5)
    
        def find_shorter_path_to_summit(self):
            # This scoring is fast but not exact:
            #Result:410, round: 2276
            scoring = lambda c: c.height
    
            # This scoring give more importance to path_length and give the good result
            # Result:402, round:2400
    #        scoring = lambda c: c.path_length + c.height
            return self.flood_map(self.end, scoring, lambda cell: cell.height == 0, "down")
    
        def print(self, round):
            global current_color
            # clear the terminal
            print("\033c", end="")
            current_color = None
            print(round)
            for line in self.map:
                for cell in line:
                    cell.print()
                print()
            sleep(0.005)
    
    
    
    def round1(map):
        cell, nb_round = map.find_a_way_to_summit()
        map.find_path(cell)
        map.print(cell.path_length)
        return cell.path_length, nb_round
    
    def round2(map):
        cell, nb_round = map.find_shorter_path_to_summit()
        map.find_path(cell)
        map.print(cell.path_length)
        return cell.path_length, nb_round
    
    
    def main():
        map = Map()
        result_1 = round1(map)
        map.clear()
        result_2 = round2(map)
        print("Round 1 :", result_1)
        print("Round 2 :", result_2)
        print(map.nb_lines, map.nb_columns)
    
    
    if __name__ == "__main__":
        main()

    Matthieu Gautier|irc:starmad