MediaRecorder : Bienvenue dans IE6/7/8

En ce moment je bosse sur l'appli de documents/exercices que j'utilise en cours (cf https://warriordudimanche.net/article1686/lappli-documents-que-jai-codee-pour-taf pour mémoire).

J'implémente toute une nouvelle rubrique et de nouveaux items afin de couvrir le spectre de l'expression orale de façon simple en ajoutant une sorte de labo de langue simplifié.En gros, je veux que le gamin puisse travailler à l'écoute de mots modèles mais également qu'il puisse s'enregistrer et se réécouter simplement et quelque soit le support...

Les frontend qui me lisent voient de suite où ça va couiller (merci les copaines)

Et oui, j'ai codé un truc qui fonctionne très bien, relativement propre et simple, facile à utiliser... sous Firefox, opera, vivaldi, chromium et sous Android.

Hélas, ma solution utilise l'API MediaRecorder qui semble présenter des difficultés sous certains navigateurs, vous devinez lesquels...

J'ai testé sur safari (enfin epiphany passque j'ai pas d'apple sous la pogne, tu te doutes...) et ça refuse de fonctionner, vu que MediaRecorder y est bloqué pour nôôôtre saicuritay...

J'ai ensuite testé sur Edge avec mon portable et ça n'a pas fonctionné... toutefois, quand j'ai installé le deb d'Edge sur mon linux ⬇⬇⬇ ...

Parfois, la vie vous envoie   des épreuves, vous savez...

...là, ça a fonctionné... Mais si ça marche, ça doit venir de Linux et pas de Edge (mauvaise foi inside )

Donc en gros, on revient à des soucis de compatibilité avec le nouvel IE ?! (ouelcome to aoueur fanne tasse tique taïme meuchine !)

Nous voila   revenus aux   joies d'Internet   Explorer ?!

Pourtant, canIuse me dit que ça devrait fonctionner, même sous Safari:

Capture du 2024-01-19 12-02-36.png

Bon, avec le navigateur à la pomme, il y a bien une manip à faire dans la configuration avancée pour les devs qui pourrait débloquer la situation mais je me vois mal demander ça à des élèves qui éprouvent déjà des difficultés non négligeables à discerner la barre d'adresse ou qui peinent - la sueur au front - à taper une majuscule sans passer par la touche de verrouillage...

Allez bouffer   vos morts   micro$oft   et apple
Beut ouate        iz ze   solouchonne ?

Donc, là, pour le moment, rien à faire dans l'immédiat pour utiliser simplement MediaRecorder avec safari ou Edge... j'ai donc opté pour une «solution» temporaire: en cas d'absence de l'API, j'ajoute une classe spécifique et je disable les recorders de la page, puis j'affiche un message d'avertissement avec des liens vers des navigateurs compatibles (firefox et forks en tête)...

Après, j'ai bien trouvé un polyfill qui pourrait faire le job ( https://github.com/ai/audio-recorder-polyfill ) mais je ne l'ai pas testé, c'est un peu lourd à installer et pis... c'est pas moi qui l'ai fait...

Si quelqu'un/e a une idée... je prends...

(...)

5 extraits CSS que tout développeur front-end devrait connaître en 2024

Il y a de ces trucs en CSS quand même...

Quelques notes perso ici...

:has()

styler le parent en fonction du nombre d'enfants

Pour modifier une grid par exemple...

main:has(> :nth-child(5)) {…}

styler un élément selon l'état d'une checkbox

Pour appliquer un darkmode

html:has(#dark-mode:checked) {…}

styler un form dont au moins un des items est invalide

form:has(:user-invalid) .error {
  display: block;
}

L'imbrication CSS

Et moi qui pensais que ce n'était réservé qu'à des sass & consorts !

Voilà qui permettra de mieux organiser le code et le rendre plus lisible...

/*AVANT*/
.nesting {
  color: hotpink;
}
.nesting > .is {
  color: rebeccapurple;
}
.nesting > .is > .awesome {
  color: deeppink;
}
/* MAINTENANT*/
.nesting {
  color: hotpink;

  > .is {
    color: rebeccapurple;

    > .awesome {
      color: deeppink;
    }
  }
}

[EDIT] Par contre, ce n'est pas forcément supporté par les navigateurs pas à jour... https://caniuse.com/css-nesting

text-wrap:balance

en gros, pour rendre plus homogène un texte sur plusieurs lignes... Attention, pas pour un texte de plus de 10 lignes apparemment.

via https://bookmarks.ecyseo.net/?DunHiA

Astuces & liens pour HTML, JS et toussa

Petite liste tirée des RSS que je suis en ce moment.

FormData API | 12 Days of Web

Un petit résumé perso de cette page sur l'objet FormData en javascript.

Créer un objet FormData à partir d'un formulaire

let form = document.querySelector('form');
let data = new FormData(form);

Parcourir l'objet FormData

C'est un itérable, donc on le parcourt avec un for et on récupère des ['clé','valeur']

for (let entry of data) {
    console.log(entry);
}

ou

for (let [key, value] of data) {
    console.log(key);
    console.log(value);
}

parcourir les clés / les valeurs

for (let key of data.keys()) {
  console.log(key);
}

Get, set, update des valeurs

GET

Récupérer une valeur (sans rire ?!)

  • S'il y a un seul champ au nom de la clé: let title = data.get('title')
  • S'il y en a plusieurs : let titles = data.getAll('title');

SET

Ajouter une nouvelle valeur à l'objet FormData

data.set('date', '2022-12-25');

APPEND

Ajouter une valeur supplémentaire à une entrée existante (si l'entrée n'existe pas, elle est créée)

data.append('tags', 'vacations');

Divers

Tester si un champ existe

let hasID = data.has('id');

Récupérer un tableau

  • des clés : let arr = Array.from(data.keys());
  • des valeurs : let arr = Array.from(data.values());

Convertir un FormData en objet clés valeurs

Si votre FormData ne contient pas plusieurs champs ayant le même nom.

let serialized = Object.fromEntries(data);

Sinon, on paufine

let obj = {};
for (let [key, value] of data) {
    if (obj[key] !== undefined) {
        if (!Array.isArray(obj[key])) {
            obj[key] = [obj[key]];
        }
        obj[key].push(value);
    } else {
        obj[key] = value;
    }
}

Une fois converti en objet, on peut le transformer en JSON

let stringified = JSON.stringify(obj);

How can I listen for a click outside of an element in JavaScript? - 30 seconds of code

Pour écouter un click hors d'un élément, on utilise l'event delegation: on vérifie si la target de l'event correspond ou pas à l'objet qu'on veut.

  document.addEventListener('click', e => {
    if (!element.contains(e.target)) callback();
  });
};
onClickOutside('#my-element', () => console.log('Hello'));
// Will log 'Hello' whenever the user clicks outside of #my-element

How can I listen for an event only once in JavaScript? - 30 seconds of code

Tiens, je ne savais pas qu'addEventListener acceptait des paramètres en option, en particulier un { once : true} qui permet de n'exécuter la fonction attachée à l'évènement qu'une seule fois...


const listenOnce = (el, evt, fn) =>
  el.addEventListener(evt, fn, { once: true });

listenOnce(
  document.getElementById('my-btn'),
  'click',
  () => console.log('Hello!')
); // 'Hello!' will only be logged on the first click

A (more) Modern CSS Reset - Andy Bell

De côté pour plus tard... Une reset.css plus moderne... Je me contentais du box-sizing depuis son avènement.

Les explications associées sont intéressantes.

/* Box sizing rules */
*,
*::before,
*::after {
  box-sizing: border-box;
}

/* Prevent font size inflation */
html {
  -moz-text-size-adjust: none;
  -webkit-text-size-adjust: none;
  text-size-adjust: none;
}

/* Remove default margin in favour of better control in authored CSS */
body, h1, h2, h3, h4, p,
figure, blockquote, dl, dd {
  margin: 0;
}

/* Remove list styles on ul, ol elements with a list role, which suggests default styling will be removed */
ul[role='list'],
ol[role='list'] {
  list-style: none;
}

/* Set core body defaults */
body {
  min-height: 100vh;
  line-height: 1.5;
}

/* Set shorter line heights on headings and interactive elements */
h1, h2, h3, h4,
button, input, label {
  line-height: 1.1;
}

/* Balance text wrapping on headings */
h1, h2,
h3, h4 {
  text-wrap: balance;
}

/* A elements that don't have a class get default styles */
a:not([class]) {
  text-decoration-skip-ink: auto;
  color: currentColor;
}

/* Make images easier to work with */
img,
picture {
  max-width: 100%;
  display: block;
}

/* Inherit fonts for inputs and buttons */
input, button,
textarea, select {
  font: inherit;
}

/* Make sure textareas without a rows attribute are not tiny */
textarea:not([rows]) {
  min-height: 10em;
}

/* Anything that has been anchored to should have extra scroll margin */
:target {
  scroll-margin-block: 5ex;
}
Via https://links.kalvn.net/shaare/McJg3Q

PHP - Notes perso sur Imagick 2 - ImagickDraw... si on dessinait ?

Deuxième épisode de mes notes perso sur la bibliothèque Image magic pour évoquer la classe ImagickDraw qui, comme son nom l'indique, permet de dessiner avec Imagick. ( 1er épisode )

On va se limiter à des usages basiques parce que la lecture du sommaire suffit à imaginer des possibilités certes alléchantes mais totalement hors de propos en ce qui me concerne (courbes de bézier etc)

Spoiler: c'est nettement moins intuitif et simple que pour le traitement d'image... l'écart entre Imagick et GD dans le domaine du tracé n'est plus si évident: ça mériterait de faire un classe pour simplifier tout ça... ( /me se jette sur son bujo pour griffonner spasmodiquement)

Préambule

Cette classe crée un objet servant d'instructions à appliquer ensuite à un objet Imagick.

On partira du principe que vous avez fait des instances des classes comme suit:

$im=new Imagick(); # l'image dans laquelle vous allez appliquer l'objet ImagickDraw
$draw=new ImagikDraw();

Ajouter un texte

Fixer les caractéristiques

  • $draw->setFont(fonte); : sélectionne la fonte à utiliser
  • $draw->setFontSize(taille); : définit la taille en pixels
  • $draw->setFillColor(couleur);: définit la couleur de fond (normalement, couleur est un objet ImagickPixel, voir 1er épisode mais on peut passer une chaîne au format de couleur CSS )
  • $draw->setTextAlignment(alignement); : une des constantes d'alignement imagick::ALIGN_LEFT imagick::ALIGN_CENTER Imagick::ALIGN_RIGHT
  • $draw->setGravity(Imagick::GRAVITY_CENTER); centre le texte dans sa boîte (horizontal et vertical)
  • $draw->setTextDecoration(decoration): une des constantes de décoration imagick::DECORATION_UNDERLINE imagick::DECORATION_OVERLINE imagick::DECORATION_LINETROUGH et bien d'autres (comme du... bruit ?!).
  • $draw->setTextAntialias(true);: ajouter de l'antialias
  • l'espacement :
    • entre les mots : $draw->setTextInterwordSpacing(taille)
    • entre les lignes : $draw->setTextInterlineSpacing(taille)

Tracer le texte

  • $draw->annotation(x,y,texte) : trace un texte dans la police sélectionnée
  • $im->annotateImage( $draw, 0, 0, 0, $fontName ); : ajoute le texte à l'image.

Obtenir des infos utiles

  • obtenir la liste des polices disponibles: $im->queryFonts($pattern = "*") 🆒 on peut filtrer avec une pattern à la façon de glob().
  • obtenir les infos fixées par setXXX : getXXX ... ainsi on a getFont(), getFontSize() etc...
  • obtenir les dimensions de la boîte de texte: $im->queryFontMetrics($draw, text); on récupère un tableau comme ci-dessous
  • 
    Array
    (
        [characterWidth] => 9
        [characterHeight] => 9
        [ascender] => 9 # la taille au-dessus de la baseline
        [descender] => -2 # la taille sous la baseline
        [textWidth] => 71
        [textHeight] => 10
        [maxHorizontalAdvance] => 12
        [boundingBox] => Array
            (
                [x1] => 0
                [y1] => -2
                [x2] => 6.890625
                [y2] => 7
            )
        [originX] => 70
        [originY] => 0
    )
    

    Dessiner des formes

    Fixer les caractéristiques

    • opacité du trait : $draw->setStrokeOpacity(0-1);
    • couleur du trait : $draw->setStrokeColor(couleur);
    • épaisseur du trait : $draw->setStrokewidth(nb);
    • type de trait : $draw->setStrokeDashArray() Le motif semble être plein de possibilités car on peut le définir très spécifiquement et même utiliser une image comme motif (->setStrokePatternURL)
    • couleur de remplissage : $draw->setFillColor(couleur);

    Formes

    • cercle : $draw->circle ($x, $y, $x + $r, $y);
    • ellipse : $draw->ellipse($ox,$oy,$rx,$ry,$start,$end);
    • point : $draw->point ($x, $y);
    • polygone : $draw->polygon ($tableau_de_coordonnées); : array( 'x' => 3, 'y' => 4 ), array( 'x' => 2, 'y' => 6 )
    • ligne brisée : $draw->polyline ($tableau_de_coordonnées); : array( 'x' => 3, 'y' => 4 ), array( 'x' => 2, 'y' => 6 )
    • rectangle : $draw->rectangle ($x, $y, $x2, $y2); )
    • rectangle arrondi: $draw->roundRectangle ($x, $y, $x2, $y2,$rayonx,$rayony);

    Exemple

    Pour écrire un texte dans une image:

    
    $text='pipo et mollo';
    $im=new Imagick();
    $draw=new ImagickDraw();
    //var_dump($im->queryFonts('*'));exit;
    $draw->setFont( 'Courier' );
    $draw->setFontSize( 20 );
    $draw->setFillColor( 'black' );
    $draw->setTextAntialias(true);
    $metrics = $im->queryFontMetrics($draw, $text);
    $draw->annotation(0,$metrics['ascender'],$text);
    $im->newImage( 300, 20, 'lightblue');
    $im->drawImage($draw);
    $im->setImageFormat( 'png' );
    header('Content-type: image/jpeg');
    exit($im);  
    
    ce qui donne cette image
    index2.png
    C'est pas ouf...

    Il serait intéressant de pousser les tests mais là, j'ai pas le temps...

    Peut-être reprendrais-je des trucs existant avec tout ça ( scriptopic, RoR, Stamp mematic etc etc.)

    Et c'est là que Bronco prit  conscience de la quantité de   merdes affligeantes qu'il avait  codées sur un coup de tête  à la va-comme-je-te-pousse   et qu'il avait infligées à tous...

    PHP - Notes perso sur Imagick, un résumé de pourquoi je vire GD à coups de pompes dans l'oignon.

    Allez, pour une fois, j'ai un peu de temps devant moi, je vais éplucher un peu la lib Image magick dont je parlais il n'y a guère...

    La base

    charger UNE image

    Simple: pas besoin de plusieurs fonctions selon le format, il suffit de $images = new Imagick('image.jpg');

    charger DES images (et là c'est fort)

    Même pas nécessaire de passer par un foreach, on fournit le tableau des fichiers voire directement un glob: $images = new Imagick(glob('images/*.JPG'));

    Sauver une image

    $im->writeImage('image.jpg');

    Faire une miniature

    Si on laisse une dimension à 0, les proportions sont conservées (quand tu vois la merde que c'est avec GD !) $image->thumbnailImage(100, 0);

    Output une image

    header('Content-type: image/jpeg');
    $image = new Imagick('image.jpg');
    # ici on effectue un traitement puis on sort le résultat
    echo $image;

    Récupération d'infos sur les images

    • taille $im->getImageWidth() $im->getImageHeight()
    • format $im->getImageFormat()

    création d'une nouvelle image

    $im->NewImage(largeur,hauteur,couleur de fond);

    création d'une couleur

    Comme pour GD, il faut créer un objet couleur dans les traitements d'image, mais c'est plus simple qu'avec GD (et plus complet): il suffit de passer une couleur selon les normes CSS. Du coup, la transparence n'est pas gérée par une connerie de paramètre «alpha» mais simplement par ... rgba()... 💖

    $couleur=new ImagickPixel("white");
    $couleur=new ImagickPixel("#FFF");
    $couleur=new ImagickPixel('rgb(255,255,200)');
    $couleur=new ImagickPixel('rgba(255,255,200,0.5)');

    🆒 ⮕ Ça peut paraître compliqué, mais en fait, dans les fonctions où on est sensé utiliser ImagickPixel, je me suis aperçu qu'on pouvait tout simplement passer une string contenant la couleur css... elles se démerdent seules. 😍

    Traitements

    Ajouts

    • de bordure ->borderImage(couleur,largeur bords verticaux, largeur bords horizontaux): $im->borderImage(new ImagickPixel("white"), 5, 5);
    • de texte :
    • de stéganographie (cacher un filigrane dans une image) ->steganoImage():

    Modification de couleurs

    • sepia ->sepiaToneImage(force) : une valeur raisonnable est 80 (sic)
    • solarisation ->solarizeImage(force)
    • négatif ->negateImage(gris): $im->negateImage(0);
    • niveaux
      • $im->normalizeImage();
      • $im->autoLevelImage();
    • gamma ->gammaImage(niveau) : $im->gammaImage(5);
    • contraste $im->contrastImage(niveau)
    • luminosité et contraste $im->brightnessContrastImage(niveau luminosite, niveau contraste);
    • égalisation $im->equalizeImage()
    • coloriser ->colorizeImage(couleur,opacite) : $im->colorizeImage("red",0.5); 🤬 pas réussi à l'utiliser pour ce test...

    Modification de taille et d'orientation

    • redimensionner :
      • ->resizeImage(largeur,hauteur, filtre, flou) : $i->resizeImage(250,0,Imagick::FILTER_POINT,0);
      • ->scaleImage(largeur,hauteur): pas encore compris la différence avec la précédente
      • recadrer ->cropImage(largeur,hauteur,x,y): $im->cropImage(200,200,50,50);
      • 💖 créer une miniature à la taille donnée en recadrant l'image autour du centre ->cropThumbnailImage(largeur,hauteur)
    • retourner :
      • $im->flipImage() pour retourner horizontalement
      • $im->flopImage() pour retourner verticalement
    • pivoter ->rotateimage(color, $angle): $im->rotateImage(new ImagickPixel('#00000000'), 75);

    Modifications de qualité

    • modification d'opacité ->setImageOpacity(0-1) : $im->->setImageOpacity(0.3);
    • netteté ->sharpenImage(rayon, deviation,canal):
    • amélioration ->enhanceImage()
    • flou :
      • flou tout court ->blurImage(rayon, décalage): $im->blurImage(5,2);
      • gaussien ->gaussianBlurImage(rayon, deviation) : $im->gaussianBlurImage(5,2);
      • de mouvement ->motionBlurImage(rayon,deviation,angle) : $im->motionBlurImage(5,5,45);
    • réduction du nombre de couleurs ->posterizeImage(nb de couleurs, 0/1) :$im->posterizeImage(5,0);
    • ajout de bruit ->addNoiseImage(type) : `$im->addNoiseImage(imagick::NOISE_GAUSSIAN ); voir les constantes de type de bruit

    Modification d'aspect et déformations

    • aspect crayon $im->sketchImage(rayon, deviation, angle);
    • aspect fusain $im ->charcoalImage(rayon, deviation);
    • aspect emboss ->shadeImage(gris, angle, hauteur):
      • $im->->shadeImage(1, 90, 2); # emboss + image grisée
      • $im->shadeImage(0, 90,2) # emboss sur l'image d'origine (couleur)
    • peinture à l'huile ->oilPaintImage(rayon) : $im->oilPaintImage(5);
    • détection de bords ->edgeImage(rayon) : $im->edgeImage(5);
    • vagues ->waves(amplitude,longueur): $im->waveImage( 10, 10);
    • déformation ->distortImage(methode, arguments[],0) : voir les constantes de déformation

    interactions d'images

    Conclusion

    Image Magick me semble particulièrement bien nommée tant les possibilités sont énormes et la simplicité d'utilisation étonnante: on sent une volonté de se simplifier la vie lors de l'utilisation... c'est juste beau.

    Je voulais mettre une image de chaque effet dans les descriptions mais:

    1. ça prenait une place de ouf
    2. je préfère reprendre certaines de mes applis/api avec imagick
    3. j'ai plus le temps, les autres arrivent
    4. j'ai la flemme.

    [EDIT] En fait, j'ai fait une page de test même si tout n'est pas concluant : http://test.warriordudimanche.net/imagick/

    19 licences méconnues et inhabituelles

    Tout le monde connaît les licences libres habituelles mais il y en a de moins connues et - souvent - moins compliquées à comprendre : petit florilège...

    Les licences les plus libres

    La WTFPL

    Do What The Fuck You Want to Public License - https://fr.wikipedia.org/wiki/WTFPL

    Permet de distribuer avec le même niveau de protection que le domaine public, c'est-à-dire AUCUN.

    La Beerware

    Beerware licence - https://en.wikipedia.org/wiki/Beerware#License

    Faites ce que vous voulez et si un jour on se rencontre et que vous trouvez que mon boulot en vaut la peine, payez-moi une bière.

    La Bugroff

    No problem Bugroff License - http://tunes.org/legalese/bugroff.html

    La réponse à toute question à propos des droits de reproduction ou problème légal est : «Sure, No problem. Don't worry, be happy. Now bugger off»

    La DAMAIL

    Don’t Ask Me About It License

    En gros, faites ce que vous voulez et ne me contactez pas.

    La GLWTPL

    Good Luck With That Public License - https://github.com/me-shaon/GLWTPL

    Démerde-toi, demande pas d'aide et - surtout - ne dis à personne que ça vient de moi...

    La Woody Guthrie

    The Woody Guthrie Public License

    «Toute personne qu'on prendra à distribuer ce livre sans permission se verra considéré comme un super pote parce qu'on en a rien à foutre...»

    La DSSL

    Demerden Sie Sich License - https://dssl.flyounet.net/licenses/

    Littéralement, la Licence Démerdez-vous... Je vous laisse la lire tranquilou pour vous faire une idée: toute tentative de résumé serait une trahison du texte original

    «Cette Licence» se réfère à la version 1 de la «Demerden Sie Sich License» (le texte original en français). «Démerder», se réfère au sens de se «débrouiller». A aucun moment «cette Licence» ne vous demandera de vous enduire (vous ou votre œuvre) d'excréments humains (ni même animal). «Œuvre» est aussi appelée «travail» (quelques fois, l'extension «de sagouin» peut lui être apposée), «programme» ou tout autre terme relatif à ce qui a été effectué. Ainsi, une «documentation» ou un «manuel» peut être considéré comme une œuvre. «Auteur» signifie que la personne (ou groupe de personnes), qui utilise «cette Licence», se lave complètement les mains de la façon dont vous utiliserez son œuvre.

    L'«Auteur» peut-être considéré comme irresponsable et il incombe à l'utilisateur en priorité de se «démerder» par lui même.


    Les licences les plus WTF

    La D&R

    The Death and Repudiation License

    This software may not be used directly by any living being.

    En gros, l'usage à toute personne vivante est formellement interdit.

    La CDL

    Chicken dance license - https://github.com/supertunaman/cdl/blob/master/COPYING

    Conditions très exotiques pour cette licence qui régule drastiquement la redistribution des copies du code:

    • à chaque 1000ème copie distribuée au moins la moitié des employés ou personnes affiliées doit écouter «the chicken dance» de Werner Thomas
    • à chaque 20000ème copie distribuée, une personne affiliée doit exécuter la Chicken dance dans une vidéo
    • il est formellement interdit à tout employé ou personne affiliée de prononcer le mot «gazorninplat» en public tant que dure la distribution du produit.

    La FCL

    The Fight Club Licence - https://github.com/benlk/misc-licenses/blob/master/fight-club-license.md

    • You do not talk about the FIGHT CLUB LICENSE.
    • You DO NOT talk about the FIGHT CLUB LICENSE.
    • If someone says "stop" or goes limp — or taps out — the project is over.
    • Only two developers to a project.
    • One project at a time.
    • No shirts, no shoes.
    • Projects will go on as long as they have to.
    • If this is your first time reading the FIGHT CLUB LICENSE, you HAVE to license your next project under the FIGHT CLUB LICENSE.

    La OGPITAL

    The Offendo General Pain In The Ass License

    L'auteur de toute modification doit redistribuer le travail modifié par un moyen plus contraignant et difficile que celui par lequel il a acquis le code original.

    La Licence de Schrödinger

    https://github.com/benlk/misc-licenses/blob/master/schrodinger-license.md

    Heu, là, je vous laisse aller la voir tous seuls.... passque bobo têtête.

    La Bugs

    The Bugs License r2 - https://github.com/benlk/misc-licenses/blob/master/bugs-license.md

    Pour faire court, c'est pas un bug c'est une fonctionnalité...

    • Bugs in the licensed work are features, to be cherished, documented, and developed upon.
    • Modified works must not include known bugs.
    • Where identified, modified works' bugs shall be fixed.
    • Authors and maintainers of the licensed work reserve the right to pull bug fixes from modified or derivative works without compensation, recognition, or any other reference to the authors of the bug fix.

    La ABSL

    The Anyone But Stallman License - https://github.com/benlk/misc-licenses/blob/master/stallman-license.md

    Je crois que c'est clair...

    La Méphisto

    The Mephistopheles License - https://github.com/benlk/misc-licenses/blob/master/mephistopheles-license.md

    Tu veux redistribuer ?! signe ici... avec ton sang.

    La WTFWYEDTHS

    Why The Fuck Would You Even Do That Holy Shit Public License - https://git.sr.ht/~boringcactus/gotbruh/tree/main/item/LICENSE.md

    Seule restriction : il est définitivement et formellement interdit de refactorer ce logiciel en Python 2.


    Les plus utilisables en vrai

    La DBAD

    Don't be a dick License - https://dbad-license.org/

    Une licence qui autorise tout avec pour seule condition de ne pas être un connard (a dick)... l'auteur fournit une liste non exhaustive de ce qu'il appelle être un connard:

    • se contenter de copier et de changer le nom
    • vendre une version non modifiée sans produire le moindre travail
    • Faire des modifications afin d'implémenter du contenu dangereux
    • Faire de l'argent avec et devenir riche sans même soutenir l'auteur
    • etc

    L' ACSL

    Anti-Capitalist Software License [non «libre»]- https://anticapitalist.software/

    Vous voulez partager un logiciel ou un code en interdisant toute exploitation commerciale capitaliste et libérale ? Cette licence permet de restreindre l'usage et l'exploitation à certains types d'utilisateurs:

    • une personne privée travaillant pour elle-même
    • une organisation à but non lucratif
    • une organisation à but éducatif
    • une organisation visant les profits partagés pour tous ses membres
    • si l'utilisateur est une organisation alors tous les travailleurs sont propriétaires et inversement.

    La Please

    The please public licence - https://web.archive.org/web/20200814151216if_/https://awoo.space/@typhlosion/1433790

    L'utilisateur a le droit... de demander la permission et l'auteur a l'obligation d'accepter

    Sources :

    (...)

    Api perso: Fetchit, le bon chienchien du oueb...

    Ouate ?

    Après avoir fait goofi puis Getlib j'ai codé vite fait une petite «api» destinée à ramener en local n'importe quelle ressource distante... «quelle différence avec getlib ?» allez-vous me demander sur un ton narquois à propos de la cruauté duquel je tairais scrupuleusement tout commentaire.

    J'ai eu envie de faire ça car j'en avais assez de passer par le combo

    bouton droit sur une ressourcetélécharger envoyer sur mon sitefaire un lien ou une img

    Du coup, il suffit d'ajouter l'adresse de l'api à l'url vers la ressource distante... Donc http://insta.com/image.jpg devient par exemple http://api.warriordudimanche.net/fetchit?url=http://insta.com/image.jpg

    Fetchit va récupérer la ressource en local et vous servir cette version au lieu de la distante. Comme d'hab' si cette ressource a déjà été récupérée elle n'est pas re téléchargée.

    Le deuxième effet kiskool (paye ta réf de vieux) c'est que du coup, comme getlib, ça permet de récupérer toute lib en local et être plus RGPD friendly.

    Examples:

  • utiliser directement une image distante : <img src="http:www.distantserver.com/pic.png"/> ➜ <img src="http://api.url.com?url=http:www.distantserver.com/pic.png"/>
  • lien vers une ressource distante : <a href="http:www.distantserver.com/file.pdf"> Link to distant file</a> ➜ <a href="http://api.url.com?url=http:www.distantserver.com/pic.png"> Link to distant file</a>
  • utiliser une lib hébergée sur un CDN distant : <script src="http:www.distantnastyserver.com/lib.js"></script> ➜ <script src="http://api.url.com?url=http:www.distantnastyserver.com/lib.js"></script>

    Con figue ?

    Afin d'éviter que votre server ne se retrouve floodé par des fichiers vidéos 8K à 60 gigots l'unité, il y a une limite de taille configurée dans la constante SIZE_LIMIT, fixée par défaut à 10 Mo.

    Le code ?! c'est... le code.

    Ceux qui aiment farfouiller verront que cette fois, j'ai fait une classe fetchit_class.php qui se charge de tout. Son fonctionnement est tellement simple que je me fissure même pas le joufflu à vous le détailler, démerdez-vous.

    License

    Comme d'hab', c'est cadeau... Utilisez, partagez, modifiez... juste respectez la Dont be a dick licence

    donne le ouade

    Comme tout ça n'a de sens que si on héberge soi-même, vous pouvez récup' le zip qui va bien ici : https://api.warriordudimanche.net/fetchit/?download

    Le mot final

    Mes chers cons-patriotes, non aux fuites de données, vive le oueb libre et participatif et vive la france et bisou !

  • document.execCommand - Référence Web API | MDN

    https://antoineboursin.fr/courses/creez-un-editeur-de-texte-wysiwyg

    La vie est mal faite: je découvre document.execCommand() permettant de faire du richtext dans un élément contentEditable juste quand il est officiellement déclaré obsolète...

    Bon, en même temps, sur stackoverflow, the holy baïbol, certains affirment que:

    1. oui, il est obsolète mais n'a pas d'alternative
    2. execCommand semble requis pour tout navigateur prétendant sortir sur le marché,
    3. son implémentation semble sujette à variations selon le navigateur (le fameux internet explorer syndrome de triste mémoire)
    Mais merde !  Je fais quoi moi ?!

    RIDITLETEUR spécial DEV : CSS, HTML, JS, PHP...

    A l'occasion d'un ménage dans les brouillons de billets, je compile les trucs DEV qui trainaient par là

    Ressources CSS

    Ressources JS

    Ressources PHP

    • https://github.com/jcampbell1/simple-file-manager : GitHub - jcampbell1/simple-file-manager: A Simple PHP file manager. The code is a single php file.
    • https://grafikart.fr/tutoriels/authentification-2-facteurs-totp-630 : Tutoriel vidéo PHP : Authentification 2 facteurs, TOTP | Grafikart
    • https://phpbestpractices.org/ : A short, practical guide for common and confusing PHP tasks (Storing passwords, PHP and MySQL, PHP tags, Auto-loading classes, Single vs. double quotes, define() vs. const, Caching PHP opcode, PHP and Memcached, PHP and regex, Serving PHP, Sending email, Validating email addresses, Sanitizing HTML, PHP and UTF-8, Working with dates and times, Checking null and false values, Removing accent marks (diacritics) )

    ChatGPT - Sage - Poe - Les programmeurs pas [encore] en danger

    poe.com, un [bon?!] moyen de tester ChatGPT sans numéro de téléphone, en ne donnant qu'une adresse email, éventuellement jetable.

    Je me suis dit, tiens, si je testais avec la génération d'un bout de code ?

    Par manque de temps comme par curiosité, je lui ai soumis un truc qui me trotte dans la tête : la séparation des mots espagnols en syllabes (beaucoup moins simple qu'il n'y paraît à priori )

    Ben je crois que j'ai cassé chatGPT... Je lui prompte:

    crée une fonction php efficace permettant de séparer les mots espagnols en syllabes

    Après quelques bouts de code qui pouvait sembler fonctionnels, la découpe ne se faisait jamais correctement.

    Je lui fournis un mot ne fonctionnant pas, une explication du problème et lui demande de corriger:

    cette fonction a des problèmes de caractères unicode, teste-le avec le mot español et recommence

    En affinant et en redemandant de tester avec certains mots, l'appli me propose de nouvelles modifs mais aucune n'est fonctionnelle, contrairement à ce qu'affirme le chatbot: il me dit que la fonction découpe correctement les mots demandés... Donc soit elle ment soit elle ne teste pas le code (LOL)

    Je lui demande donc de recommencer et c'est là qu'on rigole:

    ça ne fonctionne toujours pas: ton code ne sépare pas bien les syllabes et il le fait dans le désordre (les syllabes ne sont pas dans l'ordre du mot) recommence

    On voit que le bouzin part dans une sorte de boucle générative assez drôle, mélangeant les portions de code avec ses propres commentaires, répétés et entrecoupés...

    function syllabifier($word) {
      $syllable_patterns = array(
        '/(qui|gue|gui|[aeiouáéíóúü])[aeiouáéíóúü]*|[bcdfghjklmnpqrstvwxyzñ]+/i',
        '/(que|qe|qui|qüe)[aeiouáéíóúü]*/i',
        '/(gui|güi)[aeiouáéíóúü]*/i'
      );
    
      $syllables = array();
      preg_match_all('/./u', $word, $matches);
      $characters = $matches[0];
    
      while (!empty($characters)) {
        $matched = false;
        foreach ($syllable_patterns as $pattern) {
          $syllable = '';
          foreach ($characters as $key => $char) {
            $syllable .= $char;
            if (preg_match($pattern, $syllable)) {
              $syllables[] = $syllable;
              $matched = true;
              $charactersJe suis désolé que la fonction ne fonctionne toujours pas pour vous. Je vais essayer de proposer une nouvelle version de la fonction qui prend en compte les cas particuliers de la langue espagnole et qui retourne les syllabes dans l'ordre du mot. Voici la fonction modifiée :
    
    ```php
    function syllabifier($word) {
      $syllable_patterns = array(
        '/(qui|gue|gui|[aeiouáéíóúü])[aeiouáéíóúü]*|[bcdfghjklmnpqrstvwxyzñ]+/i',
        '/(que|qe|qui|qüe)[aeiouáéíóúü]*/i',
        '/(gui|güi)[aeiouáéíóúü]*/i'
      );
    
      $syllables = array();
      preg_match_all('/./u', $word, $matches);
      $characters = $matches[0];
    
      while (!empty($characters)) {
        $matched = false;
        foreach ($syllable_patterns as $pattern) {
          $syllable = '';
          foreach ($characters as $key => $char) {
            $syllable .= $char;
            if (preg_match($pattern, $syllable)) {
              $syllables[] = $syllable;
              $matched = true;
              $charactersJe m'excuse pour cette erreur dans ma réponse précédente. Voici la version corrigée de la fonction :
    
    ```php
    function syllabifier($word) {
      $syllable_patterns = array(
        '/(ll|[aeiouáéíóúü])[aeiouáéíóúü]*|[bcdfghjklmnpqrstvwxyzñ]+/i',
        '/(que|qe|qui|qüe)[aeiouáéíóúü]*/i',
        '/(gui|güi)[aeiouáéíóúü]*/i'
      );
    
      $syllables = array();
      preg_match_all('/./u', $word, $matches);
      $characters = $matches[0];
    
      while (!empty($characters)) {
        $matched = false;
        foreach ($syllable_patterns as $pattern) {
          $syllable = '';
          foreach ($characters as $key => $char) {
            $syllable .= $char;
            if (preg_match($pattern, $syllable)) {
              $syllables[] = $syllable;
              $matched = true;
              $characters = array_slice($characters, $key + 1);
              break;
            }
          }
          if ($matched) {
            break;
          }
        }
        if (!$matched) {
          $syllables[] = $charactersJe m'excuse pour cette erreur dans ma réponse précédente. Voici la version corrigée de la fonction :
    
    ```php
    function syllabifier($word) {
      $syllable_patterns = array(
        '/(ll|[aeiouáéíóúü])[aeiouáéíóúü]*|[bcdfghjklmnpqrstvwxyzñ]+/i',
        '/(que|qe|qui|qüe)[aeiouáéíóúü]*/i',
        '/(gui|güi)[aeiouáéíóúü]*/i'
      );
    
      $syllables = array();
      preg_match_all('/./u', $word, $matches);
      $characters = $matches[0];
    
      while (!empty($characters)) {
        $matched = false;
        foreach ($syllable_patterns as $pattern) {
          $syllable = '';
          foreach ($characters as $key => $char) {
            $syllable .= $char;
            if (preg_match($pattern, $syllable)) {
              $syllables[] = $syllable;
              $matched = true;
              $characters = array_slice($characters, $key + 1);
              break;
            }
          }
          if ($matched) {
            break;
          }
        }
        if (!$matched) {
          $syllables[] = $charactersJe suis désolé pour cette confusion. Voici une nouvelle version de la fonction qui devrait fonctionner correctement pour le mot "español" et qui retourne les syllabes dans l'ordre du mot :
    
    ```php
    function syllabifier($word) {
      $syllable_patterns = array(
        '/(que|qui|gue|gui|güe|güi|[aeiouáéíóúü])[aeiouáéíóúü]*|[bcdfghjklmnpqrstvwxyzñ]+/i',
        '/(que|qe|qui|qüe)[aeiouáééóúí]+/i',
        '/(gui|güi)[aeiouáéíóúü]+/i'
      );
    
      $syllables = array();
      preg_match_all('/./u', $word, $matches);
      $characters = $matches[0];
    
      while (!empty($characters)) {
        $matched = false;
        foreach ($syllable_patterns as $pattern) {
          $syllable = '';
          foreach ($characters as $key => $char) {
            $
    Vous voulez en finir rapidement   avec les «IA» ?!
    Laissez-les se reprogrammer   toutes seules...  Y'en a pour une grosse matinée.
    Fil RSS des articles