Linux (fr)

  • Tour d'horizon des éditeurs de texte pour le terminal (Journaux LinuxFR)

    Sommaire

    Le nombre d'éditeurs de texte disponible sur nos systèmes d'exploitation est très important, même en se limitant à ceux s'exécutant dans un terminal.

    La sélection suivante est donc forcement partielle. Dans la suite je parlerais des principaux éditeurs, de leurs clones, des anciens moins connu et enfin des plus récents.

    La famille vi

    La particularité de cette famille est d'être modale, les touches ont une action différente selon le mode dans lequel on est. De plus vi est dans la norme POSIX, donc tous les OS de type POSIX embarque un clone de vi.

    Voir l'histoire de vi : wikipedia - Vi History

    elvis

    Elvis est un des premiers clone de vi (avec Stevie)

    debian: tracker.debian.org/pkg/elvis

    nvi

    Nvi est une réécriture du vi des BSD 4.4 à partir du code d'Elvis.

    debian: tracker.debian.org/pkg/nvi

    vim

    Vim est certainement le clone de vi le plus utilisé aujourd'hui. Il est disponible sur de nombreuses plateformes et une vie entière ne suffit pas a faire le tour de ses fonctions.

    debian: tracker.debian.org/pkg/vim

    neovim

    Neovim est un fork de vim.

    Voir la dépêche sur le sujet, neovim une refonte de vim pour le 21e siecle

    debian:

    kakoune

    Éditeur qui s'inspire de vim mais a sa propre philosophie (voir le
    répertoire doc/)

    debian:

    La famille emacs

    M-x editeur

    wikipedia - Liste des implémentations d'Emacs

    emacs

    On ne le présente plus, le plus difficile étant de trouver quelque chose qu'on ne peut pas faire dans emacs.

    debian: tracker.debian.org/pkg/emacs24

    note: se lance en ligne de commande avec l'option -nw pour
    --no-window-system

    uemacs

    Version légère et portable d'emacs.

    Linus Torvalds maintient une ancienne version de uemacs et l'a fait
    depuis évoluer.

    mg

    Version très portable de uemacs nommé initialement Micro GNU/emacs.

    debian: tracker.debian.org/pkg/mg

    zile

    zile est une implémentation d'emacs plus limité et plus légère.

    debian: tracker.debian.org/pkg/zile

    La famille à menu

    Les éditeurs de cette famille ont comme point commun, d'être plus
    abordable pour le novice en fournissant un menu permettant l'auto-découverte.

    nano

    Nano est la version GNU de Pico (Pine Composer), l'éditeur de texte du client mail Pine.

    debian: tracker.debian.org/pkg/nano

    Note: Pico est aussi disponible dans Debian,
    packages.debian.org/jessie/alpine-pico

    Jed

    Jed associe les fonctionnalités d'un éditeur très extensible pour développeur à une interface facile basé sur un menu.

    • url: www.jedsoft.org/jed
    • filiation:
    • wikipedia: wikipedia - JED

    • code source: git://git.jedsoft.org/git/jed.git

    • début du développement: 2006 ?

    • langage : C + S-Lang

    • utf-8: ok

    debian: tracker.debian.org/pkg/jed

    ne

    ne, le nice editor semble être un bon compromis entre richesse des
    fonctions et simplicité. Cet éditeur possède un jeu de fonctions
    (commandes) qui peuvent être lié a une séquence de touche ou à une
    entrée de menu.

    debian: tracker.debian.org/pkg/ne

    mcedit

    mc (mindnight commander) propose un éditeur très complet, mcedit.

    debian: tracker.debian.org/pkg/mc

    kaa

    Encore un éditeur avec un menu, celui-ci extensible en Python.

    debian:

    Les autres

    Des éditeurs qui ne rentrent pas dans les précédentes catégories ou qui peuvent les imiter toutes.

    Joe

    Un des plus ancien challenger.

    debian: tracker.debian.org/pkg/joe

    Fork www.mirbsd.org/jupp.htm

    Diakonos

    L'objectif principal de Diakonos est de proposer un éditeur en console avec les raccourcis clavier classique d'une application graphique tel un navigateur ou un traitement de texte.

    debian: tracker.debian.org/pkg/diakonos

    Yi

    Yi est un éditeur de texte écrit et extensible en Haskell.

    debian: tracker.debian.org/pkg/yi

    Textadept

    Textadept est un éditeur graphique qui propose aussi une interface
    curse. Celui-ci est extensible en Lua. L'auteur utilisant le composant Scintilla pour la version graphique, celui-ci a développé une version pour curse scinterm

    Spacemacs

    Spacemacs n'est pas un éditeur, mais une (énorme) configuration pour
    emacs. Leur baseline "The best editor is neither Emacs nor Vim, it's
    Emacs and Vim!" et leur originalité un <leader> configuré sur espace qui ouvre un Menu permettant de découvrir les fonctions disponibles.

    Conclusion ?

    Pas de conclusion, si vous voulez en découvrir encore d'autre, voici deux listes :

    Mais attention de ne pas vous perdre par ici texteditors.org !

    Lire les commentaires

  • Inventaire de matos (Journaux LinuxFR)

    Bonjour

    Je suppose que je suis mauvais pour trouver des logiciels qui correspondent à mon besoin. Il y a quelques semaines j’avais besoin de retranscrire une interview, je ne trouvais pas de logiciel pour le faire sur le coup, or il existe le site otranscribe ou le logiciel Parlatype, j’ai découvert ces deux possibilités quelques jours après avoir galéré avec mpv et gedit…

    Je travaille dans une UMR (un institut de recherche) et j’avais besoin d’inventorier notre matériel (lasers, photodiode, filtre, analyseur, lunettes de protection,…). Je ne trouvais rien qui réponde vraiment à mon besoin. J’ai fini par commettre INVENTAIRE.

    Mon besoin est le suivant :
    - outil en ligne pour être accessible depuis n’importe quel poste (intranet, pour l’instant, tout le monde à tous les droits)
    - associer directement différents documents (data-sheet, caractérisation,…)
    - gérer les différents entretiens (nettoyage, calibration,…) avec des icônes en fonction du temps restant
    - un journal disponible pour chaque composant listé (pour suivre les aventures de laser22 et la fabuleuse calibration d’analyseur_de_spectre12)
    - plusieurs inventaires peuvent être créés (plusieurs équipes ou domaines par exemple…)
    - des sections « administratif » et « technique » clairement différenciées pour permettre de remplir uniquement une partie si on le souhaite.
    - Si on affiche une seule catégorie, il est possible de trier en fonction des caractéristiques spécifiques à celle-ci

    Ça donne un listing :
    listing

    Une page réussissant toutes les infos pour chaque composant :
    detail

    D’autres captures d’écran sur https://github.com/yeKcim/inventaire/

    Je ne suis pas développeur, le code (php, mysql) est donc très certainement crade, mais je me dis que cela peut
    - soit rendre service à quelqu’un d’autre et avoir des avis
    - soit avoir un commentaire m’expliquant que je viens d’inventer la roue octogonale alors que la roue circulaire existe depuis longtemps.

    Lire les commentaires

  • L’écriture neutre (Journaux LinuxFR)

    Les problèmes de l’écriture dite « inclusive »

    C’est laide

    Très.

    Cela n’inclut pas toute la monde

    Très bien, ça donne de la visibilité aux femmes. Dans quelques années toutes les « non-binaires » et autres « agenres » risquent de venir râler parce qu’elles se sentent exclues, et on va se retrouver à faire comme les gens sur tumblr avec des pronoms idiotes telles que « xir, fær, … », qu’il faudra réussir à intégrer dans l’écriture « inclusive ».

    L’accessibilité

    C’est très complexe à lire et à écrire (par exemple, sous Windows, à part en installant manuellement la disposition bépo ou quelque chose de similaire, on ne peut pas faire la caractère « · »)

    Ça ne résout aucune problème à l’oral (comment prononcer « agriculteur·ice·s » ?)

    La point (.) possède déjà une sens (la fin d’une phrase), lui en ajouter une nouvelle est donc plutôt gênante.

    L’écriture neutre

    J’ai donc décidé de vous proposer la réforme suivante, que j’appelle « écriture neutre ».

    Les règles sont simples : les genres disparaissent.

    Je pars de la constat suivante : la genre n’a quasiment jamais d’intérêt:

    • pour toutes les objets inanimées, ça ne sert strictement à rien (quelle est l’intérêt de savoir qu’on dit « une chaise » mais « un tabouret » ?)
    • il est inutile de préciser la sexe d’une personne dans 99% des phrases que l’on faite.

    Il est donc possible de n’utiliser qu’une seule « genre », que l’on appellera « neutre ». Cette genre est extrêmement simple à apprendre puisqu’elle est composée exactement comme la genre féminine dans l’écriture « traditionnelle ».
    Ainsi, comme vous avez pu la remarquer jusqu’à maintenant en lisant cette journal, on ne dira plus « Je lis mon gros journal en regardant la télé en attendant que l’avocat m’appelle » mais « Je lis ma grosse journal en regardant la télé en attendant que l’avocate m’appelle ». Les mots comme « un », « le », « mon », « il » disparaissent complètement.

    Dans l’exemple précédente, il est à noter qu’on n’a aucune idée de la sexe (ou la genre) de la dite avocate. Cela peut très bien être une femme ou une homme, mais de toute façon on s’en fiche.

    Si vraiment on a besoin de signaler la sexe de quelqu’une, il suffit alors de la préciser à l’aide d’autres mots par exemple « la personne de sexe féminine », ou « la singe mâle est en colère » voire même « cette homme est grande ».

    Quelques notes supplémentaires

    La mot « monsieur » disparait : lorsqu’on salue une personne, elle est inutile de signaler sa sexe présumée (c’est encore une fois inutile, et de plus certaines personnes peuvent se vexer si l’on se trompe, ce qui peut créer de nombreuses problèmes). On utilisera donc uniquement « madame ». « Monsieur et Madame Dupond » deviendra donc « Mesdames Dupond ».

    Cette règles à de très nombreuses avantages :

    • Malgré une petite période d’adaptation, ça devrait être assez simple à apprendre. C’est simplement une réflexe à acquérir, et non pas une toute nouvelle orthographe.
    • toutes les personnes sont, cette fois, incluses (vu qu’elle n’est aucunement question de genre ou de sexe, même les non-binaires seront ravies)
    • ça passe très bien à l’oral
    • pas besoin de trouver une nouvelle caractère sur nos claviers, et toutes les lecteurs pour aveugles et autres s’en sortiront très bien
    • ça facilite grandement l’apprentissage de la langue pour les étrangers. À l’instar de l’anglais, plus besoin d’apprendre les genres de chaque mots (et Jane Birkin n’aura plus d’excuse pour faire semblant d’inverser la genre des mots alors qu’elle pratique la français depuis des dizaines d’années)

    Vous vous demandez sûrement pourquoi j’ai choisi de baser cette genre neutre sur la genre féminine (de l’écriture traditionnelle) : tout simplement pour éviter toutes les remarques des pseudo-féministes qui vont venir râler parce que « si on ne garde que le masculin, c’est encore pire » ou « ça invisibilise les femmes, olala ». Personnellement, je trouve que se baser sur la genre masculine aurait été plus simple, vu qu’elle faisait déjà office de neutre dans l’écriture « traditionnelle ». Ceci étant dit, je ne suis absolument pas fixée, et on peut très bien choisir l’une ou l’autre, les deux me conviennent.

    Lire les commentaires

  • Pâtes à l'huile d'olive ou au beurre ? (Journaux LinuxFR)

    En cette merveilleuse journée de mai, une question me traverse l'esprit. Est-ce que le lectorat de linuxfr préfère les pâtes à l'huile d'olive ou au beurre ?

    En effet, il semblerait que certaines personnes préfèrent les pâtes au beurre, ce qui est choquant, et j'aimerais savoir si ces personnes sont nombreuses.

    Évidemment, quand je parle d'huile d'olive, il s'agit de véritable huile d'olive, et pas quelque chose de coupé acheté en promotion dans une grande surface.

    Ce journal est à mettre en rapport avec le journal demandant si il fallait mettre de l'huile dans l'eau des pâtes. (La réponse est négative).

    Et pour finir, une nimage en rapport.

    Lire les commentaires

  • La voiture en open source (Dépêches LinuxFR)

    « Vous ne téléchargeriez pas une voiture… » disait la vidéo. Eh bien, justement, si !

    Télécharger une voiture ?
    Cette image (du centre) est tirée de la vidéo bien connue insérée dans de nombreux DVD et Blu‐ray, dans laquelle l’annonceur ose comparer le matériel et l’immatériel : on soustrait un bien matériel (don, échange, vente ou vol), là où l’on multiplie un bien immatériel (copies à loisir). Ce débat est bien évidemment volontairement faussé et donc caduque.

    OSVehicle
    OSvehicle est justement une tentative de voiture libre et open source. Vous pouvez enfin télécharger une voiture, et ce n’est pas voler (c’est rouler d’ailleurs).

    L’idée n’est pas seulement de produire un design modifiable, modulaire et DIY (« Do It Yourself »), ou de produire localement, et de manière indépendante. L’idée est également d’innover, de s’adresser aux marchés de niche, de réduire l’impact écologique et, bien évidemment, de partager les savoirs et les passions.

    Une des motivations clefs du véhicule open source est aussi de reprendre le contrôle sur la réparabilité et la bidouillabilité à l’heure de l’obsolescence programmée, sur le véhicule connecté, et de produire de manière équitable (fair trade). Bien évidemment, ce projet est à très haut potentiel.

    Le véhicule open source est donc une plate‐forme ouverte, incluant le châssis, le moteur et la partie électronique.

    Appel à contribution sur la section « Do It Yourself » 

    Le bricolage ou bidouillage est central dans le libre, et pas seulement au niveau code. Quelques dépêches ont couvert ce sujet par le passé :

    NdM : Une dépêche sur InMoov, un robot avec plans sous licence libre à imprimer en 3D (voir vidéo) serait la bienvenue.

    Lire les commentaires

  • Mozilla nous dit que le closed-source est plus bankable (Journaux LinuxFR)

    Petit journal bookmark et billet d'humeur

    Mais pourquoi ne suis-je pas étonné… Voila, après avoir bien mis en avant Pocket (pas libre du tout), voila que Mozilla le rachète. Oui, ils achètent du closed-source, alors certes ils disent qu'ils vont le mettre en open-source mais voila la morale pour les gens qui débutent un projet : à service identique, vaut mieux que vous fassiez du closed-source, c'est plus bankable, car le fait de faire de l'open-source (ex: wallabag) vous réduit pour les investisseurs classiques (vous avez moins de choses à vendre car tout le monde peut copier votre code) tout en aillant pas d'avantage par rapport à des investisseurs potentiels liés à l'open-source (avoir les bons contacts semble plus important).

    Amis trolleurs, je recherche de la contre-argumentation pour m’expliquer en quoi c'est positif pour le libre en général, quel message positif ça envoie aux libristes de la part d'une entité qui de toute façon devient de plus en plus inexistante (je serai trolleur je dirai que c'est justement parce qu'elle fait comme Google vis à vis des libristes sans avoir les moyens de Google).

    L'annonce, via NextInpact.

    Lire les commentaires

  • [C++14 ] Expressions template pour les nuls (Journaux LinuxFR)

    Sommaire

    Expression Templates pour les nuls

    Après un contact prolongé avec Joël Falcou, et pas mal de nœuds aux cerveaux pour arriver à émuler le comportement du broadcasting de Numpy avec des expression templates dans Pythran, j'ai eu l'envie soudaine, un peu folle peut-être, de réécrire un moteur d'expressions template en C++14, mais pour faire simple et didactique.

    Mais de quoi zy parle

    Les expressions templates sont une maintenant assez vieille technique de C++ qui permet par exemple d'éviter de créer des objets intermédiaires lourds quand on calcule sur des tableaux en utilisant des expressions complexes.

    Par exemple, pour le type std::vector<double>, si on surcharge naïvement (et de façon fort risquée, pas touche aux conteneurs de la lib standard comme ça) les opérateurs +, * etc avec un code du genre :

    std::vector<double> operator+(std::vector<double> const& left, std::vector<double> const& right) {
        assert(left.size() == right.size() && "same size");
        std::vector<double> out(left.size());
        std::transform(left.begin(), left.end(), right.begin(), out.begin(),
                       std::plus<double>());
        return out;
    }

    et bien l'évaluation d'une expression du genre a + b * c va créer un tableau inutile (le résultat de b * c) et la move semantic ne nous sauve pas totalement. Et on va faire deux boucles, une par opération.

    Avec les expressions template, on va plutôt écrire :

    add<std::vector<double>, std::vector<double>> operator+(std::vector<double> const& left, std::vector<double> const& right) {
        return {left, right};
    }

    Avec :

    template<typename L, typename R>
    struct add {
        L const& left_;
        R const& right_;
        add(L const& left, R const& right) : left-(left), right_(right) {}
        // ...
    };

    Ce qui nous donnera comme type de retour de l'expression a + b * c :

    add<std::vector<double>,
        mul<std::vector<double>,
            std::vector<double>
           >
       >

    En ajoutant un opérateur [] aux types add<...> et mul<...> qui fait suivre l'appel aux fils, et une fonction membre size() qui renvoie, par exemple, la plus petite des tailles des deux fils :

    template<typename L, typename R>
    struct add {
        L const& left_;
        R const& right_;
        add(L const& left, R const& right) : left-(left), right_(right) {}
        auto operator[](size_t i) const { return  left_[i] + right_[i]; }
        auto size() const { return std::min(left_.size(), right_.size(); }
    };

    on peut alors écrire le code bâtard mais néanmoins relativement facile à comprendre :

    auto expr = a + b * c;
    auto n = expr.size();
    std::vector<double> res(n);
    for(size_t i = 0; i < n; ++i)
      res[i] = expr[i];

    Et voilà, on a une unique boucle, pas de tableau intermédiaire, c'est la fête et vive les expressions template. Cette technique est très largement utilisée :

    Mais elle est assez lourde à mettre en œuvre avec les outils pre-C++11. Je vous propose une solution que je croyais innovante, mais après discussion avec mon mentor sus-nommé, elle n'est qu'ingénieuse, ce qui est somme toute déjà pas mal.

    Expressions template à la sauce C++14

    Le parcours de l'arbre d'expression de bas en haut à coup d'appels récursifs, ça rappelle fury le design pattern visitor. C'est d'ailleurs une des options proposées par Boost.Proto, le gros pavé pour ceux qui aiment manger des expressions template avec de la crème le matin.

    Du coup, proposition didactique (pleins de détails et optimisations possibles sont écartés pour la clarté du propos) : on va associer à chaque type de nœud de notre arbre un tag (une structure vide, un type) et une fonction générique dont le but sera de lancer la mécanique de parcours de l'arbre. Exemple :

    struct add_tag {};
    template<class A, class B>
    auto add(A&& a, B&& b) {
      return [=](auto visitor) { return visitor(add_tag{}, a(visitor), b(visitor));};
      }

    Bon ça parait un peu mystérieux comme ça, le gain en clarté n'est pas (clair ?) évident, mais on renvoie juste, quand on fait appel à la fonction add, une fonction générique capable d'appliquer un visitor sur les fils, de bas en haut.

    On peut faire la même chose pour les feuilles de l'arbre, ici en distinguant les références vers des objets complexes et les constantes :

    struct cst_tag {};
    template<class T>
    auto cst(T expr) {
     return [=](auto visitor) { return visitor(cst_tag{}, expr); };
    }
    
    struct ref_tag {};
    template<class T>
    auto ref(T& expr) {
     return [&](auto visitor) { return visitor(ref_tag{}, expr); };
    }

    Ça fait peu ou prou la même chose, mais avec un tag différent.

    Maintenant que la mécanique est en place, on peut code de façon élégante nos visiteurs ! Par exemple pour obtenir le i-ème élément:

    struct evaluator {
      evaluator(size_t i) : i_(i) {}
    
      template<class T>
      auto operator()(lazy::cst_tag, T c) { return c; }
    
      template<class T>
      auto operator()(lazy::ref_tag, T& r) { return r[i_]; }
    
      template<class A, class B>
      auto operator()(lazy::mul_tag, A a, B b) { return a * b; }
    
      template<class A, class B>
      auto operator()(lazy::add_tag, A a, B b) { return a + b; }
    
      private:
      size_t i_;
    };

    On utilise le tag pour spécialiser l'appel et déterminer le nœud à visiter. L'appel se fait simplement par :

    auto expr = add(cst(12), mul(ref(a), ref(b)));
    auto expr_0 = expr(evaluator(0));

    On peut même spécifier un comportement par défaut, en jouant sur l'ordre de résolution des surcharges :

    struct size {
    
      template<class T>
      auto operator()(lazy::cst_tag, T c) { return std::numeric_limits<size_t>::max(); }
    
      template<class T>
      auto operator()(lazy::ref_tag, T& r) { return r.size(); }
    
      template<class T, class A, class B>
      auto operator()(T, A a, B b) { return std::min(a,  b); }
    
    };

    À la différence de la première approche, plus besoin de modifier les types proxy add, mul etc. On peut mettre toute la logique à un endroit, et l'étendre de manière non intrusive. Au final, si on sait vouloir stocker notre expression finale dans un std::vector<...>, on peut même écrire de façon assez élégante :

    template<class E>
    auto eval(E const & expr) {
      size_t n = expr(size());
      std::vector<decltype(expr(evaluator(0)))> res(n);
      for(size_t i = 0; i < n; ++i)
        res[i] = expr(evaluator(i));
      return res;
    }

    qui fait le bonheur des petits et des grands :

    auto expr = add(cst(12), mul(ref(a), ref(b)));
    auto evaluated = eval(expr);

    Performance

    Un petit coup de clang++ -std=c++14 -Ofast -march=native sur un code utilisant l'expression précédente a fait apparaitre cette séquence d'assembleur:

    400ab0:       c4 c1 7a 6f 0c 1e       vmovdqu (%r14,%rbx,1),%xmm1
    400ab6:       c4 c1 7a 6f 54 1e 10    vmovdqu 0x10(%r14,%rbx,1),%xmm2
    400abd:       c4 c1 7a 6f 5c 1e 20    vmovdqu 0x20(%r14,%rbx,1),%xmm3
    400ac4:       c4 c1 7a 6f 64 1e 30    vmovdqu 0x30(%r14,%rbx,1),%xmm4
    400acb:       c4 c2 71 40 0c 1f       vpmulld (%r15,%rbx,1),%xmm1,%xmm1
    400ad1:       c4 c2 69 40 54 1f 10    vpmulld 0x10(%r15,%rbx,1),%xmm2,%xmm2
    400ad8:       c4 c2 61 40 5c 1f 20    vpmulld 0x20(%r15,%rbx,1),%xmm3,%xmm3
    400adf:       c4 c2 59 40 64 1f 30    vpmulld 0x30(%r15,%rbx,1),%xmm4,%xmm4
    400ae6:       c5 f1 fe c8             vpaddd %xmm0,%xmm1,%xmm1
    400aea:       c5 e9 fe d0             vpaddd %xmm0,%xmm2,%xmm2
    400aee:       c5 e1 fe d8             vpaddd %xmm0,%xmm3,%xmm3
    400af2:       c5 d9 fe e0             vpaddd %xmm0,%xmm4,%xmm4
    400af6:       c4 c1 7a 7f 4c 1d 00    vmovdqu %xmm1,0x0(%r13,%rbx,1)
    400afd:       c4 c1 7a 7f 54 1d 10    vmovdqu %xmm2,0x10(%r13,%rbx,1)
    400b04:       c4 c1 7a 7f 5c 1d 20    vmovdqu %xmm3,0x20(%r13,%rbx,1)
    400b0b:       c4 c1 7a 7f 64 1d 30    vmovdqu %xmm4,0x30(%r13,%rbx,1)
    400b12:       48 83 c3 40             add    $0x40,%rbx
    400b16:       48 81 fb 00 03 00 00    cmp    $0x300,%rbx
    400b1d:       75 91                   jne    400ab0 <main+0x70>
    

    Ce qui est franchement cool : le code a été vectorisé, déroulé et il est… vachement propre. On retrouve bien là le principe de costless abstraction si cher au C++. J'♥.

    Répéter, c'est apprendre

    La petite lib que j'ai écrite pour tester ces idées n'ira pas sur le grand ninternet, c'était juste pour le lulz. Et puis après coup, Il m'a pointé vers https://isocpp.org/blog/2016/05/cppcon-2015-expression-templates-past-present-future-joel-falcou qui contient bien plus de contenu que ce maigre article, qui ne sera finalement qu'une petite introduction et qui aura eu l'avantage de me forcer de coucher sur le clavier (avant d'aller moi-même me coucher) mes idées. Et n'est-ce pas ça, le but d'un journal ?

    Lire les commentaires

  • Tutoriel : Comment utiliser la forge GitLab du labo pour gérer un projet ? (Laboratoire Linux SUPINFO)

    Initialiser un nouveau projet :

    1. Créer un compte sur la forge : http://code.labo-linux.org/users/sign_up
    2. Se connecter : http://code.labo-linux.org/users/sign_in
    3. Ajouter votre clé SSH : http://code.labo-linux.org/profile/keys
    4. Créer un nouveau projet : http://code.labo-linux.org/projects/new
    5. Suivre les instructions de lignes de commande GIT à exécuter pour initialiser le dépôt

    Le dossier ainsi créé va suivre les modification de tous vos fichiers. Vous devez maintenant apprendre à utiliser GIT en suivant dans l'ordre cette série de tutoriels : https://www.atlassian.com/fr/git/tutorial

    Si la ligne de commande vous rebute, il y a un client multiplateforme extrèmement complet : http://www.syntevo.com/smartgit/download (veillez à prendre la licence complète gratuite à usage non commercial).

    Pour que le versionnage soit utile, il faut Commit/Push à chaque fois que quelque chose est complété (comme un bug, une fonctionnalité, etc). Cela évite d'avoir des régressions et de pouvoir faire machine arrière le cas échéant.


    Découper son projet en toutes petites étapes :

    Cela permet d'y voir plus clair et de savoir par où commencer. Vous augmenterez votre motivation en évitant la paralysie de la feuille blanche.

    1. Se rendre sur l'interface Issues de votre projet (les liens sont à adapter) : http://code.labo-linux.org/root/demo/issues
    2. Cliquer sur New issue
    3. Décrire une tâche de l'ordre de « faire un hello world avec le framework X », « gérer le login/logout », « envoyer un email sur telle action », « créer une page de statistiques » ...
    4. Optionnellement, vous pouvez rattacher ces issues à des milestones (c'est un jalon, une version)


    Autres fonctionnalités utiles :

    1. Dans les champs texte, GitLab gère des symbols actifs comme le "@" (vous suggèrera les pseudos des membres) et le "#" (vous suggèrera vos issues).
    2. Préciser le numéro d'une issue dans un message de commit créé un référencement du commit dans l'issue. Exemple : le message de commit "Hello World #1" fera apparaitre un nouveau commentaire "mentionned in commit xxxxxx" dans l'issue n°1.
    3. Vous pouvez fermer automatiquement des issues dans vos messages de commit ! À découvrir en lisant ceci : https://about.gitlab.com/2013/09/22/gitlab-community-edition-6-dot-1-released/


    Git est un outil extrèmement puissant que vous découvrirez au fur et à mesure de vos besoins. Travailler en équipe requiers une réelle organisation en dehors de l'outil : répartition de tâches, tests préalables avant toute mise en commun pour limiter l'instabilité du logiciel, découpage en jalons, etc.

    Vous trouverez des réflexions sur les « workflows » (manière de s'organiser) sur cette page : https://www.atlassian.com/fr/git/workflows


    Gestion de projet plus globale

    La gestion d'issues proposée par GitLab ne peut pas se soustraire à une gestion d'équipe plus globale. Les Méthodes Agiles que vous découvrirez pendant votre cursus proposent de grands concepts qui évitent à de votre groupe de s'enrayer :

    1. Une réunion de départ qui dégage les jalons du projet, c'est à dire un premier découpage de ses grandes étapes qui n'entre pas dans le détail mais permet de fixer des échelles de temps
    2. Une revue hebdomadaire obligatoire, qui permet de définir à l'avance un objectif court terme pour l'équipe
    3. Un point journalier rapide, même s'il ne s'est rien passé, où chaque membre de l'équipe doit avouer ses difficultés et exprimer ce qui a été fait. Cela permet d'identifier au plus tôt qui a besoin d'aide.
    4. Une revue de projet (et une seule) toutes les deux semaines / un mois pour statuer sur l'avancée du jalon en cours ainsi que sur la prévision du prochain.

    Cette structuration de l'équipe par des cérémonies ponctuelles dans le temps neutralise l'effet « sous-marin » et permet à chaque membre de l'équipe de savoir où se situent les autres.

    L'objectif n°1 de ces méthodes est de faire passer le client et la qualité du logiciel avant toute chose. En itérant régulièrement, votre travail évoluera sur des bases saines car validerez au fur et à mesure qu'il correspond toujours aux attentes du client. La gestion des bugs devient ainsi prioritaire sur les fonctionnalités, si cela est pertinent. Ce fonctionnement est en totale opposition aux cahiers des charges dont le but est de figer un processus jusqu'à son aboutissement.

    Les Méthodes Agiles sont un genre de framework qui délimite bien d'autres routines d'équipe qui ne sont pas toujours adaptées à la situation : à vous de prendre ce qui vous plait ! C'est l'essence même de ces méthodes.

  • Écrire des diagrammes de séquences (Dépêches LinuxFR)

    Les diagrammes de séquences sont très utiles pour représenter le déroulement d’événements au fil du temps. Ils sont par exemple très utilisés pour décrire des protocoles de communication, où les paquets d’information se croisent, se perdent, passent du temps dans les tuyaux.

    Dans la seconde partie de la dépêche, après avoir expliqué leur principe de ces diagrammes, quelques logiciels existants seront listés et un nouveau venu sera présenté.

    Les diagrammes de séquences sont très utiles pour représenter le déroulement d’événements au fil du temps. Ils sont par exemple très utilisés pour décrire des protocoles de communication, où les paquets d’information se croisent, se perdent, passent du temps dans les tuyaux.

    Ces diagrammes comportent :

    • des acteurs, avec leur ligne de vie (un acteur peut représenter une personne, une machine, un processus, un fil d’exécution…). La spécification UML utilise le terme de « participant » ;
    • des messages échangés entre acteurs.

    On fait ces dessins au tableau, puis on les efface, mais parfois on voudrait les inclure dans une page d’un document, ou les envoyer par courriel.

    Logiciels existants

    Des outils logiciels existent, pour générer de tels diagrammes :

    • éditeur de texte (ASCII art) ;
    • Mscgen (http://www.mcternan.me.uk/mscgen) ;
    • éditeurs dits UML ;
    • éditeurs SDL (Specification and Description Language) ;
    • éditeurs de diagrammes : Dia, LibreOffice, Microsoft Visio, etc. ;
    • outils d’ingénierie système (Capella…).

    Mais pour le moment, je ne suis pas satisfait de ceux que j’ai utilisés. Je voudrais les possibilités suivantes :

    • créer un acteur ou le détruire au cours du temps ;
    • croiser les échanges de messages ;
    • perdre un message ;
    • indiquer l’expiration d’un temps imparti (timeout) ;
    • faire une mise en page du dessin sans dessiner (j’entends par là que je ne veux pas passer trop de temps à déplacer à la souris les éléments pour les aligner ou les relier, et puis tout décaler un par un parce que j’ai inséré un nouvel acteur en plein milieu…) ;
    • avoir un logiciel libre et gratuit.

    Si quelqu’un connaît un tel logiciel, je suis preneur.

    Et alors ?

    En attendant, j’ai fait un prototype d’un tel logiciel, que j’appelle pour le moment meseq sur le principe de mscgen :

    • on écrit un fichier texte décrivant le scénario ;
    • meseq génère une image PNG à partir de ce fichier.

    L’avantage de cette approche est la simplicité et la rapidité de développement de l’outil, mais l’inconvénient est que c’est moins ergonomique qu’un éditeur avec rendu WYSIWYG.

    J’ai mis au point une syntaxe rudimentaire pour le fichier d’entrée. Je sais déjà que je vais la modifier pour la rendre plus évolutive.
    Voici un exemple pour illustrer cette syntaxe (fichier .msq) :

    [init]
    actors w3client proxy "" w3server
    
    [scenario]
    
    w3client   ->   proxy   CONNECT
    w3client   <-   proxy   OK
    w3client   ->   proxy   bytes
    proxy      ->   w3server bytes
    :
    w3client  <->   w3server "TLS Handshake\nwhat follows is ciphered"
    :
    :
    w3client   ->    proxy   "GET /index.html"
    proxy      ->   w3server "GET /index.html"
    proxy      <-   w3server "200, index.html"
    w3client   <-    proxy   "200, index.html"
    

    Et voici l’image générée par meseq (plus complète que l’exemple ci‐dessus) :

    example_web.msq.png

    Autre exemple, avec flèches qui se croisent, etc. :

    example_piggyback.msq.png

    Show me the prototype

    Ce prototype est là pour étudier la faisabilité, présenter mes idées et expérimenter.
    Bon, il est codé vite et mal : non documenté, bogué, mal structuré… Bref, un vrai code de goret.

    Ce prototype et les exemples sont sur Github : https://github.com/goeb/meseq.

    On utilise les bibliothèques Cairo et Pango pour dessiner, écrire le texte, puis générer l’image. Elles sont relativement simples à utiliser.

    Il existe d’autres bibliothèques pour dessiner, que je n’ai pas étudiées (et je ne suis pas sûr qu’il existe un moyen simple de les utiliser en Python) :

    • libgd, utilisée par mscgen ;
    • les bibliothèques sous‐jacentes de Graphviz (dont le rendu est agréable).

    Pour la suite

    Les améliorations à faire sont :

    • améliorer le rendu (diagramme plus compact verticalement, réduire les conflits de textes qui se superposent…) ;
    • ajouter des visuels (bloc de commentaire, couleurs…) ;
    • augmenter la qualité de code ;
    • choisir une licence libre.

    Par la suite, je porterai peut‐être ce programme en C ou C++, afin qu’il soit plus facile d’accès pour les personnes ne disposant pas de Python sur leur poste (je pense aux personnes lambda sur système d’exploitation Windows).

    Afin d’orienter les choix qui restent à faire, je serais intéressé par les avis éclairés des lecteurs de LinuxFr.org :

    • utilisez‐vous les diagrammes de séquences ?
    • quels éléments visuels trouvez‐vous indispensables, et pour représenter quoi ?
    • faut‐il rester en Python ou passer en C ou C++ ?

    N. D. M. : voici une liste des liens apparus dans les commentaires du journal :

    Lire les commentaires

  • La gestion de l'authentification sous Linux avec PAM (Laboratoire Linux SUPINFO)

    La gestion de l'authentification sous Linux avec PAM

     

    Note: ce document est le second d'un cycle de trois articles sur l'authentification sur les systèmes Linux. Le premier se trouvant ici et le troisième .

    Il est possible de personnaliser finement tous les aspects de l'authentification des utilisateurs Linux et ce pour chaque application du système.

     

    Linux-PAM

    En effet, il a été choisi de centraliser le mécanisme d'authentification système sous Linux pour plusieurs raisons :

    • afin d'éviter de réimplémenter les mêmes schémas d'authentification dans tous les logiciels.
    • ne pas avoir à recompiler toutes les applications lors du changement des méthodes d'authentification.
    • permettre à l'administrateur de choisir quel mécanisme d'authentification chaque application utilise.

    Ces raisons ont conduit à la naissance de Linux-PAM (pour Pluggable Authentication Modules, soit en français Modules d'Authentification Enfichables).

    Avant PAM, pour pouvoir authentifier un utilisateur, une application faisait appel aux bibliothèques du système (via getpwnam() par exemple) qui la plupart du temps (à moins que NSS ne lui dise d'utiliser une autre source ailleurs) regardaient dans les fichiers /etc/passwd et /etc/shadow pour vérifier l'existence de l'utilisateur et la validité de son mot de passe. Cette technique fonctionnait mais n'était pas très souple pour les raisons évoquées précédemment.

    Dorénavant, une application compatible PAM délègue cette tâche à Linux-PAM (via un appel à la PAM-API), et celui-ci, suivant les directives inscrites dans ses fichiers de configuration, autorise ou non l'authentification.

    Mais PAM ne s'occupe pas seulement de la vérification du mot de passe. Il offre un total de six primitives d'authentification grâce à des modules fournissant certaines fonctions. Ces primitives sont regroupés dans les quatre catégories que voici :

    account
    • Gère la disponibilité du compte. Cette disponibilité regroupe l'accès au serveur sur lequel est stocké le compte, mais aussi si l'utilisateur est autorisé à utiliser ce compte à ce moment donné et par ce moyen. Par exemple on pourra spécifier qu'il n'est autorisé à se connecter qu'entre 8h30 et 17h00 et seulement en console.
    auth
    • Premièrement, c'est dans cette catégorie que l'on vérifie le moyen d'authentification (le mot de passe, le jeton, etc).
    • Ensuite c'est ici que l'on affecte les credentials de l'utilisateur, c'est à dire ses privilèges et les groupes auxquels il appartient.
    password
    • Les modules classés dans cette catégorie permettent simplement de mettre à jour le jeton d'authentification de l'utilisateur. Cela peut être parce que ce jeton à expiré, ou, si c'est un mot de passe, parce que l'utilisateur veut le modifier.
    session
    • Mise en place de la session
    • Fermeture de la session
    Pour ces deux aspects, cela prend en compte l'écriture dans les journaux système, l'affichage d'un message personnalisé, l'assignation des variables d'environnement, ou bien encore le montage/démontage de certains lecteurs.

     

    Les fichiers de configuration

    La configuration de PAM peut se faire de deux façon différentes. Soit dans un fichier unique nommé /etc/pam.conf ou soit dans une série de fichiers situés dans le répertoire /etc/pam.d. À noter que la présence de ce répertoire fait que PAM ignorera le fichier pam.conf.
    La façon la plus claire de faire et aussi la plus répandue est l'utilisation du dossier pam.d et c'est cette méthode que je vais détailler ici.

    Chaque fichier du répertoire pam.d gère la configuration du service homonyme. Par exemple le fichier /etc/pam.d/sudo configure l'authentification faite par l'intermédiaire de l'outil sudo.
    Il y a cependant une exception à cela. Le fichier /etc/pam.d/other contient la configuration pour les services n'ayant pas leur propre fichier.

    Ensuite, ces fichiers sont tous organisés suivant le même schéma. Ils sont composés d'une suite d'instructions qui constituent ce que l'on nomme une pile. Chaque instruction est inscrite sur une ligne et chaque ligne est organisée comme ci-dessous :

    catégorie contrôle chemin-du-module arguments-du-module

    Ces lignes sont donc empilées les unes au-dessus des autres pour combiner les actions des modules qui les composes. On pourra par exemple avoir une ligne ayant un module d'authentification vers un serveur LDAP, suivi d'une autre avec un module d'authentification vers un serveur Kerberos pour enchaîner ces deux méthodes.

    Dans l'instruction d'exemple ci-dessus, la catégorie est choisie parmi celles décrites dans la section précédente (account, auth, password ou session).

    Le contrôle est le comportement que la PAM-API doit adopter lorsque le module échoue à sa tâche. Il peut soit prendre la forme d'un simple mot clé, ou soit une forme plus compliquée composée d'une suite de valeur=action entourées de crochets.

    Voici les valeurs que peut prendre ce contrôle lorsque c'est un simple mot clé :

    required Si un module required échoue, un statut d'erreur sera retourné par la PAM-API, mais seulement après avoir exécuté les autres instructions du fichier ayant la même catégorie.
    requisite Comme pour required un statut d'erreur est retourné si un module requisite échoue, mais cependant la main est directement redonné à l'application appelante sans exécuter les modules suivants de la pile. Le statut d'erreur retourné est celui du premier module required ou requisite à échouer.
    sufficient Si aucun module précédent n'a échoué et l'exécution de ce module est un succès, les autres instructions de la pile ne sont pas exécutés et la main est redonnée à l'application en lui signalant la validation de l'authentification.
    Si le module échoue, son statut de retour est ignoré et le reste des instructions de la pile est exécuté.
    optionnal Le succès ou l'échec d'un tel module n'est important que s'il est le seul module de la pile de cette catégorie, sinon son statut de retour est ignoré.

     

    Quant à la syntaxe complexe du contrôle, elle a la forme suivante :

    [valeur1=action1 valeur2=action2 ...]

    valeurN correspond au code de retour de la fonction invoquée dans le module. Ce code de retour dépend des modules et est l'un des suivants (pour connaître ceux que peut renvoyer un module, se reporter à la page de manuel de celui-ci) :

    success Succès de l'établissement de la session.
    open_err Le module ne peut pas être ouvert (par exemple il peut ne pas être trouvé).
    symbol_err Un objet nécessaire au module (par exemple un fichier) est introuvable.
    service_err Une erreur interne au module est survenue.
    system_err Une erreur système est survenue (par exemple si l'appel à la PAM-API n'est pas formaté correctement).
    buf_err Une erreur mémoire est survenue.
    perm_denied Une permission d'accès à été refusée à l'utilisateur.
    auth_err L'authentification à échouée. Cette erreur arrive généralement car le jeton (ou mot de passe) est invalide.
    cred_insufficient Pour une raison quelconque l'application n'a pas les privilèges nécessaires pour authentifier l'utilisateur.
    authinfo_unavail Les informations d'authentification sont inaccessibles. Par exemple si ces informations sont sur un serveur LDAP et qu'il y a une coupure réseau, ce statut sera retourné.
    user_unknown L'utilisateur est inconnu.
    maxtries Le nombre maximal d'essais pour l'authentification à été atteint.
    new_authtok_reqd Le compte utilisateur est valide mais le jeton à expiré. L'action généralement faite par l'application suite à ce statut est de demander à l'utilisateur de changer son jeton.
    acct_expired Le compte utilisateur à expiré.
    session_err L'établissement de la session à échouée.
    cred_unavail Impossible de retrouver les credentials de l'utilisateur.
    Les « credentials » sont tout ce qui identifie de manière unique l'utilisateur, comme par exemple son numéro identifiant, les groupes auquel il appartient, etc.
    cred_expired Les credentials de l'utilisateur ont expirés.
    cred_err Impossible d'assigner ses credentials à l'utilisateur.
    no_module_data Des données spécifiques au module n'ont pas été trouvées.
    conv_err Erreur de conversation.
    authtok_err Le module n'a pas été capable d'obtenir un nouveau jeton d'authentification (par exemple lors du changement de celui-ci).
    authtok_recover_err Le module n'a pas été capable de retrouver l'ancien jeton.
    authtok_lock_busy Le module n'a pas été capable de changer le jeton d'authentification car celui-ci était verrouillé.
    authtok_disable_aging Le vieillissement du jeton (en vue de son expiration) à été désactivé.
    try_again Les tests préalables au changement du jeton d'authentification ont échoués, réessayer plus tard. Ces tests peuvent être par exemple le bon accès au serveur Kerberos si le jeton est un ticket Kerberos.
    ignore Ignorer le résultat de ce module. Il ne participera donc pas au code de retour de la pile de modules.
    abort Erreur critique, sortie du module immédiate.
    authtok_expired Le jeton d'authentification a expiré.
    module_unknown Le module est inconnu.
    bad_item L'application a essayée de définir ou d'accéder à un objet non disponible (un fichier par exemple).
    conv_again  
    incomplete  
    default Toute valeur précédemment listée non mentionnée explicitement.

     

    Quant à actionN il peut prendre une des formes suivantes :

    ignore Lorsqu'utilisé sur une pile de modules (donc que ce n'est pas le seul module de cette catégorie), le statut de retour de ce module ne participera pas au choix du code de retour envoyé à l'application.
    bad Cette action indique que le code de retour doit être considéré comme indicatif si le module échoue. Si ce module est le premier de la liste à échouer, sa valeur sera utilisée comme valeur de retour après l'exécution des autres instructions.
    die Équivalent à bad avec comme effet de quitter immédiatement la pile de modules (sans exécuter les modules suivants) et redonner la main à l'application.
    ok Cette action dit à PAM que le statut de retour de ce module doit contribuer directement au code de retour global renvoyé par la PAM-API après avoir lu la pile de modules. Autrement dit, si le statut renvoyé initialement devait être PAM_SUCCESS, le statut de retour du module remplacera cette valeur. À noter tout de même, si l'état initial de la pile était un code d'échec, cette valeur ne serait pas remplacée.
    done Équivalent à ok avec comme effet de quitter immédiatement la pile de modules (sans exécuter les modules suivants) et redonner la main à l'application.
    N (un entier non signé) Équivalent à ok avec comme effet de sauter les N modules suivants de la pile. Un N égal à 0 n'est pas permis (et serait égal à ok).
    reset Efface le statut de retour de la pile de modules et recommence avec le prochain module.

     

    En sachant cela, les quatre mots clés de la forme simple (required, requisite, sufficient et optionnal) peuvent se représenter de la façon suivante avec la syntaxe complexe :

    • required : [success=ok new_authtok_reqd=ok ignore=ignore default=bad]
    • requisite : [success=ok new_authtok_reqd=ok ignore=ignore default=die]
    • sufficient : [success=done new_authtok_reqd=done default=ignore]
    • optionnal : [success=ok new_authtok_reqd=ok default=ignore]

    L'élément suivant des instructions est le chemin-du-module qui peut être soit le chemin complet vers le module, ou soit le chemin relatif depuis le dossier par défaut des modules (cela peut être par exemple /lib/security, /lib64/security, /lib/x86_64-linux-gnu/security/, etc).

    Enfin, on termine les instructions par les argument-du-module. Pour les connaître, il faut consulter la page de manuel du module en question. Les arguments étant séparés par des espaces, afin de pouvoir placer un espace dans un argument, il faut entourer celui-ci de crochets.

     

    Les modules

    Les modules sont au cœur du système PAM. C'est grâce à eux que l'on peut définir le schéma d'authentification. Ils s'occupent chacun de la gestion d'un mécanisme d'authentification spécifique.
    Voici une liste des modules les plus communs :

    Nom Catégories compatibles Description courte
    pam_access.so Toutes Détermine l'endroit depuis lequel l'utilisateur à le droit de se connecter (en local, depuis telle adresse IP, etc...)
    pam_debug.so Toutes Aide à débugger le comportement de PAM en renvoyant le code de retour demandé par l'utilisateur.
    pam_deny.so Toutes Refuser l'accès de l'utilisateur. On invoque généralement ce module après avoir essayé les autres méthodes d'authentification.
    pam_echo.so Toutes Retourne un message texte personnalisé.
    pam_env.so Auth
    Session
    Permet de définir les variables et de supprimer les variables d'environnement de la session utilisateur.
    pam_exec.so Toutes Exécute une commande personnalisée.
    pam_faildelay.so Auth Change le délais d'attente avant de considérer l'authentification comme un échec pour une application.
    pam_filter.so Toutes Peut se placer pour filtrer les entrées/sorties entre l'utilisateur et l'application. Il peut par exemple forcer les minuscules surt tout ce que l'utilisateur écrira une fois loggé. Ne fonctionne cependant que pour les tty et les applications basées sur stdin/stdout.
    pam_ftp.so Auth Permet de se connecter à un serveur FTP.
    pam_getenv.so   Récupère les variables d'environnement depuis le fichier /etc/environment.
    pam_group.so Auth Assigne à l'utilisateur les groupes auquel il appartient.
    pam_issue.so Auth Affiche le contenu d'un fichier issue (par défaut /etc/issue) avant le prompt de l'utilisateur.
    pam_krb5.so Toutes Permet l'authentification via un serveur Kerberos.
    pam_lastlog.so Session Affiche une ligne d'information sur la dernière connexion de l'utilisateur.
    pam_ldapd.so Toutes Permet l'authentification via un serveur LDAP.
    pam_limits.so Session Permet de limiter l'usage des ressources système à l'utilisateur (charge CPU, nombre maximal de processus, etc).
    pam_listfile.so Toutes Accepte ou refuse l'authentification des utilisateurs en fonction du contenu d'un fichier.
    pam_localuser.so Toutes N'accepte que les utilisateurs listés dans le fichier /etc/passwd.
    pam_loginuid Session Applique l'UID de l'utilisateur au processus demandant l'authentification.
    pam_mail.so Auth
    Session
    Affiche un message si l'utilisateur a de nouveaux emails.
    pam_mkhomedir.so Session Créé le répertoire de l'utilisateur ci celui-ci n'existe pas.
    pam_motd.so Session Affiche le message du jour (par défaut le contenu du fichier /etc/motd).
    pam_mount.so Auth
    Session
    Donne la possibilité de monter un disque local ou distant à l'ouverture de la session utilisateur.
    pam_mysql.so ? Permet l'authentification via un serveur MySQL.
    pam_namespace.so Session Créé un espace de nommage pour la sessions (voir plus de détails dans la page de manuel du module).
    pam_nologin.so Account
    Auth
    Empêche les utilisateurs non-root de se connecter.
    pam_permit.so Toutes Module qui autorise tout le temps l'accès. À utiliser avec précaution pour des raisons de sécurité.
    pam_pwhistory.so Password Retient les anciens mots de passe des utilisateurs pour forcer à en avoir un différent lors du renouvellement de celui-ci.
    pam_rhosts.so Auth Permet l'authentification des utilisateurs sur la machine locale par SSH.
    pam_rootkok.so Auth Authentifie l'utilisateur sans avoir besoin de rentrer un mot de passe, du moment que son UID est 0 (l'UID de l'utilisateur Root).
    pam_securetty.so Auth Restreint la connexion de Root aux tty (terminaux) listés dans /etc/securetty.
    pam_selinux.so Session Met en place le contexte de sécurité pour la session qui s'ouvre.
    pam_sepermit.so Account
    Auth
    L'authentification est permise seulement si l'utilisateur possède une entrée dans fichier /etc/security/sepermit.conf.
    pam_shells.so Account
    Auth
    Autorise l'authentification seulement depuis les shells listés dans /etc/shells.
    pam_succeed_if.so Toutes Valide l'authentification suivant des tests faits sur les caractéristiques de l'utilisateur (nom, UID, GID, shell, home, etc).
    pam_tally2.so Account
    Auth
    Maintient un compteur du nombre d'essais d'authentifications. Ce compteur est réinitialisé lorsque l'authentification réussie. Utile pour bloquer un compte après un certain nombre de tentatives ratées.
    pam_time.so Account Permet de restreindre l'accès de l'utilisateur suivant l'heure de la journée, le jour de la semaine, le service sur lequel il se connecte et le terminal depuis lequel il se connecte.
    pam_timestamp.so Auth
    Session
    Permet de valider automatiquement l'authentification sans demander de mot de passe si la dernière authentification réussie est inférieur à une certaine date.
    pam_tty_audit.so Session Permet d'activer l'enregistrement de ce que l'utilisateur écrira dans un tty.
    pam_umask.so Session Définie l'umask sur la création des fichiers pour la session qui s'ouvre.
    pam_unix.so Toutes Authentification via les mécanismes standard, c'est à dire en faisant appel aux bibliothèques du système (ces dernières regardant par défaut dans les fichier /etc/passwd et /etc/shadow).
    pam_userdb Account
    Auth
    Authentification via une base de données Berkeley DB.
    pam_warn.so Toutes Module qui inscrit dans les logs l'authentification de l'utilisateur.
    pam_wheel.so Account
    Auth
    Autorise l'accès seulement aux utilisateurs du groupe wheel (ou du groupe au GID 0 si le groupe wheel n'existe pas).
    pam_winbind.so Toutes Permet l'authentification via un serveur Active Directory.
    pam_xauth.so Session Permet de conserver les clés xauth (cookies du serveur X) lors du changement de session.

     

    Il existe bien d'autres modules qui permettent d'utiliser tout types de serveurs pour l'authentification ou d'autres types de jetons (comme par exemple des cartes magnétiques). Mais vu qu'ils sont utilisés plus rarement, je vous laisse les découvrir par vous même.

     

    Conclusion

    PAM est un mécanisme très puissant pour la gestion de l'authentification sous Linux. Bien qu'assez complexe sur certains aspects, il permet à l'administrateur d'avoir un total contrôle de l'accès au système par les utilisateurs. C'est aussi un point clé lorsque l'on veut centraliser l'authentification des machines d'un réseau.

     

    Ressources supplémentaires

     

  • Lectures de vacances, offertes par le groupe Transcriptions de l’April (Dépêches LinuxFR)

    Depuis le mois de janvier 2017, ce sont un peu plus de 36 heures d’enregistrements audio et vidéo concernant le logiciel libre et les libertés numériques en général, qui ont été transcrites, relues, finalisées et publiées sur le site de l’April.

    La version texte de ces fichiers audio et vidéo permet :

    • d’augmenter leur indexation sur les moteurs de recherche ;
    • d’améliorer leur accessibilité aux personnes porteuses de handicaps ;
    • de retrouver les propos exacts des intervenants, les utiliser sans trahir leur pensée en citant fidèlement la source.

    Cependant, en cette période de vacances, cela permettra aussi à chacun et chacune de « lire » conférences, émissions de radio, reportages, etc., quitte ensuite à regarder ou écouter l’enregistrement en question.

    Et pour celles et ceux qui souhaiteraient participer, n’hésitez pas ! Vous pouvez rejoindre notre groupe, peut‐être commencer en relisant une transcription déjà effectuée, puis vous lancer en choisissant un enregistrement qui vous motive et dont vous pensez qu’il serait souhaitable qu’il soit disponible sous forme texte. Bon courage !

    À moins que ceci ne fasse partie de vos bonnes résolutions de rentrée, en septembre !

    Lire les commentaires

  • Mageia 6 est sortie (Dépêches LinuxFR)

    La très attendue Mageia 6 est enfin disponible. Des problèmes de compatibilité avec des périphériques pas très libres — mais très utilisés — sont la cause principale de ce retard.

    En attendant cette sortie, la communauté des développeurs avait publié la robuste version 5.1 qui sera maintenue pendant encore trois mois. L’enjeu était de faire mieux et d’éviter les régressions.

    De nombreux testeurs utilisent au quotidien cette version depuis la parution de la version candidate. Elle semble tenir toutes ses promesses :

    • passage à Wayland par défaut pour GNOME (X.org reste disponible) et vous pouvez l’essayer avec KDE Plasma ;
    • ajout du média autonome (live) avec l’environnement Xfce, aux côtés des classiques KDE Plasma et GNOME, le tout sous GRUB 2 remplaçant de GRUB 1 ;
    • ajout de dnf2 en tant que gestionnaire de paquetages alternatif au classique urpmi et de l’interface graphique dnfdragora en plus du classique rpmdrake ;
    • prise en charge d’AppStream pour ajouter des méta‐données aux outils comme GNOME Logiciels (GNOME Software) et Plasma Discover pour découvrir des logiciels à installer ;
    • retour de la portabilité sur processeur ARM (pour les plus aventureux).

    Sommaire

    Les nouveautés principales de Mageia 6

    Bien qu’il ne s’agisse pas d’une nouvelle fonctionnalité, Mageia 6 prend en charge plus de 25 environnements de bureau et gestionnaires de fenêtres (les détails seront disponibles lors d’une prochaine publication sur le blog) ! Que ce soit KDE Plasma 5.8.7 (LTS), GNOME 3.24.2, MATE 1.18, Cinnamon 3.2.8, Xfce 4.12.1, LXQt 0.11…

    KDE Plasma

    Le passage de Qt 4 à Qt 5 permet d’alléger notablement KDE Plasma, que l’on ne peut plus qualifier de lourd.
    Presque toutes les applications KDE 4 ont été migrées vers Plasma, de sorte que vous bénéficierez d’une belle expérience unifiée.

    GNOME

    Le serveur d’affichage Wayland est activé par défaut, l’utilisation de X.Org reste possible au besoin, si votre matériel est défaillant. Sur les processeurs graphiques Intel (voire AMD et sans doute NVIDIA), l’interface HDMI est gérée de base pour envoyer la vidéo vers un écran LCD ; le Bluetooth aussi, pour envoyer l’audio sur votre chaîne Hi‐Fi.

    Les extensions GNOME Shell les plus classiques sont disponibles en paquets de base : hibernate-status, alternate-tab, apps-menu, auto-move-windows, common, drive-menu, launch-new-instance, native-window-placement, onboard, overrides, places-menu, screenshot-window-sizer, user-theme, window-list, windowsNavigator et workspace-indicator, permettant d’utiliser GNOME au clavier efficacement tout en conservant quelques fonctionnalités utiles.

    Xfce et les autres…

    Une version autonome (live) est distribuée en ISO aux côtés de KDE Plasma et GNOME pour permettre de tester un environnement plus léger. Vous pouvez tester sur clef USB ou DVD. Voici la gamme complète des images ISO de Mageia :

    • installation classique DVD pour 32 bits ;
    • installation classique DVD pour 64 bits ;
    • DVD autonome GNOME 64 bits ;
    • DVD autonome Plasma 64 bits ;
    • DVD autonome Xfce 32 bits ;
    • DVD autonome Xfce 64 bits.

    En synthèse des mises à jour

    Tous les logiciels dans les dépôts ont été reconstruits et mis à jour pour inclure les derniers et les plus importants logiciels de l’écosystème libre, vous trouverez ci‐dessous quelques‐uns des principaux composants inclus dans cette version :

    • système de base : noyau Linux 4.9.35 (LTS), systemd 230, X.org 1.19.3, Wayland 1.11.0, Mesa 17.1.4 ;
    • bibliothèques graphiques : Qt 5.6.2 (LTS), GTK+ 3.22.16 ;
    • environnements de bureau : Plasma 5.8.7 (LTS), GNOME 3.24.2, MATE 1.18, Cinnamon 3.2.8, Xfce 4.12.1, LXQt 0.11 ;
    • applications : LibreOffice 5.3.4.2, Firefox 52.2.0 ESR, Thunderbird 52.2.1, Chromium 57.

    Dans le détail des nouveautés de Mageia 6

    Prise en charge de Wayland

    Wayland est un protocole de serveur d’affichage plus simple et plus efficace que l’architecture de X.Org qui utilise un gestionnaire de fenêtres composite fonctionnant de concert avec le système X Window.

    Avec l’introduction des compositeurs (permettant des effets de transparence, d’ombre portée, etc.), X.Org ne peut plus être performant, car il constitue une étape supplémentaire entre l’application et le compositeur, ainsi qu’entre le compositeur et le matériel.

    Wayland a été proposé pour succéder à X11 : un serveur Wayland joue à la fois le rôle de compositeur (gestionnaire de fenêtres) et de serveur d’affichage.

    Wayland est donc une évolution majeure dans l’architecture GNU/Linux, même si elle n’est que peu visible pour la majorité des utilisateurs. Une couche logicielle est fournie pour faire fonctionner les anciennes applications, via une version spéciale du serveur X.Org fonctionnant au‐dessus de Wayland : XWayland.
    Une conséquence possible de la disponibilité de Wayland devrait être la disponibilité de jeux nécessitant un affichage performant.

    MCC : le Centre de contrôle Mageia

    Cet utilitaire qui permet de configurer le système contribue fortement à la réputation de Mageia. Il est hérité de Mandrake, puis de Mandriva Linux, et s’est perfectionné au fil des années et des versions. Il a bénéficié d’une heureuse cure de jouvence. De nouvelles icônes ont joliment amélioré la convivialité de MCC.

    Exemple de menu du MCC
    Cette illustration vient de la version anglaise mais, rassurez‐vous, Mageia vous propose une version française lors de l’installation. Mageia est certainement la plus française des grandes distributions.

    Ajout de DNF2

    Proposé par Fedora, dnf a été logiquement intégré à Mageia. Il est disponible en plus de l’outil classique d’installation urpmi.

    Les apports d’AppStream

    Les utilisateurs bénéficient de l’outil dnfagora dans la continuité de rpmdrake, pour une interface graphique améliorée et cohérente. Cela permet à l’utilisateur de rechercher un logiciel correspondant à son besoin, en se basant sur des méta‐données consolidées entre distributions.
    C’est un apport en complément du travail de Debian pour http://madb.mageia.org, avec les copies d’écran des applications graphiques. Il y a aussi la possibilité de participer à l’assurance qualité de Mageia

    Mageia 6 pour l’architecture ARM

    Le portage ARM (re‐)prend vie : démarré avec Mageia 1, il est désormais disponible sur les miroirs pour architecture armv5tl et armv7hl (respectivement ARMv5 et ARMv7, ce qui inclut le Raspberry Pi). Attention, cela reste réservé aux aventureux, des images d’installation pourront être disponibles par la suite, si suffisamment de personnes se montrent intéressées.

    Par exemple, les serveurs de base de données PostgreSQL 9.4 et 9.6 sont disponibles : http://madb.mageia.org/package/list/t_group/68/application/0/arch/armv7hl/page/2.
    Pour ceux intéressés, vous pouvez aussi suivre le statut des paquets inclus selon l’architecture : https://pkgsubmit.mageia.org/arm-status.html.

    Participer à l’activité de Mageia et de sa communauté

    Nos amis francophones de MLO sont très actifs dans le soutien en français aux utilisateurs de la distribution avec tutoriels et forums officiels pour Mageia.

    Pour autant, la difficulté à sortir une distribution dans les temps a pesé pour certains :

    • Mageia 5 est sortie en juin 2015 ;
    • Mageia 5.1 est sortie en décembre 2016 ;
    • Mageia 6 arrive enfin en juillet 2017, pour une date initiale (re‐)planifiée en mars ou mai 2017, mais initialement prévue en août 2016, reportée à décembre 2016 pour diverses raisons ;
    • entretemps Cauldron (la version de dév’) a continué d’évoluer, pris en compte Wayland notamment, des mises à jour de beaucoup de logiciels (et de jeux) sur le mode de la publication continue — rolling release — (« jouez aux dés », si vous en avez envie, c’est votre choix, cela a été le nôtre pendant toute cette période).

    C’est un vrai travail de motivation et de recrutement, d’accueil de nouveaux contributeurs qui a permis la sortie de cette version Mageia 6. En bref, vous êtes les bienvenus à rejoindre le projet et à le faire perdurer (ce qui nous tient à cœur et nous motive, pouvant permettre à chacun d’apprendre beaucoup plus qu’il n’en aurait espéré de son passage sous GNU/Linux). Les contributeurs à Mageia sont présents sur la plupart des événements du Libre : FOSDEM, RMLL, JDLL, POSS, premiers samedis, Kernel Recipes, etc. N’hésitez pas à venir à notre rencontre !

    Comme Mageia 5 est bien maîtrisée, vous avez au moins jusqu’au 31 octobre 2017 pour passer à Mageia 6 qui, elle, vous permettra d’être tranquille jusqu’au 16 janvier 2019. :-)

    Bon passage à Mageia 6 ! _o/*

    Lire les commentaires

  • Migrer Windows 10 d'un disque BIOS/MBR, vers un SSD en mode UEFI/GPT avec des logiciels libres (Journaux LinuxFR)

    Sommaire

    Introduction

    Ce tutoriel vous guide pas à pas pour migrer votre installation de
    Windows qui est actuellement sur un disque dur de votre PC vers un
    nouveau disque, en l'occurrence un SSD. A vrai dire, vous pouvez aussi
    bien migrer vers un autre HDD.

    La spécificité de ce tutoriel est qu'elle utilise les outils fournis par
    Microsoft avec Windows ainsi que des logiciels libres (Clonezilla
    principalement, mais si quelque chose devait mal tourner vous pouvez avoir
    besoin d'utiliser fdisk, gdisk ou testdisk pour ne citer qu'eux). Quand
    j'ai voulu faire cette migration je n'ai pas trouvé de tutoriel
    expliquant de bout en bout comment faire cette migration juste avec les
    outils de Microsoft et des logiciels libres.

    Typiquement, vous pouvez avoir envie/besoin de faire cela car vous avez
    acheté un nouveau disque pour remplacer l'ancien (par exemple car
    l'ancien montre des signes de faiblesse, ou vous voulez améliorer la
    réactivité de votre système).

    En plus de la migration du système d'exploitation, ce tutoriel vous
    explique comment passer d'un démarrage en mode BIOS/MBR à un démarrage
    en mode UEFI/GPT.

    Succinctement la démarche est la suivante, d'abord installer le nouveau
    disque dans le PC, et initialiser la table de partition selon les normes
    Microsoft. Puis cloner/dupliquer la partition contenant le système
    d'exploitation à l'aide de Clonezilla. Ensuite et avant de redémarrer
    dans le clone de Windows sur le SSD, faire quelques modifications dans
    le registre pour que la lettre de lecteur C: pointe vers la bonne
    partition et éventuellement modifier le mode SATA en AHCI si vous le
    modifiez aussi dans le UEFI/BIOS. Après cela, on va préparer la
    partition système EFI/ESP pour que le PC puisse démarrer dessus et qu'il
    démarre sur le Windows du SSD. Finalement, une fois dans le Windows du
    SSD, on va réactiver l'"environnement de récupération de Windows".

    Mise en garde : Faites une sauvegarde de vos données avant toute
    opération. Personne n'est à l'abri d'une mauvaise manipulation ou d'une
    erreur.

    Prérequis

    Compétences

    Niveau de difficulté : Difficile.

    Vous devez être à l'aise au niveau de l'utilisation de la ligne de
    commande dans Windows, mais aussi assez à l'aise pour gérer les
    partitions de votre disque. Savoir modifier le paramétrage de votre
    Firmware UEFI/BIOS et aussi nécessaire. Ce tutoriel guide pas à pas pour
    la majorité des opérations. Certaines n'ont pas été détaillées par souci
    de simplicité et d'efficacité.

    Matériel

    Le PC où vous voulez installer le SSD. Il faut qu'il soit en état de
    marche. De plus il doit avoir un firmware UEFI. S'il n'a que un BIOS
    standard, sans UEFI, ce tutoriel n'est pas adapté.

    Clé(s) USB ou plusieurs CD/DVD sur lequel vous aurez mis
    Clonezilla, System rescue
    CD
    et un environnement de démarrage
    Windows PE, ou Windows RE, ou le DVD/Disque d'installation de Windows.

    Le disque SSD (testé avec Samsung SSD 860 EVO 250GB). Il doit avoir une
    taille suffisante pour contenir votre partition de Windows. Dans tous
    les cas, la taille de la partition qui contiendra Windows sur le SSD
    doit être au moins égale à la taille de la partition Windows du HDD que
    vous voulez cloner. Au besoin, pour remplir ce critère, réduisez la
    taille de votre partition Windows avec le gestionnaire de disque de
    Windows par exemple (ou un autre outil de gestion de partition, comme
    gparted, sur le System Rescue CD). Cherchez sur internet si vous ne
    savez pas comment faire.

    Logiciel

    Windows 10 installé (en version 64 bits) (testé avec Win10 v1709)

    Windows 10 PE ou support d'installation de Windows 10 (clé USB ou DVD) -
    En Version 64 bits (testé avec un support d'installation de Win10 v1804)

    System rescue CD (version 5.2.2 par
    exemple)

    Clonezilla installé sur une clé ou un CD.
    Bien vérifier avant que votre système arrive à démarrer dessus. (Testé
    avec Clonezilla 2.5.5-38)

    Nomenclature

    SSD : désigne le nouveau SSD

    HDD : désigne votre disque actuel, sur lequel est installé Windows

    WinPE : un environnement de démarrage Windows PE, ou Windows RE, ou le
    DVD/Disque d'installation de Windows. Il doit être sur un support
    amovible (USB, CD ou DVD)

    S: La lettre de lecteur affectée à la partition Système EFI qui sera sur
    le nouveau SSD (parfois appelée ESP, EFI_System_Partition ou encore
    SYSTEM, ou EFI)

    N: Le clone de Windows, sur le SSD

    O: Le Windows cloné, sur le HDD

    C: La partition dans laquelle est installée Windows, lorsqu'on est dans
    Windows (que ce soit le windows cloné, ou le clone)

    Les commandes doivent être lancées en tant qu'administrateur.

    Procédure de base

    • Fixer et brancher le SSD dans l’ordinateur

    • Désactiver Windows FastStart (cf votre moteur de recherche préféré)

    • Initialiser et partitionner le disque à l'aide de Windows

      • Démarrer sur le Windows installé ou WinPE
      • Pour initialiser le disque, d'abord créer une table de partition, puis partitionner le disque. Pour ce faire :
        • Suivre les instructions de partitionnement UEFI/GPT selon Microsoft. Ci-dessous mon exemple, mais peut-être avez-vous besoin d'une partition "recovery" aussi, ou votre configuration nécessite quelques aménagements. Dans ce cas, voir les instructions de Microsoft et adapter pour vos besoins.
        • Par exemple: une partition EFI de 260Mo, une partition Microsoft Reserved (MSR) de 16Mo, une partition pour Windows (taille au moins égale à la taille de la partition de Windows à cloner). Pour informations, dans diskpart, les tailles que vous donnez en MB/Mo sont en réalité des MiB/Mio (220 = 10242 octets).
          • Ouvrir une invite de commande en mode administrateur et lancer diskpart . Et une fois dans diskpart :
            • list disk pour lister les disques et connaître le n° du SSD.
            • select disk # avec le numéro du SSD à la place de #
            • clean Supprime le contenu du disque / l'initialise
            • convert gpt Définit que le disque aura une table de partition GPT
            • create partition efi size=260 Crée une partition EFI de 260MiB
            • format quick fs=fat32 label="System" Formater la partition EFI au format FAT32
            • assign letter="S" Lui donner la lettre S
            • create partition msr size=16 Créer une partition Microsoft Reserved de 16MiB
            • create partition primary Créer la partition pour Windows (l'équivalent du C: )
            • format quick fs=ntfs label="Windows" Formater la partition pour Windows au format NTFS
            • assign letter="N" Lui donner la lettre N
            • list volume Liste les volumes. Permet de voir la table de partition.
            • exit Quitte diskpart
    • Cloner le Windows installé sur le HDD. Ceci sera fait à l'aide de
      Clonezilla

      • Redémarrer dans Clonezilla
      • Une fois dans clonezilla, et si vous êtes confortable avec les lignes de commande Linux, éventuellement supprimer de la partition Windows du HDD les fichiers pagefile.sys , hyberfil.sys (désactiver windows faststart avant), swapfile.sys .
      • Cloner la partition Windows du HDD vers le SSD (de préférence, partition de même taille, et de toutes façons, la partition de destination doit être plus grande que la source. Si ce n'est pas le cas, réduisez d'abord la taille de votre partition Windows depuis Windows). Dans clonezilla, utiliser le mode Partition vers Partition, et en mode Export. Utiliser les options -e1 auto (automatically adjust file system geometry for a ntfs boot partition if exists) -e2 (sfdisk uses CHS of hard drive from EDD (for non grub loader) -r (resize filesystem to fit partition size of target) -m (do NOT clone boot loader) -v (verbose)
      • Optionnellement cacher la partition contenant le windows source de la table de partition du disque source (si vous ne savez pas à quoi ça sert, passez votre chemin). Pour cela modifier le type de partition de la partition NTFS de windows (en principe, NTFS a un id de « 7 ». On peut utiliser id 17 pour la partition cachée : 17 correspond à « IFS Hidden »). Utiliser cfdisk ou fdisk pour faire ce changement (ce sont des programmes linux).
    • Dans le Firmware UEFI (ou BIOS-UEFI), on peut en profiter pour passer
      du mode SATA "IDE" vers "AHCI". Windows n'aime pas ce changement et
      il faut donc faire une opération dans le registre qui est
      détaillée ci-dessous. Tant que vous ne le faites pas, vous aurez un
      écran de plantage bleu de windows au démarrage (BSOD).

    • Si vous voulez être sûr de ne pas faire de bêtise dans le Windows que
      vous venez de cloner, je vous conseille d'éteindre l’ordinateur & de
      débrancher l’ancien disque. Ainsi vous ne risquez pas de modifier le
      mauvais fichier de registre (en l'occurrence celui de votre Windows
      sur le HDD)

    • Effectuer quelques opérations sur le Windows de destination (celui
      sur le SSD) avant qu'on ne démarre dessus. En particulier corriger le
      registre pour affecter la lettre de lecteur C: à la bonne partition,
      et si le paramétrage du Firmware UEFI (BIOS-UEFI) a été modifié pour
      passer de SATA Mode PCI vers AHCI, on va aussi faire ce changement
      pour que ca fonctionne.

      • Redémarrer dans WinPE (en Mode UEFI, pas MBR !)
        • Tout d'abord déterminer la lettre de lecteur affectée au clone de Windows, celui qui est sur le SSD. Ou, s'il n'y a pas de lettre affectée, lui en donner une, par exemple N: (lettre utilisée dans les exemples qui suivent)
          • Pour cela, lancer dans diskpart
            • list volume
              Ce qui retourne la liste des volumes avec la lettre de lecteur qui a été affectée à chacun.
          • Si aucune lettre de lecteur n'est affectée, il faut alors lui en affecter une. Pour cela, lancer dans diskpart
            • select volume # (avec # étant le numéro du volume qui contient le nouveau windows)
            • assign letter=N
              S'il n'est pas possible d'utiliser select volume alors faire comme ceci
            • list disk
            • select disk # (# étant le numéro affecté au SSD)
            • list partition
            • select partition # (# étant le numéro affecté à la partition de Windows sur le SSD, probablement 3)
            • assign letter=N
        • Faire un CHKDSK /F sur la lettre du nouveau Win
        • Pour que la partition C: utilisée par Windows soit celle du SSD et pas celle de l’ancien disque, modifier une clé de registre du nouveau Windows :
          • Lancer REGEDIT et dans le registre HKEY_LOCAL_MACHINE monter la ruche N:\Windows\System32\Config\SYSTEM . Lui donner le nom "NewWin" On s’intéresse à HKEY_LOCAL_MACHINE\NewWin\MountedDevices . Ce sont là les valeurs qui sont dans le registre " HKEY_LOCAL_MACHINE\SYSTEM\MountedDevices " lorsqu'on est dans l'installation de Windows.
            • Dans HKEY_LOCAL_MACHINE\NewWin\MountedDevices modifier la lettre de lecteur C: en renommant \DosDevices\C: par \DosDevices\O: (car la valeur fait référence à la partition de l'ancien Windows sur le HDD et on ne veut pas, en démarrant, utiliser cette partition mais celle de son clone qui est sur le SSD). Ainsi, lorsqu'on démarrera dans le nouveau Windows, la partition contenant le Windows sur le HDD aura la lettre O:, et la partition contenant le Windows sur le SSD aura la lettre C:
            • Créer une nouvelle valeur binaire nommée \DosDevices\C: et lui donner comme contenu celui de \DosDevices\N: qui est renseignée dans le registre WinPE, c'est-à-dire là HKEY_LOCAL_MACHINE\SYSTEM\MountedDevices ( C: étant la lettre qu'utilisait le Windows du HDD comme partition où il y a le dossier \Windows )
            • ATTENTION: Bien vérifier que la copie a fonctionné et qu'il y a les bonnes valeurs, car dans mes essais, j'ai du m'y reprendre à 2 fois car le 1er "coller" ne collait pas ce que je voulais.
            • En principe c'est tout. Mais d'après certaines sources, il y aurait une clé \\?\Volume{GUID} ayant le même contenu que le \DosDevices\O: qu’on vient de modifier. Chez moi ce n'était pas le cas. Si vous avez une telle valeur, alors il faut lui donner le contenu de \DosDevices\N: depuis le registre WinPE
        • Si en même temps que la migration on veut aussi passer du mode SATA IDE vers AHCI alors il faut encore faire ceci. Cela a été repris du site tomshardware.co.uk
          • Toujours dans REGEDIT avec la ruche montée en HKEY_LOCAL_MACHINE\NewWin
          • Aller à HKEY_LOCAL_MACHINE\NewWin\ControlSet000\Services\storahci\StartOverride
          • Changer la valeur DWORD de 3 à 0.
          • Au redémarrage, si ça n'a pas été fait, changer la paramétrage du contrôleur SATA de IDE à AHCI. Au redémarrage, Windows devrait directement démarrer correctement et sans plantage (BSOD).
        • Rendre le disque bootable en installant les outils EFI de microsoft et configurant le Magasin BCD (BCD Store)
          • D'abord assigner une lettre de lecteur à la partition ESP
            • MOUNTVOL S: /S
              Si ca n'a pas fonctionné, faire comme ceci dans diskpart
            • list disk
            • select disk # (# est le numero du SSD retourné par list disk)
            • list partition
            • select partition # (# est probablement 1)
            • assign letter=S
          • Puis lancer bcdboot N:\windows /l fr-fr /s S: /f UEFI
            • N:\Windows est le répertoire contenant le clone de Windows sur le SSD)
            • S: = partition EFI
    • Redémarrer, et avant le lancement de Windows vérifier votre UEFI
      (ou BIOS-UEFI). Il faut qu'il soit configuré pour démarrer par défaut
      en mode UEFI et pas en mode BIOS. Penser aussi à corriger le
      paramétrage SATA si cela a été modifié dans le registre de Windows.

      Le paramétrage du démarrage avec
      bcdboot N:\windows /l fr-fr /s S: /f UEFI a normalement créé le
      magasin BCD, mis tous les fichiers EFI sur la partition SYSTEME (ESP,
      partiton EFI, la 1ère du SSD) et dit au firmware UEFI qu'il doit
      automatiquement démarrer avec le gestionnaire de démarrage
      (boot manager) de Windows.

    • Une fois qu’on a réussi à démarrer dans la copie de Windows

      • Réactiver le "FastBoot"
      • Réactiver l'environnement de récupération de Windows en lançant, depuis une ligne de commande avec les droits administrateur, la commande reagentc.exe /enable . Vérifier avec reagentc.exe /info . Et s'il y a une erreur essayer avec reagentc.exe /enable /setreimage /path C:\Recovery\WindowsREC:\Recovery\WindowsRE est le dossier où se trouve le fichier Winre.wim
      • Vérifier que tout est en ordre. Eventuellement donner un nouveau nom à votre partition C: (pour la différencier de celle sur le HDD) en lançant: LABEL [drive:][label]
      • Redémarrer encore une fois en laissant le processus de démarrage se faire tout seul pour vérifier que tout est ok.
    • Réinsérer l'ancien disque dur.

    • Normalement, il devrait être possible de redémarrer dans l'ancien
      Windows, du moment que vous savez comment booter en MBR, et sous
      réserve de ne pas avoir modifié le mode SATA dans le UEFI/BIOS. SI
      c'est le cas, vous pouvez envisager de modifier le registre du
      Windows du HDD, ou de modifier le paramétrage du UEFI/BIOS.

      Si vous avez aussi Linux d'installé sur le HDD, il devrait toujours
      être possible de le démarrer en mode BIOS

    • On peut diminuer/augmenter la taille de la partition C: du SSD (Pour
      un SSD TLC ou VNAND, on peut par exemple laisser de l’espace libre à
      la fin ~10 % de la capacité du disque d'après le logiciel Samsung
      Magician, pour un SSD 860 EVO)

    • En principe, puisqu’on boot en EFI on peut enlever sur le clone
      Windows sur le SSD les fichiers \bootmgr et \Boot\BCD puisque ce
      sont ceux qui étaient utilisés pour un boot en mode BIOS/MBR et que
      désormais on est en EFI. Vous pouvez d'abord les renommer et vérifier
      que ca ne change rien au prochain boot, plutôt que de les supprimer
      tout de suite.

    Quelques pistes si ça ne fonctionne pas…

    • Faire un chkdsk sur la nouvelle partition
    • Recréer le bootsector du NTFS avec testdisk (dispo sur System Rescue CD, mais peut être aussi dans Clonezilla ? Je n'ai pas vérifié)
    • Vérifier le BCD:
    • Vérifier que la partition EFI est bien initialisée (présence des fichiers \EFI , \EFI\Boot\ , \EFI\Microsoft\ …) Si ce n'est pas le cas, il y a eu un problème avec bcdboot N:\windows /l fr-fr /s S: /f UEFI
    • Vérifier le boot manager du bios (démarrage en UEFI ou MBR ? Gestionnaire de démarrage par défaut ? Présence du gestionnaire de démarrage de Windows ?)
    • A priori, pas utile : Commandes à lancer dans WinPE
      • Pour recréer le boot sector de la partition systeme (EFI): bootrec /fixboot
      • Pour chercher les OS sur le disque et les mettre dans le bootloader bootrec /scanos
    • Quelques commandes de bcdedit pour modiser la valeur de certains éléments du magasin BCD. Inutile car le BCD Store qui est utilisé lorsqu'on démarre en mode EFI n'est pas le même que celui utilisé dans un démarrage en mode MBR. Donc, pas besoin de chercher à modifier le BCD. Je garde pour info : les lettres sont celles telles que définies dans le système où on est (WinPE par ex). Doc BCDEDIT
      • bcdedit /set {bootmgr} device \Device\HarddiskVolume1
      • bcdedit /set {default} device \Device\HarddiskVolume3
      • bcdedit /set {default} osdevice \Device\HarddiskVolume3
      • Ou à la place de \Device\HarddiskVolume1 mettre les lettres de lecteur :
      • bcdedit /set {bootmgr} device partition=S:
      • bcdedit /set {default} device partition=C:
      • bcdedit /set {default} osdevice partition=C:

    Documentation, pour aller plus loin…

    A propos du EFI/UEFI:

    A propos de l'entrée MountedDevices du registre:
    http://diddy.boot-land.net/firadisk/files/mounteddevices.htm

    Si on veut y accéder, par défaut les fichiers du BCD sont cachés. Pour
    les rendre visibles:

    • attrib bcd -s -h -r
    • mv bcd bcd.bak
    • bootrec /rebuildbcd

    Documentation bcdedit:

    MBR Partition ID

    A propos des disk ID (=Disk signatures):

    Si besoin de supprimer du registre les entrées de disques qui ne sont
    pas connectés ou sans lettre assignée lancer: mountvol /R. Ce
    programme permet aussi de lister les lettres de volumes avec leur GUID
    (GUID pour ce système uniquement, il n’est pas stocké dans la partition,
    ni ailleurs sur le disque, il est assigné par windows pour un couple
    (signature de disque/partition offset) dans une instance de windows
    alors que dans une autre instance de windows la même partition sur le
    même disque aura ce GUID différent)

    Changer le label du volume: commande LABEL [drive:][label]

    Historique de révisions

    • Vous trouverez la dernière version de ce tutoriel sur ma page perso
      de tutoriels informatique
      .
      Vous y trouverez aussi la version HTML, PDF et TXT.

    • 2018-06-17 : Ajout d'une note indiquant que ce tutoriel utilise des
      logiciels libres

    • 2018-06-11 : Correction de la forme et de fautes d'orthographe

    • 2018-05-28

    Commentaires : voir le flux atom ouvrir dans le navigateur

  • 3 outils pour développeur : MailHog, Tokei et Pandoc (Dépêches LinuxFR)

    Dans cette dépêche, je vais vous présenter trois outils que j'utilise de temps en temps et qui pourrait servir à d'autres développeurs :

    • MailHog permet d'attraper des courriels pour les examiner ;
    • Tokei compte les lignes de code d'un projet ;
    • Pandoc est un couteau suisse pour manipuler des fichiers et les transformer d'un langage de markup à un autre.

    MailHog

    MailHog (sous licence MIT) permet d'attraper des courriels envoyés par une plateforme de développement et de les afficher dans une interface web. Pour cela, il fournit un serveur SMTP et un remplaçant du binaire sendmail, libre à vous de choisir le moyen qui vous convient le mieux. Il offre également, en option, la possibilité de transférer vers un vrai serveur SMTP les courriels et un outil de type chaos-monkey pour tester les cas d'erreurs d'envoi de courriels.

    L'interface web de MailHog avec 3 courriels capturés

    Je m'en sers quand je développe sur la partie serveur de Cozy Cloud. Cela permet de tester des fonctionnalités qui nécessitent l'envoi de courriels sans avoir à se compliquer la vie à configurer un vrai serveur d'envoi de courriels. En bonus, on évite de prendre le risque d'envoyer des courriels vers des vrais comptes d'autres personnes et on ne perd pas de temps à attendre que le courriel arrive, en attente d'un traitement anti-spam.


    Tokei

    Pour estimer la taille d'un projet, le nombre de lignes de code peut être une métrique intéressante. Il existe plusieurs projets pour faire ça, celui que je trouve le plus pratique est Tokei (sous licence Apache ou MIT). Voici ce qu'il affiche pour le dépôt principal de code de LinuxFr.org :

    -------------------------------------------------------------------------------
     Language            Files        Lines         Code     Comments       Blanks
    -------------------------------------------------------------------------------
     CoffeeScript           10          770          642           31           97
     Dockerfile              1           70           49            4           17
     HTML                   24         2660         2161            4          495
     JavaScript             11         2686         2025          394          267
     Markdown                1          187          187            0            0
     Rakefile                2           33           24            3            6
     Ruby                  262        11593         8338         1500         1755
     Ruby HTML               1           47           46            0            1
     Sass                   47        27317        23467         1583         2267
     Shell                   4           68           50            4           14
     SVG                    41        10886        10865           17            4
     TeX                     1           53           43            0           10
     Plain Text             44          531          531            0            0
     XML                     1           11           11            0            0
     YAML                    4          173          160            4            9
    -------------------------------------------------------------------------------
     Total                 454        57085        48599         3544         4942
    -------------------------------------------------------------------------------

    Par rapport à cloc, Tokei a plusieurs avantages :

    • il est beaucoup plus rapide (0,03 seconde pour Tokei contre 3,2 secondes pour cloc sur le dépôt principal de LinuxFr.org) ;
    • il est plus précis : cloc utilise des expressions rationnelles alors que Tokei a de vrais parsers (en particulier, un début de commentaire dans une chaîne de caractères comme printf("/*") peut bien induire en erreur cloc) ;
    • il ignore par défaut les fichiers listés dans .gitignore (par exemple, quand j'ai lancé cloc sur l'exemple ci-dessus, il a compté les fichiers dans tmp/cache et j'ai du le relancer avec des options pour qu'il fasse ce que j'en attendais).

    Pandoc

    Il existe de nombreux langages de markup : HTML, Markdown, reStructuredText, textile, DocBook, \LaTeX, MediaWiki markup, OrgMode, Epub, etc. Et ces langages ont parfois plusieurs variantes (exemple : CommonMark et GitHub Flavored Markdown pour le Markdown). Bref, ce n'est pas toujours facile de connaître les différents langages et de passer de l'un à l'autre. Pandoc (sous licence GPLv2 ou plus) permet de convertir un texte de la plupart de ces langages vers un autre langage, ou d'autres choses comme du PDF ou du LibreOffice.

    Je m'en sers, par exemple, pour écrire des présentations en markdown et en générer une version PDF via la classe Beamer pour \LaTeX. Ça m'a également servi, par le passé, pour convertir un wiki d'un format à un autre.

    Commentaires : voir le flux atom ouvrir dans le navigateur

  • Gestion de l'erreur - C++ - std::optional (Journaux LinuxFR)

    Sommaire

    Introduction

    Ce journal discute de la gestion d'erreur lors des appels de fonction. Dans la première partie, nous discuterons plusieurs solutions de gestion d'erreur classiques rencontrée dans de nombreux languages comme C, C++, Python, etc. Dans la seconde partie, nous présenterons std::optional<T>, une nouvelle classe de la librairie standard C++17 et nous discuterons comment celle-ci change la gestion d'erreur. Pour finir je donnerai un avis personnel sur l'API de cette classe que je n'aime pas, et je proposerai une solution alternative inspirée de ce qui se fait dans d'autres langages, comme swift, rust, ocaml, haskell, etc.

    Ce journal s'adresse au développeur débutant dans sa première partie. Le développeur débrouillé pourra être intéressé par la présentation de std::optional de la seconde partie. Enfin la partie finale sera sûrement le point de départ de nombreux débats (constructifs) et pourra intéresser tout le monde, mais surtout le développeur confirmé.

    Ce journal est clairement MON avis sur la question, et de nombreux points sont largement subjectifs, ils sont issus de mon expérience personnelle et je vous invite à m'incendier dans les commentaires si vous n'êtes pas d'accord ;)

    Note : je m'intéresse uniquement au traitement des optionals, donc j'ignore certains détails de bonnes pratiques de programmation ou d'optimisation ou de cas particuliers, ainsi inutile de troller sur le fait que certains de mes exemples n'exploitent pas la move sémantique et copient inutilement des chaînes, je sais ;)

    Fonctions partielles et fonction totales

    Il existe de nombreuses fonctions qui peuvent échouer, on appelle cela des fonctions partielles. Quelques exemples que nous utiliserons au cours de ce document.

    • Une fonction maximum qui donne la valeur maximum d'une liste. Que se passe-t-il si la liste est vide ?
    • Une fonction recherche qui cherche un élément dans un tableau et retourne l'indice où celui-ci se trouve. Que se passe-t-il si l'élément n'est pas dans le tableau ?
    • Une fonction lireFichier qui retourne le contenu lue dans un fichier. Que se passe-t-il si le fichier n'est pas lisible ou n'existe pas ?

    Pour toutes ces fonctions, il convient de mettre en place une politique de gestion d'erreur adaptée. Nous en discuterons plusieurs :

    • La politique du contrat.
    • La méthode des valeurs sentinelles
    • La méthode du flag de réussite.
    • La méthode par exception
    • La méthode par optional.

    Méthode par contrat

    Cette méthode est de loin la plus simple, il suffit de placer un contrat avec l'utilisateur de la fonction disant qu'il ne doit appeler la fonction que dans un contexte où elle doit réussir.

    Cette approche est utilisé par exemple en C++ pour l'opérateur operator[] d'accès aux cases d'un tableau sur un std::vector. Dans le cas où on essaye d'accéder à une mauvaise case, le comportement du programme est indéfini.

    Cette méthode est très simple, mais force le développeur à s'assurer que le contrat est respecté avant l'appel de fonction. C'est souvent contre productif voir impossible. Dans le cas de la fonction recherche il faudrait parcourir une première fois la structure pour vérifier que l'élément est dedans avant d'appeler la fonction recherche pour savoir où il est. Dans le cas de la fonction lireFichier, c'est carrément impossible puisque pour savoir si on peut lire un fichier, il faut le lire, et qu'il n'y a aucune garantie qu'un fichier lue à un instant t sera lisible à l'instant t+1.

    Je n'apprécie pas cette méthode car elle est source de nombreux bugs difficiles à trouver.

    Méthode par valeur sentinelle

    L'idée ici étant d'utiliser une valeur de retour particulière pour matérialiser l'erreur.

    C'est une approche très souvent utilisée dans de nombreuses librairies. Par exemple, en C, nous avons la fonction fopen FILE *fopen(const char *path, const char *mode); chargée d'ouvrir un fichier. En cas de réussite, la fonction retourne un pointeur vers un objet utilisé par la suite pour traiter le fichier. En cas d'échec, elle retourne un pointeur NULL.

    Dans le cas de la méthode recherche qui renvoie l'indice dans un tableau d'un élément recherché, on pourrait renvoyer une valeur négative, puisque les indices dans un tableau sont toujours positifs. L'usage se ferait ainsi de la manière suivante :

    // prototype de la fonction
    int rechercher(const Collection &c, const Item item);
    
    //...
    
    int offset = rechercher(maCollection, monItem);
    
    if(offset >= 0)
    {
        std::cout << "Item trouvé à la position " << offset << std::endl;
        std::cout << "La valeur de l'item est " << maCollection[offset] << std::endl;
    }
    else
    {
        std::cout << "Item non trouvé".
    }

    Cette méthode ne peut cependant pas s'appliquer à tous les cas de figure. Quelle valeur sentinelle pourrait renvoyer la fonction maximum ? Celle-ci devra être garantie de ne pas pouvoir être confondue avec une valeur qui serait le vrai résultat de la fonction.

    Cette méthode rend l'erreur facile, en effet, il est aisé d'oublier de tester la réussite, ainsi le code suivant, qui semble anodin, est faux :

    int offset = rechercher(maCollection, monItem);
    
    std::cout << "Item trouvé à la position " << offset << std::endl;
    std::cout << "La valeur de l'item est " << maCollection[offset] << std::endl;

    En effet, si l'élément n'est pas trouvé, offset vaut -1 et maCollection[offset] n'a pas de sens.

    Méthode par flag de réussite

    Ici la fonction vas renvoyer un flag, souvent un booléen pour matérialiser la réussite. La valeur de retour étant en fait passée par référence et modifiée.

    // prototype de la fonction
    bool rechercher(const Collection &c, const Item item, int &offset);
    
    //...
    
    int offset;
    bool res = rechercher(maCollection, monItem, offset);
    
    if(res)
    {
        std::cout << "Item trouvé à la position " << offset << std::endl;
        std::cout << "La valeur de l'item est " << maCollection[offset] << std::endl;
    }
    else
    {
        std::cout << "Item non trouvé".
    }

    Cette approche corrige une des limitations de la méthode par valeur sentinelle, elle peut fonctionner pour n'importe quelle fonction, puisque il n'est pas nécessaire de trouver une valeur sentinelle adaptée, la réussite étant matérialisée par le booléan. Cependant on peut toujours oublier de tester le booléan de résultat et ainsi utiliser la valeur de offset qui serait non initialisée (ou initialisée par défaut avec une valeur fausse).

    Méthode par exception

    Cette méthode est plus souvent utilisée dans des langages comme Python. Par exemple, la fonction de recherche d'un élément dans une liste vas soit renvoyer l'indice de l'élément, soit va lever une exception qui va remonter la pile d'appel jusqu'à être interceptée ou jusqu'à terminer le programme.

    >>> # cas qui fonctionne
    >>> [1,2,3].index(2)
    1
    
    >>> # cas qui renvoie une exception
    >>> [1,2,3].index(4)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ValueError: 4 is not in list
    

    La méthode par exception a de nombreux avantages :

    • Si on ne traite pas l'exception, elle finira le programme, souvent avec un message d'erreur explicite, ce qui évite les bugs dissimulés où la valeur sentinelle ou non initialisée est utilisée.
    • Le code n'est pas complexifié par une gestion d'erreur avec de nombreux if
    • La gestion d'erreur peut être repoussée à plus tard, dans une fonction appelante.

    La gestion de l'exception se fait, en Python, avec un bloc try / except :

    try:
       offset = maCollection.index(monItem)
       print("l'element a été trouvé, il est en position", offset, "et c'est", maCollection[offset]
    except: # Normalement il ne faut pas attraper TOUTES les exceptions, mais c'est un tutoriel simplifié
       print("Élement non trouvé")

    Le C++ gère aussi les exceptions, mais la librairie standard ne s'en sert pas. Pour différentes raisons que je n'aborderais pas, la communauté du C++ n'aime pas les exceptions et peu de librairie les utilisent correctement.

    Cependant, rien ne force le développeur à gérer les exceptions et rien n'indique à celui-ci qu'une fonction peut lancer une exception, si ce n'est une lecture scrupuleuse de la documentation. Certains langages, comme Java, proposent un système d'exception qui force le développeur à gérer celles-ci ou à les propager explicitement à la fonction appelante.

    C'est donc à mon sens une solution intéressante, mais il est trop facile d'oublier de traiter un cas exceptionnel. Heureusement, celui-ci se traduira par une exception qui finalisera le programme, mais en tant que développeur j'aurais aimé que mon compilateur m'assure lors du développement que je n'avais pas raté ce cas.

    Bilan

    Dans l'état actuel des choses, nous avons des méthodes qui laissent beaucoup de place à l'erreur potentielle et qui forcent à bien lire la documentation de chaque fonction pour distinguer les valeurs sentinelles, comprendre le fonctionnement du flag de réussite, ou connaître la liste des exceptions pouvant apparaître.

    La méthode par exception est sans doute la plus propre de toutes, mais il est difficile dans les langages qui ne gèrent pas les exceptions vérifiées (Comme C++, Python, etc.) d'être certain d'avoir traité toutes les exceptions possibles.

    En dernier point, touts ces méthodes sont très implicites et il n'est pas évidant de repérer les oublis de gestion d'erreur lors d'une lecture de code.

    C++17 et std::optional

    std::optional vas apparaître avec C++17 et une implementation était disponible dans Boost.Optional. Il s'agit d'une classe qui peut contenir ou pas une valeur. L'objet peut être testé avec une méthode has_value et la valeur peut être récupérée le cas échéant avec la méthode value. Vous pouvez dès à présent tester std::optional dans le namespace std::experimental dans de nombreux compilateurs. Reprenons notre exemple de la fonction rechercher :

    // prototype de la fonction
    std::optional<int> rechercher(const Collection &, const Item &);
    
    // ...
    
    std::optional<int> offsetO = rechercher(maCollection, monItem);
    
    if(offsetO.has_value()) // ou tout simplement if(offset)
    {
        int offset = offsetO.value();
        std::cout << "Item trouvé à la position " << offset << std::endl;
        std::cout << "La valeur de l'item est " << maCollection[offset] << std::endl;
    }
    else
    {
        std::cout << "Item non trouvé".
    
    }

    Cette approche est très proche de l'approche par flag de réussite, sauf que le flag de réussite est contenu dans l'optional en même temps que la valeur de retour. Je trouve personnellement que cela rend l'API de la fonction plus lisible car on distingue bien en argument les entrées et en valeur de retour les sorties pouvant ne pas réussir. Comparons nos anciens prototypes :

    // Méthode par valeur sentinelle, le prototype ne donne aucune
    // information sur les erreurs possibles, il faudra lire la documentation
    int rechercher(const Collection &, const Item &);
    
    // Méthode par flag de réussite, le prototype nous laisse penser qu'il
    // y a quelque chose à faire, d'autant que la valeur passée par référence
    // n'est pas const, ce qui devrait nous alarmer, mais c'est tout de même
    // flou.
    bool rechercher(const Collection &, const Item &, int &);
    
    // Méthode par exception, le prototype ne liste pas les exceptions.
    int rechercher(const Collection &, const Item &);
    
    // Méthode par optional, le prototype met en évidence la présence d'un
    // résultat qui peut ne pas être là.
    std::optional<int> rechercher(const Collection &, const Item &);

    De plus, on ne peut pas utiliser directement l'optional<T> en lieu
    et place de la valeur contenu, il faut explicitement aller le chercher
    avec la méthode value.

    Cette méthode est donc attrayante à mes yeux, mais on peut encore se tromper en allant directement chercher la valeur avec value sans tester sa présence :

    int offset = rechercher(maCollection, monItem).value();

    Heureusement, la fonction value lève une exception dans ce cas là, donc tout n'est pas perdu.

    Une autre limitation concerne la soupe de code qui apparaît lorsque on travaille avec de nombreuses méthodes retournant des optional. Imaginons que nous avons les méthodes f, g et h tel que :

    std::optional<B> f(Arg);
    std::optional<C> g(B);
    D h(C);
    

    et que nous voulions construire la méthode std::optional<D> foo(Arg). Notre code risque de ressembler à ceci :

    std::optional<D> foo(Arg arg)
    {
        auto fResO = f(arg);
        if(!fResO)
        {
            return std::optional<D>{}; // un optional vide
        }
    
        auto fRes = fResO.value();
    
        auto gResO = g(fRes);
        if(!gResO)
        {
            return std::optional<D>{}; // un optional vide
        }
    
        auto gRes = gResO.value();
    
        return std::optional<D>{h(gRes));
    }

    Et encore, je vous ai épargné la cascade de if imbriqué. Ce code est lourd et fastidieux et potentiellement source d'erreur. Pourrait-on faire mieux ?

    Une nouvelle API pour std::optional

    Je reproche deux choses à std::optional dans son état actuel :

    a) La libraire est source d'erreur car on peut appeler la fonction value alors que l'optional ne contient rien. Il faut en théorie s'assurer qu'il contient bien une valeur avant, et rien ne force cette vérification.
    b) Il est difficilement composable, en effet, l'utilisation de plusieurs std::optional est souvent source d'une cascade de if imbriqués qui font mal aux crane et qui sont sources d'erreurs.

    Sécurité

    Nous allons nous attaquer au premier point. Ce que je veux c'est une fonction qui, connaissant un optional, fasse un traitement si celui-ci contient une valeur et pas de traitement sinon.

    Dit autrement, je veux cette fonction, que j'appelle arbitrairement optionalApply :

    template<typename T1, typename F>
    void optionalApply(std::optional<T1> o, const F &f)
    {
        if(o)
        {
            f(o.value());
        }
    }
    

    Simple non ? Elle effectue l'action f si l'optional est bon, et pas d'action sinon. F est un type templaté qui peut contenir au choix des fonctions, des lambdas, ou des objets fonction. On pourra donc écrire le code de recherche d'un élément dans un tableau de la façon suivante :

    optionalApply(rechercher(maCollection, monItem), [&](int offset)
    {
        std::cout << "Item trouvé à la position " << offset << std::endl;
        std::cout << "La valeur de l'item est " << maCollection[offset] << std::endl;
    });

    En se servant des fonctions lambda de C++11. Je l'avoue, la syntaxe est particulière du fait des lambdas, mais ici on obtient un code ou il est impossible de se tromper. Par contre je n'ai pas géré le cas o ùon veuille faire quelque chose si l'optional ne contient rien. Autant faire une nouvelle fonction, optionalCase

    template<typename T1, typename FOk, typename FNotOk>
    void optionalCase(std::optional<T1> o, const FOk &fOk, const FNotOk &fNotOk)
    {
        if(o)
        {
            fOk(o.value());
        }
        else
        {
            fNotOk();
        }
    }

    Ce qui nous donne maintenant :

        optionalCase(rechercher(maCollection, monItem),
                     [&] (int offset)
                      {
                          std::cout << maCollection[offset] << std::endl;
                      },
                     [] ()
                     {
                         std::cout << "Item non trouvé" << std::endl;
                     }
                     );
    

    On pourra débattre de la lisibilité du truc, mais maintenant, en tout cas, on ne peut plus se tromper.

    Composabilité avec map

    Maintenant la question c'est comment chaîner plusieurs fonctions qui peuvent renvoyer des optionals et ce facilement, en limitant la présence de variables intermédiaires (les optionals et leur valeur) et en limitant l'erreur au maximum.

    Pour cela on va écrire la fonction map, variante de optionalApply qui contient un type de retour :

    template<typename T1, typename T2, typename F>
    std::optional<T2> map(std::optional<T1> o, const F &f)
    {
        if(o)
        {
            return std::optional<T2>(f(o.value()));
        }
    
        return std::optional<T2>(); // un optional vide
    }
    

    Cette fonction nous permet donc d'appliquer n'importe quelle fonction de transformation de A vers B sur un std::optional<A> vers un std::optional<B>. Exemple d'utilisation, on veut calculer la longueur du contenu d'un fichier, sachant que on possède une fonction std::optional<std::string> readFileContent(const std::string &path).

    // Solution sans map
    std::optional<size_t> getFileLength(const std::string &path)
    {
         auto contentO = readFileContent(path);
         if(contentO)
         {
             auto content = contentO.value();
             return std::optional<size_t>(content.size());
         }
         else
         {
             return std::optional<size_t>(); // optional vide
         }
    }
    
    // Solution avec map
    
    std::optional<size_t> getFileLength(const std::string &path)
    {
         return map(readFileContent(path), [] (std::string content)
         {
             return content.size();
         });
    }

    La solution avec map est plus simple. Notons que on pourrait faire encore plus simple et plus lisible en exploitant C++14 et C++17 pour la détection automatique des type des lambdas et si map était une méthode de optional, on pourrait avoir quelque chose du genre :

    std::optional<size_t> getFileLength(const std::string &path)
    {
         return readFileContent(path).map([] (auto content)
         {
             return content.size();
         });
    }

    Notons aussi que le lambda n'est pas obligatoire si la fonction à chaîner existe déjà.

    Composabilité avec bind

    Nous ne sommes toujours pas capables de traiter le cas présenté initialement avec les fonctions f, g et h car celles-ci ne sont pas des fonctions de A dans B, mais de A dans std::optional<B>, ce qui complexifie un peu les choses, nous allons introduire une nouvelle fonction, bind qui gère ce cas.

    template<typename T1, typename T2, typename F>
    std::optional<T2> bind(std::optional<T1> o, const F &f)
    {
        if(o)
        {
            return f(o.value());
        }
    
        return std::optional<T2>(); // un optional vide
    }

    On peut donc maintenant traiter notre cas initial, je vous rappelle :

    // sans map ni bind
    
    std::optional<D> foo(Arg arg)
    {
        auto fResO = f(arg);
        if(!fResO)
        {
            return std::optional<D>{}; // un optional vide
        }
    
        auto fRes = fResO.value();
    
        auto gResO = g(fRes);
        if(!gResO)
        {
            return std::optional<D>{}; // un optional vide
        }
    
        auto gRes = gResO.value();
    
        return std::optional<D>{h(gRes));
    }
    
    // avec map et bind
    
    std::optional<D> foo(Arg arg)
    {
        return map(bind(f(arg), g), h)
    }
    
    // avec map et bind en fonction membre des optionals
    
    std::optional<D> foo(Arg arg)
    {
        return f(arg).bind(g).map(h);
    }

    Voila, c'est plus simple et moins source d'erreur.

    Pour finir, que faire si en bout de chaîne on veux une valeur par défaut si il n'y a pas de valeur dans l'optional, et bien il existe value_or qui est déjà dans le standard c++17 qui permet de récupérer la valeur ou une valeur par défaut, ce qui permet d'écrire :

    std::optional<D> fooWithDefault(Arg arg, D def)
    {
        return map(bind(f(arg), g), h).value_or(def);
    }

    Conclusion

    Je vous ai présenté différentes méthodes de gestion des fonctions partielles. Pour ma part, mon coeur balance entre les optionals (avec map et bind) et les exceptions. Les optionals assurent une sécurité importante du code, une grande composabilité et assurent que l'erreur est traitée. Les exceptions ont moins de garantie, mais il existe des cas où on ne veut pas traiter l'erreur et où il est préférable d'avoir une exception.

    Ces deux approches sont utilisables en C++, en Python (mais avec moins de garantie à la compilation) et dans de nombreux langages comme Haskell (mon préféré), Rust, Swift, Ocaml, j'en oublie des milliers. L'approche par optional a une place de premier ordre dans certains langages. Le C++ propose depuis son standard C++17 une API d'optional, mais je la trouve limitée et je vous ai proposé des extensions.

    Les fonctions map, bind, optionalCase et optionalApply que je vous ai proposées sont utilisables comme cela, mais pour en faire une vraie librairie il faudrait prendre en compte de nombreux cas particuliers, notamment pour traiter le cas où les objets contenus dans l'optional ne peuvent pas être copiés.

    Lire les commentaires

  • De l'exploitation des logs de fail2ban… (Journaux LinuxFR)

    Comme beaucoup d'entre vous, pour sécuriser l'accès SSH de mon serveur j'utilise fail2ban (en plus des règles habituelles de sécurité). Fail2ban permet d'envoyer un mail à chaque fois qu'il bannit une IP mais finalement personne ne prend le temps d'examiner ces mails car le format n'est pas exploitable.

    J'ai donc décidé d'exploiter les logs de fail2ban afin de générer un rapport quotidien.

    Pour cela, j'ai utilisé python et les excellentes bibliothèques pandas et matplotlib.

    report.png

    Principe de fonctionnement

    1) fail2ban-getlog

    Une tâche cron se déclenche toutes les heures et va alimenter un fichier de travail (log.csv) avec tous les nouvelles IP bannies depuis le dernier lancement.

    Paramètres de lancement :

    fail2ban-getlog log.csv

    2) fail2ban-report

    Une autre tache cron va se déclencher quotidiennement et utiliser ce fichier de travail (log.csv) pour générer un rapport PDF (report.pdf). Afin de localiser les IP, j'utilise la bibliothèque geoip2 qui nécessite une base de données (GeoLite2-Country.mmdb). Il est possible de télécharger une base de données gratuite sur le site du projet.

    Paramètres de lancement :

    fail2ban-report log.csv GeoLite2-Country.mmdb report.pdf

    Le rapport généré (report.pdf) contient pour l'instant 3 graphiques. Le premier permet de visualiser le nombre d'IP bannies par jour, le deuxième permet de visualiser le nombre d'IP bannies par pays et le dernier permet de visualiser le nombre de bans par IP.

    Ensuite en fonction des désirs de l'utilisateur on peut envoyer le rapport par mail ou le mettre à disposition à un emplacement particulier.

    Les sources sont disponibles sur github et les dépendances nécessaires sont : python3-pandas, python3-matplotlib, python3-geoip2.

    Futur

    Pour l'instant, les 3 graphiques permettent de visualiser l'activité globale (depuis le début de la collecte des logs). J'envisage de rajouter des graphiques pour visualiser l'activité des dernières 24h.

    Lire les commentaires

  • Soirée déc‐ouverte LinuxFr.org, numéro 1 : FusionForge, LibreOffice et OpenLaw (Dépêches LinuxFR)

    L’idée est de lancer un nouveau format de soirée libriste (et d’itérer dessus). Le processus est de commencer par une première soirée, organisée très simplement (effort minimaliste), pour un nombre restreint de personnes engagées et de réfléchir à l’évolution continue du format, via des soirées répétitives, sans doute à un rythme mensuel.

    À la base, LinuxFr.org organisait des réunions IRL/AFK (In Real Life, Away From Keyboard, dans la vie réelle, loin du clavier). C’était limité aux équipes de modérateurs, administrateurs, développeur(s), rédacteurs. Les sujets étaient centrés sur les évolutions de la communauté et des contributions au site. Pour de multiples raisons, ça s’est essoufflé. La volonté est de relancer cette dynamique, tout en ouvrant un peu le spectre et l’audience.

    Da News in French

      Déroulement de la soirée

      Le format initial sera le suivant : réunir quelques projets libres (deux ou trois) autour d’une table et discuter librement de liberté et d’ouverture. L’audience sera là pour écouter et interagir. Le réseautage et le partage de nourriture et boisson seront le petit plus, donc apportez vos spécialités.

      Trois parties :

      • accueil et brise‐glace, 10 à 15 min ;
      • table ronde ouverte, entre 1 h et 1 h 30 ;
      • réseautage, jusqu’à fermeture des portes.

      Les trois intervenants et projets seront :

      Informations pratiques

      • adresse : Inno3 (Inno « cube »), 137 Boulevard de Magenta, 75010 Paris, France (escalier A, 2e étage à droite) ;
      • transports en commun :
        • Métro 2 et 4, station Barbès‐Rochechouart ;
        • Métro 4 et 5, station Gare du Nord ;
        • RER E, station Magenta ;
      • date et heure : mercredi 8 février 2017 à 19 h.

      Attention, l’accès est limité à vingt personnes !

      Dans le prochain épisode

      La prochaine soirée déc‐ouverte LinuxFr.org, numéro 2, est prévue le mardi 7 mars.

      Les intervenants seront :

      Lire les commentaires

    • Comment concilier partage de ses données personnelles et vie privée ? (Journaux LinuxFR)

      Ce journal constitue un début de réflexion sur la récolte de l’ensemble des données qu’ont peut recueillir sur nous même, et sur la manière de les mettre à disposition à des « demandeur de données ». Je pense en particulier à la recherche scientifique.

      Aujourd’hui, ce sont de très gros organismes comme l’état ou les GAFAM qui ont les moyens de récolter des masses de données, et on a très peu de contrôle sur ce qu’ils en font. Ils se constituent en acteur incontournables et poussent à utiliser leurs services à eux pour aggréger le plus de données possibles. Ils ont beaucoup de pouvoir pour savoir qui va acheter ou utiliser les données. On peux les soupçonner légitimement de sacrifier à in moment ou a un autre l’éthique à la rentabilité, y compris de manière non transparente, tout on ne permettant pas l’accès aux données à des acteurs qui pourraient y avoir accos pour faire des choses utiles.

      J’ai l’impression qu’il serait possible de les court-circuiter par des techniques de partage de données interopérables et de rendre à l’individu du pouvoir sur l’utilisation de ses données.

      Imaginons que des chercheurs fassent des recherches sur les déplacements des citoyens. Beaucoup d’entre nous ont des dispositifs capables d’enregistrer ses déplacements … (et bien d’autre chose). Une manière « classique » de travailler pour un chercheur est de monter une expérience, éventuellement de trouver des volontaires pour remonter les données, de trouver des jeux de données existants …

      Imaginons qu’on les autorise, si on le veux bien, à nos données. On pourrait monter un genre de site (ou d’appli) à la mode « financement participatif », mais avec des données à la place des sous. Une « bourse de données » en quelque sorte. Les chercheurs décriraient une expérience, les données dont ils ont besoins, et on pourrait individuellement leur uploader nos données (et les anonymiser) ou leur laisser un accès à la demande.

      Je pense que c’est très faisable techniquement, avec un peu de crypto pour aider à garantir la confidentialité, des formats ou des APIs ouvertes pour les formats d’échanges, des logiciels libres pour auditer le code. On peu même imaginer un « conseil scientifique » qui audite les demandes des chercheurs avant de les publier. Une appli type « tinder » pour dire « je veux «changer » ou « je zappe cette expé ». Une demande aux chercheurs de publier le jeu de données qu’ils ont finalement utilisé après coup.

      Qu’en penses-tu, libriste ?

      Lire les commentaires

    • [Bookmark]Les liens vers des contenus sont illégaux, sont illégaux (sous 2 conditions) (Journaux LinuxFR)

      Salut,
      La CJUE continue de rendre des avis qui ne me semble pas très favorable au monde de l'informatique. Cette fois ci ils ont considérés que des liens qui pointe des contenus illégaux, sont eux même illégaux, sous 2 conditions :

      • avec but lucratif
      • connaissance de cette illégalité

      Contrairement aux premières réactions que l'ai lu, je ne pense pas que les moteurs de recherche soient impactés. Ils n'ont pas connaissance de la légalité ou non des liens qu'ils publient. Par contre pour tous les sites de DDL/bitorrent/streaming/etc, ça remet gravement en cause leur ligne principale de défense (aucun hébergement de contenue illicite).

      Alors vrai changement sur internet ou pétard mouillé ?

      Lire les commentaires

    • Le Frido : un livre, libre, de mathématiques pour l’agrégation (Dépêches LinuxFR)

      La version 2017 du Frido, ce bouquin de mathématiques dont un des intérêts est d’être libre, est publiée.

      Fort d’environ 2 000 pages, il couvre la quasi entièreté du programme d’agrégation. Ce cours de mathématiques est libre au sens de la licence FDL et ses sources LaTeX sont sur GitHub depuis le début du projet.

      Sommaire

      Le Frido 2017

      Pour la plus grande joie des personnes qui seront admises aux oraux de l’agrégation de mathématiques en 2018, l’édition 2017 du Frido vient de sortir.

      Il contient pratiquement tout le programme de l’agrégation en un seul bouquin ; pratique pour la cohérence des notations et des définitions. Publié sous licence FDL et disponible au téléchargement aussi bien qu’à l’achat.

      Mathématiques

      Du point de vue de la mathématique, on part d’une théorie naïve des ensembles (on suppose les nombres rationnels construits) et on va jusqu’aux processus markoviens en passant par les distributions, les groupes/anneaux/corps, la théorie de la mesure, les espaces vectoriels et d’autres.

      Une caractéristique importante est que tous les résultats sont placés dans l’ordre mathématiquement logique : il n’y a jamais une démonstration qui dit « nous verrons plus loin que ». Cela impose une très forte contrainte sur la division en chapitres. Par exemple :

      • les fonctions trigonométriques sont définies par leurs séries (tout le monde dit qu’on peut le faire, mais qui le fait vraiment ?) ;
      • les rotations dans le plan sont définies comme composées de deux symétries axiales.

      Démontrer à partir de ces définitions qu’une rotation est une application linéaire dont la matrice dans la base canonique est celle que l’on connaît est fait en détail dans le Frido, mais c’est un peu long.

      Le niveau visé

      Le Frido tente de faire le grand écart entre deux tendances :

      • le niveau mathématique est élevé : les définitions sont posées dans des cas assez généraux et quelques larges digressions hors programme sont inclues.
      • le niveau pédagogique est d’aller au plus détaillé possible. Rien n’est considéré comme évident. Toutes les justifications utiles sont données et les renvois vers les théorèmes utilisés sont explicites. Pas non plus d’abus de notations.

      Le texte est donc long, mais il ne devrait pas y avoir de blocages. Et s’il y a un bocage, une justification qui manque, contactez l’auteur ; il est sympa et il tient compte des remarques.

      Le modèle économique.

      Il n’y a pas de modèle économique. Enfin, si… Le modèle est que j’écris gratos et vous m’envoyez gratos vos correctifs. Plus précisément :

      • sur thebookedition, j’ai fixé mon bénéfice à zéro et donc les ventes me rapportent littéralement zéro ;
      • sur lulu.com, le bénéfice est fixé par le site, mais on peut accorder une réduction allant de 10 % à 60 % du prix. Il n’y a pas moyen de ne pas faire de bénéfices. Bref, sur chaque livre vendu sur lulu.com je prends entre 40 et 50 centimes qui me seront envoyés sous forme d’un chèque de 20 dollars lorsque cette somme sera atteinte.

      Comment contribuer ?

      • en parler autour de vous si vous connaissez du monde qui compte passer l’agrégation de mathématiques cette année ;
      • signaler toutes les erreurs, imprécisions et choses obscures que vous pourriez trouver en lisant ;
      • le Frido manque d’exemples de tout, partout. Merci de me signaler ce que je peux ajouter.

      Une liste de questions ouvertes et de demandes précises est dans l’introduction du Frido. Elle est à peu près classée par thèmes (algèbre, analyse, informatique) et par difficultés. Il y en a pour tous les goûts : depuis la création d’un environnement \LaTeX plus beau pour les exemples, jusqu’à des questions fines de topologie sur les espaces de distributions.

      Recompiler le texte chez vous

      Alors là, c’est le point noir.

      Python

      Vu la complexité du bouzin, il y a une pile fortement non négligeable de scripts de précompilation avant de passer à \LaTeX. C’est tout en python, mais ça utilise des modules personnels.

      • latexparser est un module personnel qui sert à manipuler du code \LaTeX ;
      • pytex est un script personnel qui s’appuie sur latexparser pour faire une montagne de modifications du code \LaTeX du Frido à la volée avant de passer la main à pdfLatex.

      Il y a un manuel du contributeur qui explique comment faire.

      pdflatex

      Ben oui, un moment il y a un logiciel qui fait le travail, et c’est pdflatex.

      Sage

      Les images sont toutes en Tikz, qui possède un mécanisme pour ne pas recompiler les figures à chaque fois. Les PDF des figures sont fournies dans le dépôt Git.

      Le code Tikz est généré par phystricks (encore un module personnel) qui se base sur SageMath. Seuls les plus braves seront capables de modifier les figures.

      EPUB

      Nous avions parlé en 2016 de produire un livre numérique, mais il y a des problèmes techniques pas tout à fait évidents à surmonter. Ce ne sera sans doute pas pour tout de suite.

      Journal des modifications depuis septembre 2016

      Maths

      • ajout de pas mal de choses concernant la géométrie projective, entre autres sur le groupe circulaire ;
      • analyse numérique, méthode des différences finies, quelques schémas pour le Laplacien ;
      • sous‐groupes finis de SO(3) ;
      • une démonstration complète du fait que le flot de y’ = f(y,t) est Cp lorsque f est Cp (c’est le genre de choses que j’appelais plus haut une « large digression hors programme ») ;
      • beaucoup de corrections de fautes et d’imprécisions un peu partout. Entre autres, une signalée par un lecteur : le Frido 2016 prétendait, démonstration à l’appui, que tout anneau intègre est euclidien. Faux.

      Autres

      • Simplification du dépôt Git. Maintenant tous les fichiers \LaTeX concernant le Frido sont dans tex/frido. La compilation reste compliquée ; le fichier principal est mazhe.tex, mais faire pdflatex mazhe.tex ne fera pas ce que vous croyez.
      • Passage de 3 à 4 volumes. Un lecteur de la version papier m’a signalé qu’au‐delà de 500 pages, c’est compliqué à manipuler dans le train. Mais, dit‐il, autour de 500 pages, c’est vraiment la frime à sortir de son sac.
      • Le livre est en vente également chez lulu.com. Chez lulu, le prix de chaque volume est de 15 euros (20 € chez thebookedition.com), mais il n’y a pas les belles images de couverture de Pepper & Carrot.

      Journal des modifications depuis septembre 2017

      Ben oui, il y a déjà du nouveau. Je me suis rendu compte hier que la définition de L2 était fausse (les fonctions sont à valeurs dans C et non dans R).

      Bref, lisez attentivement et reportez‐moi toutes les fautes que vous trouveriez. La version de septembre 2018 pour les oraux de 2019 n’en sera que meilleure.

      Remerciements

      • Tous les contributeurs. Six sont recensés sur GitHub, mais il y en a pas mal d’autres qui ont apporté leur pierre soit directement dans les commentaires ici en 2016, soit par courriel.

      • Les mathématiciens qui ont mis leurs notes en ligne. La bibliographie a 362 entrées, presque toutes en ligne. Ce sont tous des textes que j’ai réellement utilisés à un moment ou un autre.

      • Les personnes qui ont écrit sur Wikipédia. J’ai lu énormément d’articles et, souvent, je me suis fixé sur les notations et définitions de Wikipédia. Si vous comptiez m’envoyer du fric pour le Frido, faites plutôt un don à Wikipédia.

      • Les dessins des couvertures chez thebookedition.com proviennent de Pepper&Carrot par David Revoy, publié sous licence CC-BY 4.0. Au passage, merci à lui.

      Lire les commentaires

    • Wazo, le fork de XiVO, prend son envol (Dépêches LinuxFR)

      La distribution de téléphonie sur IP (PABX/IPBX) basée sur Debian et Asterisk nommée XiVO a souffert d’une soudaine extinction de voix : le site Web xivo.io et le projet GitHub ont été fermés récemment par la société Avencall. Celle‐ci détient toujours la marque XiVO et réside maintenant sous le nom de domaine xivo.solutions. (NdM.: voir ce commentaire de avencall : les sources de XiVO sont désormais sur un projet Gitlab et une version est à venir pour la fin d'année).

      Un divergeance (fork) du projet a été créée sous le nom de Wazo et les sources sont de nouveau disponibles sur GitHub. Un groupe de cinq développeurs, dont Sylvain Boily (l’initiateur du projet XiVO en 2005) a repris la gestion du nouveau projet.

      Wazo a sorti sa première version Wazo 16.16 en décembre 2016, basée sur XiVO 16.13. Vous pouvez télécharger l’image ISO sur le miroir de Wazo et une procédure de migration XiVO vers Wazo est disponible.

      Ça mange quoi en hiver, Wazo ?

      Wazo est donc un serveur de téléphonie IP basé sur Asterisk diffusé sous licence GPL v3. Il permet de gérer la téléphonie d’une entreprise avec les appels entrants, appels sortants, renvois d’appel, messageries vocales, chambres de conférence, un centre de contact modeste, de contrôler ses appels à partir de son ordinateur (CTI) et offre nombre d’API REST pour intégrer tout ce petit monde dans d’autres systèmes logiciels. À travers ces API, Wazo se veut une plate‐forme de téléphonie que vous pouvez vous approprier et autour de laquelle vous pouvez développer.

      Pourquoi le nom Wazo ?

      Wazo est tout simplement un homophone de « oiseau », principalement à cause de la mythologie du phœnix, de la renaissance d’un projet et la symbolique de prendre son envol. Pour cette raison, le projet se nomme Wazo et son nom de version pour 2017 est Phoenix. Les développeurs signalent que tout jeu de mot est le bienvenu.

      Pourquoi un fork hostile ?

      La raison principale est une divergence de vision à long terme, les développeurs de Wazo expliquent la leur :

      Nous croyons fermement que la téléphonie devrait être accessible partout : quels que soient l’appareil, l’application, l’environnement logiciel que vous avez, vous devriez pouvoir appeler qui vous voulez, quand vous voulez. Pour accomplir cela, nous voulons un logiciel de téléphonie qui soit facile à mettre en place, facile à intégrer à d’autres logiciels, scalable et extensible à volonté.

      Wazo 16.16, nouvelle version, qu’est‐ce qu'elle apporte ?

      La nouvelle version de Wazo est arrivée lundi 12 décembre 2016, et elle apporte quelques nouveautés :

      • la migration de XiVO vers Wazo ;
      • la prise en charge du codec Opus ;
      • une meilleure documentation des API REST ;
      • une nouvelle API REST pour les interconnexions SIP avec les opérateurs et la gestion d’appels sortants ;
      • une nouvelle API REST pour les groupements d’appels (plusieurs téléphones sonnent sur le même numéro) ;
      • une nouvelle API REST pour les chambres de conférence ;
      • une nouvelle API REST pour les menus vocaux ;
      • une nouvelle API REST pour les messages vocaux utilisateur ;
      • une gestion plus souple du carnet d’adresses ;
      • amélioration de l’interconnexion de plusieurs serveurs Wazo pour partager les contacts.

      Wazo en 2017, quel plan de vol ?

      Pour l’année 2017, l’équipe prévoit notamment :

      • d’ajouter une nouvelle interface Web d’administration, plus moderne et plus facilement extensible ;
      • de continuer le développement des API REST pour piloter l’intégralité du projet ;
      • de fournir des interfaces web et mobile pour les utilisateurs ;
      • de continuer son approche scalable pour une vision Cloud (PaaS ou SaaS) ;
      • et, bien sûr, d’être à l’écoute de la communauté et de répondre à ses préoccupations premières.

      Comment on finance les graines ?

      Comme tout projet logiciel, il faut bien sûr financer le temps de développement et l’équipe nous fait savoir qu’ils ont plusieurs idées dans les cartons. Ils souhaitent rentabiliser un modèle logiciel libre en fournissant du service, du développement, mais aussi apporter une nouvelle approche sur le modèle de commercialisation, sans utiliser les mécanismes retrouvés actuellement dans des projets à double licence. Donc, pas de fonctionnalités payantes à l’horizon, comme ce qui fait grincer du bec chez les utilisateurs de FreePBX ou Elastix, d’autres projets libres de téléphonie sur IP…

      Lire les commentaires

    • Extraire les sous-titres des enregistrements de la TNT HD (Journaux LinuxFR)

      Avec la fin de la définition SD pour la TNT en France, il devenait urgent pour l'amateur de VOST que je suis de comprendre comment récupérer les sous-titres des flux HD, le brave Project X ne traitant à ma connaissance que les flux SD.

      En fait, l'outil miraculeux existe, il s'appelle SubtitleEdit, mais malgré des recherches fréquentes, je n'ai appris son existence que récemment.
      En plus, il y a une petite astuce à utiliser, car il ne reconnait pas directement les flux de sous-titres de mes enregistrements au format ts (alors que dans la doc, on a l'impression que oui), cependant on s'en sort en extrayant le flux soi-même avec ffmpeg.

      J'explique les manipulations sous Ubuntu, mais ce n'est pas très distribution-dépendant.

      Installation

      1) quelques paquets à installer:
      sudo apt-get install ffmpeg mono-complete libhunspell-dev tesseract-ocr-fra tesseract-ocr-deu

      2) Télécharger SubtitleEdit
      https://github.com/SubtitleEdit/subtitleedit/releases
      Il faut choisir la version portable
      Aujourd'hui, c'est le fichier SE3411.zip qui convient

      3) Dézipper le fichier zip dans votre répertoire utilisateur
      s'y rendre, puis
      cd Tesseract/tessdata
      ln -s /usr/share/tesseract-ocr/tessdata/fra.traineddata
      ln -s /usr/share/tesseract-ocr/tessdata/deu.traineddata

      Ceci pour bénéficier de reconnaissance de caractère plus adaptée pour allemand, français.

      Utilisation

      1) On repère la piste de sous-titres voulue avec
      ffmpeg -i fichier.ts

      2) On extrait la piste avec ffmpeg
      numero= # ce que vous avez repéré
      ffmpeg -i fichier.ts -map 0:$numero -scodec copy fichier_extrait.ts

      3) On lance SubtitleEdit
      mono repertoire_de_l_executable/SubtitleEdit.exe fichier_extrait.ts

      La fenêtre OCR de reconnaissance de caractère s'ouvre automatiquement.
      On lance la reconnaissance, après avoir sélectionné la langue, on ferme la fenêtre OCR, puis on sauve au format de sous-titres voulu. C'est fini !

      Lire les commentaires

    • Wilber Week, GIMP, interviews des développeurs et sortie de 2.10 à venir ! (Dépêches LinuxFR)

      Vous le savez, on travaille dur sur GIMP. Le mois dernier, les contributeurs principaux se sont retrouvés en Espagne pour une semaine de hacking intense : la Wilber Week. Très sympathique semaine, dans une vieille maison, une résidence d'artistes au milieu de la nature et chauffée au feu de bois.

      J'ai déjà écrit un compte-rendu sur l'évènement, mais je vous fais un résumé des points importants (en seconde partie). Et il y a un appel à voter aussi…

      Wilber Week

      flatpak

      GIMP distribuera un flatpak dès la version 2.10, j'en reparlerai plus tard.

      Règles de sortie

      Pour accélérer la sortie, on a décidé d'alléger nos règles de sortie. En particulier, on autorisera désormais les sorties de versions mineures avec de nouvelles fonctionnalités. À terme, je souhaiterais un cycle de sortie continue, comme d'autres programmes (j'en parlais déjà en 2014) le font déjà.

      Pour comprendre un peu le fond du problème, nous avons des fonctionnalités vraiment cool en réserve, codées, incluses, mais non totalement finies (il arrive que des contributeurs nous balancent des patchs puis disparaissent dans la nature ; que dis-je "il arrive", c'est le plus courant !). Dans certains cas, elles sont juste trop lentes pour être utilisables, parfois il y a des bugs d'UI, parfois elles vont carrément faire planter le programme. Ce sont des bloqueurs de sortie. Bien sûr, on peut simplement les désactiver, mais cela signifie alors attendre une prochaine sortie de majeure. Or à notre rythme de sortie, ça signifie repousser de plusieurs années ! C'était assez décourageant et on avait alors tendance à repousser la majeure en espérant que quelqu'un corrige les fonctionnalités problématiques.
      Autoriser de nouvelles fonctionnalités en version mineure va donc compléter nous débloquer car on aura alors beaucoup moins de remords à désactiver les fonctionnalités dont nous ne sommes pas contents. Celles-ci pourront revenir plus tard, même dans une mineure (si quelqu'un les finit).

      GIMP 2.10

      Une autre bonne nouvelle (conséquence de la précédente) est que nous souhaitons donc sortir GIMP 2.10 cette année ! Youhou ! On ne l'avait pas annoncé officiellement mais aujourd'hui, nous venons de publier une interview du mainteneur, que j'avais faite lors de la Wilber Week et qui est le premier document officiel donnant l'information d'une sortie prévue en 2017.

      Pour info, cette interview est un de mes projets pour redonner une vie communautaire autour de GIMP. J'ai déjà réalisé 4 interviews (c'est la première en ligne) et prévoit d'étendre et d'en faire beaucoup plus. Des interviews de développeurs (GIMP ou des projets en lien, comme GEGL…), mais aussi de contributeurs non-développeurs, d'artistes qui se servent de GIMP, etc.

      Interviews

      D'ailleurs si jamais vous souhaitez traduire l'interview sur LinuxFR, n'hésitez pas à y participer dans l'espace de rédaction. Elle est en CC by-sa, comme tout ce que je fais (et c'est aussi la politique de licence du site gimp.org, même si je crois qu'on n'a pas encore ajouté l'info en pied-de-page. Mais en l'occurrence, l'auteur là, c'est moi et je vous le dis en direct par écrit ;p).
      GIMPers à Wilber Week, Montserrat

      Financement

      Je conclurai ces bonnes nouvelles en rappelant que vous pouvez financer le projet ZeMarmot soit par Tipeee (EUR), soit par Patreon (USD). Cela nous permettrait à terme de financer notre développement de GIMP, donc de vivre du logiciel libre tout en accélérant les sorties et la stabilité de GIMP, de sortir des films d'animation sympas, de faire vivre la communauté avec des interviews, des ateliers, etc. :-)

      Votez GIMP, sur le Prix de l'Initiative Audiens

      À plus petite échelle, je rappelle que vous pouvez toujours voter pour nous (pendant encore 2+ semaines) au Prix de l'Initiative Audiens. C'est un financement moins pérenne que le financement mensuel, mais ça aide quand même si on gagne et ça se fait en un clic. ;-)

      Lire les commentaires

    • Actualités Sympa (Dépêches LinuxFR)

      Au début de l’année, nous annoncions le hackathon pour le vingtième anniversaire de Sympa (Système de multi‐postage automatique) sur ce site. Annonce qui avait posé question puisque Renater n’était alors pas associé à l’événement.
      logo sympa

      Si l’association de Renater est tardive, elle a été importante : l’organisme a en effet proposé et pris en charge la présence de David Verdin (meneur du projet de 2011 à 2016) lors de l’événement et a depuis aidé activement à transformer la gouvernance et le fonctionnement du projet vers son fonctionnement actuel (accès aux infrastructures et aux données relatives à la documentation, la traduction, l’hébergement du code source…).

      Ainsi :

      • GitHub héberge maintenant le code et le suivi de bogues (c’est expérimental), l’ancien système de suivi a été fermé ;
      • Soji Ikeda (contributeur de longue date) est le nouveau responsable des publications, on compte huit publications (dont trois nouvelles versions stables) depuis le hackathon ;
      • le site et la documentation sont en cours de refonte et utiliseront désormais les pages GitHub.

      Nous avons au passage créé les canaux IRC #sympa et #sympa-fr sur freenode.

      Cet été, c’est encore Renater qui finance le stage de Ludovic Muller (déjà contributeur) pour commencer l’implémentation de la maquette réalisée pendant le hackathon. Avec l’aide de Quentin, il expérimente l’utilisation de composants Web dans l’interface actuelle.

      Ces mois de collaboration fructueuse avec Renater m’ont permis de découvrir une réelle volonté d’investissement dans le logiciel libre. C’est donc avec un immense plaisir que j’ai accepté la proposition qu’ils m’ont faite de les rejoindre. Je suis développeur Sympa et chargé de la valorisation et de la dynamisation du patrimoine open source de leur communauté depuis le 1er octobre.

      Autre bonne nouvelle : David Verdin, est de retour à Renater depuis début septembre pour se consacrer à temps plein à Sympa, sa communauté et sa promotion. Avec presque deux ETP (équivalent temps plein), c’est la première fois depuis longtemps que le projet dispose de tels moyens permanents.

      Comme le monde est petit, Guillaume Rousse (contributeur de Sympa, entre autres, lorsqu’il travaillait à l’Inria) a rejoint l’équipe sécurité de Renater.

      Nous serons présents lors de l’Open Source Summit de Paris et probablement sur d’autres événements comme le FOSDEM et la prochaine Perl Conference.

      Lire les commentaires

    • XCP-ng une alternative open source à XenServer (Dépêches LinuxFR)

      Xen Cloud Platform était l’équivalent libre et open source de XenServer avant que l’hyperviseur de Citrix ne soit lui‐même passé sous licence libre.

      Mais, la version 7.3 de XenServer a déplacé de nombreuses fonctionnalités auparavant gratuites dans les versions standard et entreprise — payantes, donc.

      En conséquence, une solution communautaire est de nouveau nécessaire : XCP-ng en devient donc le projet.

      Qui s’occupe de ce projet ?

      Contrairement à la première version de XCP, ce projet n’est pas supporté par Citrix. C’est un projet 100 % communautaire dont les premiers contributeurs sont :

      • Olivier Lambert (du projet Xen Orchestra — principal porteur du projet XCP-ng) ;
      • John Else ;
      • Nick Couchman ;
      • Jon Sands ;
      • Mike Hidalgo.

      Le projet est ouvert à tous et si vous souhaitez contribuer, vous pouvez contacter l'équipe de Xen Orchestra pour demander à participer à XCP-ng.

      Quels objectifs ?

      L’objectif principal du projet est de fournir une solution équivalente à XenServer (c’est‐à‐dire intégrant les fonctionnalités de la XAPI) dans une solution complètement communautaire et non dépendante de Citrix, ce qui inclut :

      • une solution compatible à 99,99 % avec XenServer (autant que possible), permettant par exemple de transférer des machines virtuelles depuis XenServer vers XCP-ng et vice versa ;
      • une solution compatible à 99,99 % avec les solutions de gestion libre pour XenServer (comme Xen Orchestra) ;
      • une documentation complète et fonctionnelle de sorte que tout le monde puisse utiliser les sources ;
      • une solution complètement indépendante des dépôts Citrix/XenServer.

      Le planning

      Le planning estimatif du projet inclut trois phases :

      1. créer un prototype fonctionnel et une documentation de compilation — Q1 2018 ;
      2. créer le dépôt RPM et un méta‐paquet ;
      3. ajouts et améliorations (ex : pilotes ZFS, pilote GlusterFS).

      Comment participer ?

      Aide directe (et technique)

      Les personnes avec de l’expérience dans les champs suivants sont les bienvenues :

      • construction de logiciels et de paquets (préférablement orientée CentOS RPM et SRPM) ;
      • connaissance de la XAPI et OCaml ;
      • connaissance approfondie de XenServer en général.

      Aide indirecte

      Les principaux contributeurs seront rémunérés pour le travail initial, construction/compilation, documentation et process. Tout ça aura donc un coût en temps et en argent. Les contributions seront donc les bienvenues et une campagne de financement participatif verra sans doute le jour.

      En outre, tester la solution lors des différentes phases sera également d’une grande aide.

      Lire les commentaires

    • Retour d’expérience (et tuto) XMPP (Journaux LinuxFR)

      Bonjour nal

      J'écris ce journal pour décrire mes manipulations pour utiliser XMPP. Cela pourra peut-être aider des personnes qui ont la même config que moi, et j'aimerai récupérer des remarques ou des conseils.

      XMPP

      XMPP, plein de journaux en parlent, il y a quelques polémiques (compliqué à cause des XEP) mais je suis plutôt convaincu.

      Aujourd’hui, j'ai décidé de sauter le pas, et de l’utiliser pour remplacer les SMS (avec les contacts "compatibles" bien entendu !).

      Je ne m'attendais pas à devoir écrire un tutoriel pour savoir utiliser ça…

      L’environnement

      Je souhaite dans un premier temps faire communiquer 2 personnes, avec des périphériques android, Ubuntu (LTS 16.04 et 17.10) et Windows. Plutôt banal donc.

      J’ai une brique internet avec Yunohost installé si besoin.

      Hébergeur

      Il faut d’abord choisir un hébergeur.

      Auto hébergement

      J’ai une brique internet, avec donc un petit processeur ARM, pourquoi pas installer un serveur XMPP dessus ?
      Ce journal m’indique 2 logiciels coté serveur : Prosody et Ejabberd. Le premier étant indiqué plus léger que le second.
      Malheureusement, un commentaire dit que l’installation n’est pas si simple d’autant plus que l’appli n’est pas packagée pour yunohost.

      Hébergeur sur l’Internet

      Je trouve dans ce journal une liste de serveur conseillés (et une autre liste ici) et je tombe donc sur jabberfr.org. Ce site fait partie des CHATONS de framasoft, c’est rassurant.
      J’ai un doute quand je vois ici que

      JabberFR n’est pas un serveur Jabber mais une fédération.

      Finalement, je mets quelques minutes à comprendre que c’est bien un serveur jabber pour les adresses @jabber.fr et que le formulaire d’inscription est ici : im.apinc.org/inscription (pas évident tout ça !).

      Client Android

      J’installe Conversation, indiqué par ce journal.

      Comme d’habitude, l’installation se passe bien sous Android (depuis F-Droid pour ma part).
      Conversation me permet de créer un compte depuis jabber.fr. Le message qui indique que le pseudo existe déjà est sans rapport avec le problème, mais ça fonctionne.
      Je tombe alors sur 3 méthodes pour chiffrer les messages : OMEMO, OTR, et OpenPGP. Ce site et ce journal me convainquent d’utiliser OMEMO (dommage qu’il n’y ai pas de "Server side archive").
      Je galère un peu à comprendre comment l’utiliser sur Conversation. Je scan des qr code OMEMO d’un tel avec l’autre, j’importe la clé dans Conversation, mais ca ne fonctionne pas (message "pas de clé pour le contact").
      Je passe donc avec OTR et la encore des scan de qr code à faire, mais ca fonctionne.

      Client PC

      Je choisi Gajim (au design très vieillot) car il est souvent cité en référence (ici et la par exemple).

      Alors pour installer un logiciel sous ubuntu, j’ai toujours 2 références : le wiki ubuntu et le site de l’éditeur. D’abord sur le PC Ubunut 17.04 apt install gajim, c’est facile comme d’hab !

      Lancement, le compte est bien trouvé,… tentons avec OMEMO, …, il faut un plugin, mais pas de souci, il y a un gestionnaire de plugin dans Gajim.
      Par contre je ne peux pas l’activer, et l’interface me dit d’installer les paquets suivants (1 par 1, et il faut redémarrer gajim entre chaque installe sinon c’est pas drôle) : python-setuptools python-axolotl python-qrcode python-cryptography.

      Bon, je fouille un peu les options, et ça fini par marcher en OMEMO. Et Conversation se met aussi à fonctionner avec OMEMO tout seul, bonne nouvelle !

      Pour l’install sur le PC en Ubuntu 16.04, je laisse temporairement tomber :
      Je vois que la version de Gajim des dépôts (0.16.5) n’est pas compatible avec le plugin OMEMO … Your Gajim version is too old, OMEMO needs 0.16.6 or higher.
      Bon, je chercherai un PPA plus tard…

      Futur

      Il me reste à tester Movim pour android et Dino pour Ubuntu.
      Aucune idée de la compatibilité des différentes fonctionnalités avec mes clients existants (soit j’essaie de comprendre ce qui signifient chaque XEP, soit je tente et je vois ou ca bloque…).

      Avant d'avoir trop de contactes, j'aimerai bien utiliser une adresse xmpp avec mon nom de domaine au lieu de @jabber.fr

      Voir ce qui fonctionne avec le client XMPP intégré de thunderbird

      Enfin, je jetterai un œil à Matrix. Même s’il n’y a pas la compatibilité de XMPP, ils ont l’avantage (à mes yeux) d’avoir un partenariat avec Purism pour le smartphone Librem 5.

      Une aprem pour ça, et ce n'est fini.
      Ce n'est pas encore une solution clé en main, XMPP !

      Alors, des conseils pour la suite ?

      Lire les commentaires

    • Quel IDE pour quel langage (Journaux LinuxFR)

      Il y a trop longtemps, le débat sur les IDE se cristallisait entre VI et EMACS. Sur l'un, il fallait appuyer sur 3 touche en même temps, l'autre l'une à la suite de l'autre.

      Par hasard, j'ai appris Emacs, et changer de réflexe sur les raccourcis est très compliqué (genre ctrl-x rt). J'ai beaucoup codé en C, et ocaml et perl dessus avec succès.

      Puis j'ai fait du Java avec Eclipse. Il me manquait une tonne de fonctionnalité d'édition de base par rapport à Emacs, mais se rajoutait un des fonctions nouvelles très puissantes, comme l'auto-complétion depuis les library, qui suivait le typage et la syntaxe, la documentation par le survol (pas besoin d'aller chercher un fichier particuliers), le reformatage de code (factorisation de fonction depuis un bout de code). De retour sous Emacs, tout cela me manque.

      J'ai fais aussi un détour sous Visual Studio pour le C++, où la navigation entre fichier (clic d'une fonction pour avoir sa déclaration), et le debuging visuelle était vraiment agréable.

      Depuis que je code en go, j'aime de moins en moins Emacs, et sa tonne de fonction dont il faut se rappeler le nom pour les utiliser, si encore on sait qu'elle existe genre "global-auto-revert-mode".

      Dans la grande étude de codingame, il parle des IDE préférés de leur codeur. cf : http://publications.codingame.com/codingame-2018-developer-survey/what-developers-want

      J'ai du mal à imaginer un IDE sans associer le langage qui va avec. Le support de C++ dans Eclipse n'est pas du tout au même niveau que le Java, par exemple.

      Visual Studio 42% Univers Microsoft
      IntelliJ 30% Java
      Visual Studio Code 27% de tout
      Eclipse 25% Java
      Atom 16% de tout
      PyCharm 15% Python
      NetBeans 9% Java ?
      PhpStorm 7% PHP
      Code::Blocks 7% C/C++/fortran
      Xcode 6% Univers Apple
      Cloud9 3% de tout dans le cloud
      Other 16%

      (désolé pour le vrac mais linuxfr ne supporte pas le fait d'embarquer des bouts de code externe :/)

      Pour vous quel sont les couples "ultimes" IDE-langage ? Qu'est-ce que vous conseillez ? Qu'est-ce que vous déconseillez formellement ?

      Lire les commentaires

    • Softphone et SIP (Journaux LinuxFR)

      Sommaire

      Salut Nal,

      je fais le retour des mes expériences d'utilisation des logiciels softphone pour utiliser une ligne SIP comme promis dans un post du forum.

      Mes Exigences

      Ce que je cherche c'est de pouvoir téléphoner avec mon ordinateur, en utilisant ma ligne SIP. A la création de ma ligne, j'avais pris un téléphone physique car je pensais que c'était mieux, mais au final, je ne téléphone que quand je suis devant mon ordinateur … et si je n'y suis pas, la plupart du temps, je n'ai pas envie de répondre (il y a un répondeur et mon mobile). Cela me permettra également de déplacer mon "téléphone" simplement : en déplacement, j'aurai juste besoin de prendre mon ordinateur portable (ce que je fais déjà). Je n'aurai plus besoin de déplacer également le téléphone.
      Pour information, j'utilise Xubuntu 16.04 : les tests ci-après ont donc été réalisés sur ce système.

      De plus, je veux pouvoir aussi utiliser la ligne depuis mon smartphone … pour ne pas avoir à systématiquement démarrer mon ordinateur (je sais, cela contredit le paragraphe précédent). Je n'ai pas testé la version Android des softphones mais tous (à part Ekiga) ont une version Android (et sur d'autres plate-formes également). Le principal est de savoir que c'est possible. Il n'est pas impératif d'utiliser le même logiciel sur mon ordinateur et sur mon smartphone, mais je suppose que c'est mieux car je trouverai une interface assez semblable.

      Les fonctions que j'attends d'un softphone, c'est de pouvoir téléphoner ;-) et de recevoir des appels. Mais aussi qu'il y ait un répertoire, ainsi qu'un historique des appels avec la durée (afin de comptabiliser mon temps). J'aimerai également qu'il ait la possibilité de gérer les double appels … mais je n'ai pas testé ceci.

      Idéalement, j'aurai voulu aussi la possibilité de passer un appel depuis mon répertoire sur Thunderbird en un clic. On verra que Telify le permet pour tout logiciel (et également depuis Firefox).

      Mes tests

      Par ordre de test chronologique :

      Zoiper

      Installation un peu bizarre (à la Windows) avec un exe (téléchargé depuis un .tar.gz) qui fait l'installation.
      Pour désinstaller, il faut lancer le programme de désinstall depuis /usr/share/Zoiper/Uninstall (pas de raccourcis ou d'icônes créés durant l'install).
      Complet (appels, réception, historique avec temps passé, carnet d'adresses) et relativement simple à utiliser mais pas de version en Français. Cependant, il n'est pas libre mais propriétaire (contrairement à ce que m'avait annoncé le support OVH, qui me l'a recommandé).
      Est disponible sur différentes plate-formes (Linux, Windows …) y compris Android.
      Il existe un plugin pour Thunderbird qui ajoute un bouton pour faire un appel avec Zoiper (mais pas dans les fenêtres/onglets de ContactTab - un plugin pour rechercher facilement des contacts et qui les affiche dans une fenêtre spécifique).

      Linphone

      Installation classique (paquet).
      Complet (appels, réception, historique avec temps passé, carnet d'adresses)
      Ne fonctionne pas très bien avec Telify (cf. plus loin) : il faut, parfois, afficher le gui manuellement (clic sur icône de Linphone). De plus, il n'est pas démarré automatiquement au démarrage du système, il faut l'ajouter dans les logiciels à démarrer.

      Jitsi

      Installation : il n'est plus dans les paquets Ubuntu/Debian, mais on peut utiliser le dépôt de Jitsi. Tout fonctionne directement sans avoir à choisir les périphériques audio (contrairement aux logiciels précédents).
      Complet (nombreux protocoles) mais ne permet pas d'éditer un numéro déjà composé.
      Ne fonctionne pas avec Telify : le numéro est envoyé mais la connexion téléphonique ne se fait pas (probablement quelque chose à configurer)

      Ring

      Installation avec un dépot dédié.
      Interface déroutante : je n'ai pas trouvé comment composer un numéro !
      Il est possible de l'utiliser avec SIP (même si le protocole Ring est mise en avant).
      J'ai eu un appel et je n'ai pas su décrocher. Je l'ai désinstallé !

      Ekiga

      Installation très simple (dans les dépôts).
      Je n'ai pas réussi à entendre une conversation ou à émettre une conversation (pourtant le vue-mètre du micro bougeait … mais pas celui du haut-parleur).
      A postériori, il est possible que cela soit du à un problème de codec utilisé sur la ligne.

      Yate

      Il a l'air intéressant, mais je n'ai pas pu l'installer : il n'y a pas de paquets à jour pour Ubuntu.
      J'aurais pu compiler les sources, mais s'ils ne se donnent pas la peine de maintenir le paquet de leur logiciel, ça ne me donne pas une bonne impression du logiciel.

      Vous pouvez trouver un tableau sympa sur wikipedia.

      Configuration de Telify

      Ceci permet d'initier des appels depuis Thunderbird, en un clic, avec Linphone (et les autres aussi).

      Il faut créer une nouvelle entrée pour l'url scheme sip (et tel pour firefox) :
      Apparemment selon le Bureau utilisé, on pourrait ajouter la ligne suivante dans ~/.local/share/applications/defaults.list ou dans ~/.local/share/applications/mimeapps.list
      x-scheme-handler/sip=linphone-call.desktop

      Mais il est plus simple d'utiliser xdg-mime :
      $ xdg-mime default linphone-call.desktop x-scheme-handler/sip

      Et on créera un linphone-call.desktop en copiant /usr/share/applications/linphone.desktop en /usr/share/applications/linphone-call.desktop.
      Puis on modifie /usr/share/applications/linphone-call.desktop en modifiant la ligne Exec en
      Exec=linphone -c %U
      et en ajoutant à la fin du fichier :
      MimeType=x-scheme-handler/sip

      Puis on télécharge Telify : mieux que TBDialOut car il fonctionne aussi dans les fenêtres/onglets de ContactTab de Thunderbird et également dans Firefox.

      J'ai suivi les instructions trouvées sur le forum d'Ubuntu … en particulier pour la Custom URL … mais cela ne fonctionne pas très bien avec Telify, par contre cela a l'air de fonctionner avec TBDialOut.

      Avec les 2, en fonctionnement par défaut, le numéro est composé, mais préfixé de sip: et pas postfixé par le registrar. Pour postfixer le registrar avec sip.ovh.fr (dans mon cas), il faut utiliser une Custom URL … mais l'appel à Linphone est bizare, parfois l'interface n'est pas affiché et parfois, c'est un ancien numéro qui est affiché.
      Bref, il faut que je creuse encore un peu

      Mon Choix

      Au final, j'ai choisi Linphone. J'aimerai arriver à le faire fonctionner avec Telify et apparemment, c'est possible. Sinon je me contenterai de TBDialOut.

      Lire les commentaires

    • Toulouse Hacking Convention : 9 mars 2018 (Dépêches LinuxFR)

      Le 9 mars 2018, l’ENSEEIHT de Toulouse accueillera la seconde édition de la Toulouse Hacking Convention.

      Il s’agit d’une journée de conférences tournant autour de la sécurité, suivie par une soirée/nuit de capture du drapeau (Capture The Flag ou CtF) constituée d’épreuves dans de multiples domaines (cryptographie, ingénierie inverse, exploitation de vulnérabilités, failles Web…). Le tout dans une ambiance conviviale et avec des membres de la communauté du Libre. :)

      Il s’agit de la seconde édition, la première ayant été un franc succès puisque nous avons accueilli autour de 150 participants aux conférences, et 80 participants au CTF.

      Les conférences de l’année dernière allaient de la rétro‐ingénierie de puces en regardant leurs transistors, à la désobfuscation automatique de code, en passant par un jeu de rôle de sensibilisation à la sécurité informatique. Les vidéos sont d’ailleurs disponibles sur YouTube.

      Inscrivez‐vous rapidement, les inscriptions vont fermer d’ici peu !

      Le programme de cette année n’est, à ce jour, pas finalisé ; mais il sera annoncé sous peu. Vous pouvez déjà trouver une première version sur le site.

      Lire les commentaires

    • Mes péripéties avec la répétition espacée (Journaux LinuxFR)

      Sommaire

      Bonjour Nal,

      Aujourd'hui, je viens pour te raconter mes péripéties avec la répétition espacée et la naissance de morji, un logiciel de répétition espacée, tout comme mnemosyne ou anki, mais comme alternative minimaliste en mode texte dans le terminal. Avant de te raconter le pourquoi du comment de morji, je vais te raconter un peu le concept de répétition espacée, ainsi que te montrer un peu le principe des algorithmes qui font marcher l'idée.

      La répétition espacée : qu'est-ce donc  ?

      L'idée de la répétition espacée part d'un constat expérimental : lorsqu'on apprend quelque chose, peu importe quoi, on a besoin de réviser pour ne pas l'oublier, et l'intervalle entre révision et révision peut s'allonger avec le temps — l'expérience suggère une progression exponentielle. Si je t'apprends le nom d'une plante aujourd'hui et que je te repose la question dans un mois, tu auras sans doute oublié d'ici là. Si je te repose la question demain, il y a des chances que tu t'en souviennes, et si je te repose la question une semaine après, il y a de bonnes chances aussi ; si après ceci j'attends un mois pour t'embêter de nouveau… et bien probablement aussi !

      Tu me diras, rien de bien extraordinaire là-dedans. Peut-être pas, et encore… Mais ce qui est sûr, c'est que, du coup, il faut une certaine organisation si l'on veut retenir un maximum de choses tout en faisant un minimum d'efforts. Le drame, c'est que choisir manuellement à l'intuition ce qu'il faut réviser et quand, c'est pas toujours évident.

      Un peu d'automatisation !

      C'est là qu'on se dit, et si on pouvait faire faire ce travail à une machine ? Il se trouve que ça s'applique pas facilement à tout type de connaissance, mais il y a des cas où on peut, en particulier lorsque les faits à se remémorer se structurent facilement en cartes-mémoires du type question/réponse. Par exemple :

      Question: nom de plante avec de gros piquants dangereux
      qui pousse dans le désert
      Réponse: cactus
      

      L'interaction (version naïve) se fait ainsi :

      • le programme nous pose la question ;
      • on réfléchit à la réponse ;
      • on affiche la réponse ;
      • on dit à la machine si on s'en souvenait.

      Si on s'en souvenait (on a pensé à « cactus »), la machine calcule alors la date de la révision suivante en tenant compte de l'intervalle entre les deux révisions précédentes. Sinon (on a pensé à « rose » ou « chardon » ou à rien du tout), les intervalles repartent de zéro pour ce fait, qu'il faut remémoriser.

      Ces idées ont donné naissance à des algorithmes. Le premier semble être le Système Leitner, qui date des années 70 et qui ne semble pas être vraiment utilisé aujourd'hui dans des logiciels, mais qui par contre avait l'avantage de pouvoir s'utiliser à la main avec des boîtes. Cet algorithme classait les faits par groupes (les boîtes) : le premier groupe contenait les faits non mémorisés ou oubliés, le second les faits mémorisés qui ont été révisés une fois, et ainsi de suite. Plus le numéro de groupe était élevé, moins la carte était révisée, suivant une méthode de calcul artisanale qui utilisait une taille maximale pour chaque groupe : le premier groupe était de taille 1, le deuxième de taille 2, puis 5, puis 8, etc. C'est seulement lorsqu'un groupe était « plein » qu'il fallait réviser des cartes de ce groupe pour les faire passer au groupe suivant.

      L'inconvénient du procédé, même implémenté dans un logiciel (parce que les boîtes ça prend de la place mine de rien), c'est qu'il est un peu binaire. Des fois on se souvient presque (on a pensé « kaktus »), ou alors on se souvient, mais on a eu beaucoup de mal, ou alors c'était trop facile. Du coup, l'idée est venu de demander à l'utilisateur d'évaluer lui-même sa performance, soit à l'aide d'un nombre entre 0 et 5 (mnemosyne ou SuperMemo), soit de façon plus qualitative (anki). En fonction du résultat, l'intervalle de révision suivant est ajusté par le logiciel qui maintenant a une idée de la difficulté que présente ce fait particulier pour l'utilisateur.

      Vers des algos plus évolués : exemple de SM2

      Un deuxième algo plus évolué est alors apparu, appelé SM2, du nom de SuperMemo2, logiciel pas libre qui a lancé l'idée. Depuis, son algo s'est compliqué sensiblement pour tenir compte finement du fait que certains faits sont liés entre eux et autres subtilités, et le logiciel est probablement devenu une usine à gaz, mais l'idée de fond reste la même. En fait, les logiciels mnemosyne et anki utilisent simplement une version modifiée de SM2 qui marche bien en pratique et leurs auteurs semblent sceptiques sur les versions suivantes de l'algo (ça va jusqu'à SM11 ou plus). Il y a aussi un mode Emacs qui fait de la répétition espacée et qui permet d'utiliser SM5, même si par défaut ça utilise encore le système Leitner si les infos sur le site ne sont pas obsolètes. Il y a aussi Org-Drill (Emacs encore) qui fait du SM5 par défaut.

      L'algorithme SM2 original est une simple traduction des idées ci-dessus : si I(n) représente l'intervalle entre la (n-1)-ième répétition et la n-ième, alors :

      • I(1) = 1
      • I(2) = 6
      • Pour n > 2 : I(n) = I(n-1) * facilité.

      facilité est un paramètre propre au fait qui évolue au fil des notes successives données à chaque révision. Initialement il vaut 2.5, puis il évolue autour en fonction des notes. Le paramètre a une valeur minimale de 1.3, pour éviter des révisions trop fréquentes d'un même fait : en pratique elles correspondent à des faits non-compris ou mal posés dont il faut revoir la présentation. Par exemple, anki propose 4 choix lors d'une révision :

      • On a oublié : l'intervalle est remis à zéro, la facilité laissée telle quelle ; si on a oublié ça veut pas forcément dire que c'était dur, des fois on oublie, c'est tout.
      • Ok, mais c'était dur : la facilité est diminuée (de 0.15 il me semble pour anki), et le nouvel intervalle tiendra compte de ceci.
      • Ok, juste comme il faut : la facilité ne change pas.
      • Ok, mais trop facile : la facilité augmente (0.10 pour mnemosyne, 0.15 pour anki de mémoire).

      Le détail de l'algorithme original et de la modification du paramètre de facilité peut être trouvé à la source (site qui, dit en passant, contient beaucoup d'articles intéressants sur la mémoire, bien que parfois un peu biaisés sans doute). Remarque annexe sur le document : Faut faire gaffe, car il y a une petite subtilité : le 5ème et 6ème points sont inversés dans mnemosyne et anki, c'est-à-dire qu'on ne modifie pas la facilité lorsqu'on a oublié. Ceci semble logique, car si on a oublié totalement un fait, ça veut pas forcément dire qu'en le réapprenant on va avoir des difficultés et, de plus, ajuster la facilité en variant les réponses affirmatives semble suffisant et plus raisonnable : l'algo original (si tant est que ce ne soit pas juste un bug du document) a tendance à faire plomber trop vite le taux de facilité suite à des échecs successifs lors de l'apprentissage d'une carte.

      Quelques améliorations

      Un souci avec le SM2 original, c'est qu'il suppose que l'utilisateur va apprendre tous les jours plus ou moins la même quantité de faits. En effet, si un jour on apprend 20 faits, et un autre on en apprend 50, ça veut dire que ces 20 faits seront révisés, à moins d'être oubliés, toujours aux mêmes dates avec les mêmes intervalles, et de même pour les autres 50 aussi : on se retrouve donc avec une charge de révision très inégale suivant les jours. Même en étant disciplinés, il arrive parfois de ne pas pouvoir faire ses révisions pendant plusieurs jours, par exemple, et créer ainsi sans faire exprès ce genre d'inégalités de charge.

      Les logiciels anki et mnemosyne introduisent un peu d'aléatoire dans l'algorithme pour résoudre ce problème. Plutôt que de faire réviser les 50 cartes le même jour, elles seront réparties sur les jours autour, avec une incertitude qui dépend de l'intervalle (5% pour mnemosyne, sauf pour les petits intervalles où des valeurs spéciales sont codées en dur).

      Il y a d'autres petites subtilités pour être un peu résistant aux vacances ou autres cas spéciaux : par exemple, si on se souvient d'un fait qu'on était censé réviser il y a une semaine, le nouvel intervalle doit tenir compte de la date de la vraie répétition, pas seulement de la date théorique mais, en même temps, si l'utilisateur a du mal, on peu préférer être plus conservateur sur le nouvel intervalle qu'en théorie : lors du calcul anki compte les jours de retard avec un poids plus faible qui dépend de la note ; mnemosyne se contente d'être conservateur si la note correspond à « c'était dur ». C'est des ajustements de bon sens, mais sans théorie vraiment derrière, pour autant que je sache.

      Une petite simulation !

      Pour se faire une idée de la charge de révision que l'on accumule, j'ai fait une petite simulation sur plus d'un an (500 jours). Tous les jours, 15 nouvelles cartes apprises, et quelques pourcentages pris un peu au flair (ça varie sans doute beaucoup suivant la façon de voter de la personne et le sujet) : chaque jour, 5% de cartes oubliées (mais réapprises le jour même de l'oubli), 2% classées difficiles, et 1% classées faciles. Au total, 7500 cartes sont mémorisées. On se retrouve avec un nombre de cartes à réviser par jour pour la semaine suivante qui ressemble à :

      88 88 76 85 86 79 56
      

      Un petit calcul permet de prévoir l'ordre de grandeur du résultat : en supposant de voter toujours « Ok, je m'en souviens bien », ça correspond à des intervalles (à randomisation et ajustements près) de 1, puis 6, puis à partir d'ici multiplier l'intervalle par 2.5, ce qui donne en moyenne entre 5 et 6 révisions par carte sur l'intervalle de 500 jours, donc en multipliant par le nombre de cartes nouvelles par jour, ça donne entre 5 * 15 = 75 et 90. Comme en pratique on oublie quand même des cartes, et la facilité c'est souvent un peu moins de 2.5, c'est en fait un peu plus, mais c'est le bon ordre de grandeur.

      Quelques types de cartes-mémoires

      Tout à l'heure, j'ai donné un exemple simple de question/réponse avec un cactus. Les logiciels gèrent en général plus de types de cartes-mémoire. En particulier, des faits que l'on veut être capable de retenir dans les deux sens. Par exemple, imaginons qu'on veut retenir le nom des capitales, on veut une question du genre :

      Question: France
      Réponse: Paris
      

      Mais peut-être qu'il peut être intéressant aussi d'avoir la question à l'envers aussi :

      Question: Paris
      Réponse: France
      

      En pratique on s'aperçoit souvent que ce n'est pas parce qu'on sait répondre à une question dans un sens qu'on sait le faire dans l'autre ! Les amateurs de langues le savent bien :) C'est pour cela que mnemosyne et anki sont capables de générer deux cartes-mémoires à partir d'un seul fait pour gérer ce genre de cas de façon commode.

      Une autre façon parfois pratique de représenter une question peut être le texte à trous :

      Question: [...] est la capitale de la France.
      Réponse: Paris
      

      Mais aussi :

      Question: Paris est la capitale de [...].
      Réponse: la France
      

      Pour ce genre de cartes, en pratique on écrit quelque
      chose comme :

      Question: [Paris] est la capitale de [la France].
      Réponse: la France
      

      …Et le logiciel génère à partir de ce seul fait les deux
      cartes-mémoires.

      D'un point de vue de l'algorithme, ça pose la question intéressante d'éviter de se voir demander les deux cartes le même jour, ce qui risquerait de fausser un peu la révision et la note attribuée à la deuxième carte. En pratique on utilise des solutions plus ou moins ad-hoc où on s'arrange pour ne pas mettre les deux le même jour.

      Morji

      morji c'est donc encore un autre logiciel de répétition espacée utilisant un SM2 modifié, comme anki et mnemosyne, mais dans le terminal et avec un minimum de dépendances. « Mnemosyne » est le nom d'une déesse grecque de la mémoire, « anki » signifie mémorisation en japonais ; pour rester dans le thème et faute de meilleures idées, « morji » signifie « se souvenir » en lojban.

      Une nimage d'abord

      https://bardinflor.perso.aquilenet.fr/morji/morji-screenshot.png

      Le début de l'histoire

      J'étais jusqu'à il y a peu un utilisateur relativement satisfait de mnemosyne. L'interface est plutôt simple, son concept de tags pour organiser les faits est flexible et, dans l'ensemble, le logiciel est assez orthogonal. Il a quelques défauts, parfois un peu lent pour certaines opérations, c'était quand même un peu trop clickodrome pour moi et, devoir écrire mes cartes sans vim, c'était un peu dur ; mais dans l'ensemble, c'est sympa.

      D'habitude j'utilise OpenBSD sur un fixe, mnemosyne est dans les paquets, donc tout va bien. Mais j'ai aussi une autre machine (un ordinateur portable) sur laquelle, pas de chance, OpenBSD détectait pas bien la carte réseau, du coup j'ai installé un Void Linux (il s'agissait de pas être trop dépaysé). Et là, c'est le drame. Mnemosyne n'était pas dans les dépôts. Paf.

      Je prends mon courage à deux mains, et j'essaie de compiler le truc. Je regarde les dépendances, certaines sont pas dans les dépôts. Qu'à cela ne tienne, c'est du python, j'installe ça avec pip… Après plusieurs itérations à installer de nouveaux paquets, c'est l'échec cuisant. Je commence à redouter des incompatibilités de versions, python 2 ou 3, je teste des trucs ; ça fait bien deux heures, j'abandonne et me dis que, quand même, les packageurs, c'est un peu des super héros, et que je serais mal barré sans eux.

      Ça m'a fait un peu peur, parce que, bon, l'idée de me retrouver un jour avec ma base de données mnemosyne et toutes ses données d'apprentissage sans pouvoir l'utiliser, ça fait un peu mal. Alors, comme je connaissais un peu les algorithmes, SM2 et tout ça, je savais que c'était quand même pas très compliqué et, comme j'avais pas besoin de tant de features que ça, je me suis lancé.

      Les features

      morji gère juste les trois types de cartes-mémoires que j'ai décrites avant : dans un sens, à double sens et textes à trous. Il ne gère pas l'html, ni le javascript, mais il permet de faire du balisage sémantique simple pour mettre des couleurs, du gras ou de l'italique. Par exemple, la ligne suivante dans le fichier de configuration :

      markup keyword colored red
      

      Définit le tag keyword qui permettra de rendre du texte en rouge. On l'utilise ainsi dans le contenu d'une question :

      Que veut dire [keyword mot-clé]?
      

      qui rend mot-clé en rouge.

      morji utilise un système de tags similaires à celui de mnemosyne. On peut donc associer à chaque fait un ou plusieurs tags. Ensuite, on active ou désactive des tags pour choisir quels thèmes réviser ou apprendre. Ça permet par exemple de mixer les thèmes pendant les révisions — chose que je trouve stimulante perso —, puis au moment d'apprendre de nouvelles cartes sélectionner un seul tag.

      Il est possible d'importer d'un coup une liste de faits depuis un fichier avec des champs séparés par des tabulations, un peu comme avec mnemosyne.

      Remarque technique :. morji n'est pas un projet de recherche, du coup il stocke moins de statistiques dans la base de données. Je ne sais pas si c'est surtout ça, ou le fait que mnemosyne stocke certaines informations plus ou moins en double pour des raisons qui restent un peu mystérieuses pour moi (éviter de recalculer des choses, peut-être), mais ma base de données mnemosyne est passée de presque 50M à 10M avec morji ; pratique pour faire des backups quand on a une connexion pas trop rapide :)

      Les trucs qu'il n'y a pas

      Actuellement, morji ne gère pas de fichiers externes (images, son). A priori, il serait cependant facile si besoin de l'étendre via le fichier de configuration (qui est un script Tcl même si ça se voit pas) pour lancer un visionneur d'images externe, par exemple, à défaut d'un truc parfaitement intégré.

      Il n'y a pas non plus de navigateur de cartes-mémoire. En pratique, ça correspond à cas d'utilisation très rare — en tous cas pour moi — puisque, a priori, le principe c'est qu'on va pas chercher des faits soi-même, c'est le logiciel qui le fait pour nous ; ceci dit, parfois ça pourrait être commode, mais je n'ai pas trouvé encore une solution simple qui me plaise. En attendant d'en trouver éventuellement une, pour faire des substitutions en masse ou ce genre de choses, il est possible d'utiliser un script (morji est scriptable en Tcl) ; l'interface pour faciliter cela proprement n'est pas encore vraiment fixée ni documentée (en dehors de commentaires dans le code et d'exemples), mais ne devrait pas trop changer, donc en pratique il y a moyen de se dépatouiller si besoin.

      Sous le tapis

      Là, c'est parti pour une petite section un peu technique, pour ceux qui ont eu la patience de me lire jusqu'ici :)

      Comme j'ai un peu raconté tout ce qu'il faut savoir sur SM2, les faits et les types de cartes-mémoires, etc. je me dis que tu veux peut-être savoir à quoi ressemble le schéma de la base de données utilisée par morji, qui est en fait une traduction idée pour idée des concepts.

      Il y a quatre tables : une pour les faits, une pour l'information spécifique à chaque carte-mémoire, une pour les tags, une qui fait la relation entre quels faits ont quels tags, et puis c'est tout. Je vais juste raconter un peu les deux premières, pour qu'on revoie les concepts de l'algo SM2.

      Celle des faits, facts, stocke donc, entre autres, une question et une réponse :

      CREATE TABLE IF NOT EXISTS facts(
          uid INTEGER PRIMARY KEY,
          question TEXT NOT NULL,
          answer TEXT NOT NULL,
          notes TEXT NOT NULL,
          -- oneside/twoside(recognition/production)/cloze...
          type TEXT NOT NULL
      );

      En fait, on retrouve bien le champ pour la question et la réponse. Il y a de plus un champ pour des notes additionnelles dont je n'ai pas parlé avant (mais c'est dans la nimage plus haut), et qui sert à afficher des trucs en plus dans la réponse pour les faits à deux sens, indépendamment du sens (par exemple un lien vers la source de l'information). Le champ type nous dit s'il s'agit d'un fait à un sens, à deux sens ou d'un texte à trous.

      La table contenant l'information d'apprentissage de chaque carte mémoire est un peu plus compliquée :

      CREATE TABLE IF NOT EXISTS cards(
          uid INTEGER PRIMARY KEY,
          -- last repetition time (null for new cards)
          last_rep INTEGER,
          -- next repetition time (null for new cards)
          next_rep INTEGER CHECK(next_rep ISNULL OR last_rep < next_rep),
          easiness REAL NOT NULL DEFAULT 2.5 CHECK(easiness > 1.29),
          -- number of repetitions (0 for new and forgotten cards)
          reps INTEGER NOT NULL,
          fact_uid INTEGER NOT NULL REFERENCES facts ON DELETE CASCADE,
          -- additional data whose meaning depends on facts.type
          fact_data TEXT NOT NULL
      );

      Les champs last_rep et next_rep contiennent les dates de la dernière répétition et la répétition suivante, respectivement (leur différence est donc l'intervalle théorique entre les deux répétitions). Le champ easiness contient la facteur de facilité de toute à l'heure, et reps, c'est le nombre de répétitions, donc le n des formules. Enfin, fact_uid signale le fait auquel fait référence la carte, et fact_data donne des informations supplémentaires : par exemple, est-ce le verso ou le recto qu'il faut montrer ? Un truc à remarquer aussi, c'est la valeur par défaut de 2.5 pour la facilité et la contrainte sur le minimum, qui font écho à l'algorithme.

      Petite anecdote pour la fin

      Je crois que j'ai déjà prononcé le mot Tcl un peu avant. Eh oui, morji est écrit en Tcl. En fait, quand j'ai commencé à écrire morji, j'ai vite compris que ça allait être essentiellement des requêtes SQLite et pas grand-chose de plus. Or, pendant que je me mettais à jour sur SQLite, mon attention a été attiré, un peu par hasard, par le fait que SQLite avait été initialement prévu comme une extension Tcl, avant de devenir ce qu'on connaît aujourd'hui ; du coup ça m'a intrigué, j'ai découvert que l'interface Tcl pour SQLite était vraiment sympa et leur système de tests unitaires aussi. Ajouté au fait que Tcl est un langage léger présent sur à peu près toutes les plateformes, eh bien, j'ai pas pu résister :)

      Anecdote : au début j'envisageais d'écrire morji en Go, du coup je voulais l'appeler « gogoratu » — « se souvenir » en basque —, parce que c'était rigolo, mais du coup, après, la blague tombait un peu à l'eau :)

      Voilà, c'est tout !

      Liens : site de morji, avec documentation en html ; page github du projet.

      Lire les commentaires