Articles du blog - Page 2

1 gribouilli, pour laisser vos (petits) enfants taper sur votre clavier

Il y a presque trois ans que j’ai fait gribouilli (grabouilla ça faisait moins classe, et grybouilly, trop python. Pas facile de trouver un nom de programme…). C’est un petit programme qui se met en plein écran et qui affiche des formes géométriques et des images à l’écran lorsque l’on appuie sur les touches du clavier ou que l’on clique sur les boutons de la souris (et qui trace des lignes quand on bouge la souris).

De temps en temps, mon fils me demande s’il peut y « jouer ». Pour être franc, ce qui lui plaît c’est surtout qu’à chaque fois que l’on appuie sur une touche, il y a aussi un son qui est joué. Depuis qu’il a découvert monsieur patate (KTuberling) puis GCompris, il y joue beaucoup moins, mais cette semaine, il me la redemandé. Je me suis dit : « tiens, et si ça pouvait profiter à d’autres ? » Oui, c’est un peu prétencieux, mais si ça sert à une personne, ça me fera plaisir !

Il ne faut pas trop s’apesantir sur la qualité du code, il a beaucoup évolué, sans que je revienne dessus : d’abord que des formes, puis du son, puis des images qui correspondent éventuellement au son… Du coup, on voit quelques bouts de code qui gagneraient à être factorisés, mais c’est du temps que je préfère passer à écrire cet article ;]

J’ai pas tellement de plan pour cet article, on va donc sans transition, passer aux fonctionnalités :

1.1 Fonctionnalités

  • se met en plein écran
  • joue un son aléatoire à chaque appui de touche (dans le dossier sounds)
  • affiche une forme ou une image à chaque appui de touche (dans le dossier images)
  • si un nom de fichier image correspond plus ou moins au nom de fichier son joué, c’est cette image qui est affichée (par exemple si c’est dog_2.wav qui est jouée, alors dog_4.png peut être affichée (mais pas cat_2.svg))
  • une combinaison de touche pour quitter (à modifier dans le code si elle ne vous plait pas :þ)
  • une combinaison de touche pour tout supprimer
  • la souris trace des traits
  • les boutons affichent les formes/images

1.2 Défauts

  • la longueur des mots pour nettoyer/quitter est identique (le code pour nettoyer est venu après)
  • il faut faire attention à ce que verr.maj. ne soit pas enclenché pour nettoyer/quitter (et que le raccourci pour passer du clavier azerty vers le bépo non plus…)
  • pas vraiment du plein écran sur certains windows manager (comme awesome-wm). Je n’ai pas trop cherché pourquoi.
  • je n’ai pas bloqué les touches multimédia, y compris concernant le son… et plein de sons d’animaux, trop fort, c’est trop fort…

1.3 Conclusion

Voilà, pas grand chose à dire, si ce n’est que c’est sur bitbucket, et que j’ai inclus un script qui télécharge des sons sur http://soundbible.com/ (normalement un wget -r -nd -A.mp3 est suffisant, mais là il n’y a pas les liens directement sur les fichiers, du coup, il faut tricher un peu). Ah, si, il faut installer python-qt4-phonon pour que cela fonctionne.

Très rapidement, pour jouer un son avec phonon

from PyQt4.phonon import Phonon
...
        self.m_media = Phonon.MediaObject(self)
        audioOutput = Phonon.AudioOutput(Phonon.NotificationCategory, self)
        Phonon.createPath(self.m_media, audioOutput)

    def play(self):
            fic = QtCore.QString("/tmp/myfile.mp3")
            if (QtCore.QFile(fic).exists()):
                self.m_media.setCurrentSource(Phonon.MediaSource(fic))
                self.m_media.play()

Et pour coller une image, c’est encore plus simple :

qp = QtGui.QPainter()
img = QtGui.QImage()
img.load("/tmp/mypic.jpg")
qp.drawImage(x, y, img)

J’ai bien utilisé os.path.join et os.getcwd mais je n’ai pas autre chose que du GNU/Linux à la maison, donc je ne sais pas si ça marche sur autre chose, mais ça devrait !

À la prochaine.

2 Le problème opendir de MinigalNano chez Free.fr

Il n’y a pas si longtemps, j’ai ouvert une gallerie pour la naissance de M. Je voulais quelque chose de vraiment simple, sans base de données et j’étais parti sur single file php gallery. Mais « les gens » m’ont dit que c’était trop lent. Du coup, j’ai cherché autre chose. Puis je me suis souvenu de Minigal Nano. Et tout allait pour le mieux dans le meilleur des mondes jusqu’à ce que quelqu’un me signale que le lien que je lui donne ne fonctionne pas, alors que je venais de tester… Après quelques veines tentatives de renommages des fichiers images, je me rends à l'évidence, c’est la faute à free… (Manquerait plus que ce soit de ma faute !)

Quelques recherches sur [<a href='function.opendir'>function.opendir</a>]: failed to open dir me font tomber sur ± le même problème qu’ont les gens qui veulent installer un dokuwiki sur un site .free.fr (entre autres). Du coup, je regarde comment le script liberator corrige le problème, et je vois qu’il y a un souci avec la fonction opendir (étonnant non ?)…

Me voilà donc à insérer la fonction suivante dans le fichier index.php :

function myopendir($x, $y=null) {
         if(!is_dir($x)) return false;
         return is_null($y) ? @opendir($x) : @opendir($x,$y);
}

et remplacer tous les @opendir / opendir par myopendir.

Et voilà une Minigal Nano qui roule.

3 Agrandir la police dans emacs avec control plus roulette

3.1 Agrandir la police avec Ctrl+Roulette

En fait, ce billet, c’est plutôt un vrac, mais à l’origine, c’était vraiment juste pour ça, agrandir le texte comme dans la plupart des applications. À mettre dans son .emacs bien entendu :

(global-set-key (kbd "<C-wheel-up>") 'text-scale-increase)

et pour faire l’inverse :

(global-set-key (kbd "<C-wheel-down>") 'text-scale-decrease)

3.2 Numéroter les lignes dans la marge, à la vi

Bouh vi, bouuuuuuuh.

Rien à voir avec le point précédent donc, mais bien pratique : M-x (global-)linum-mode, qui affiche donc le numéro de ligne du buffer dans la marge (ou de tous les buffers si global-…).

3.3 Highlight

Le truc que je fais souvent, c’est un C-s pour surligner une variable dans un buffer, pour voir où elle apparaît un peu plus loin. Alors que pour ça, il y a M-s h r (highlight-regexp) et toute la famille des surlignages (M-s h C-h).

Par défaut, la couleur, c’est hi-yellow, mais, le curseur est sur le y de yellow, du coup, C-k TAB et tout plein de propositions définies dans hi-lock.el s’offrent à vous. Mieux, C-a C-k TAB et c’est toutes les faces définies dans emacs que vous pourrez choisir ;]

3.4 Garder ou supprimer des lignes

En utilisant M-x keep-lines ou M-x delete-matching-lines (ou flush-lines, mais je ne m’y fais pas…) puis une regexp.

3.5 apropos

M-x apropos renseigne bien plus que C-h a qui ne montre que les commandes…

3.6 Raccourcis

C-m, C-j, C-o

3.7 Le mot du jour

4 Retenir plus facilement - ma version du systeme PAO

Au hasard de mes parcours sur la toile — bon, en fait, je sais plus comment c’est venu, du coup, on va dire que c’est par hasard1 —2 je suis tombé sur cette page. Et j’ai découvert que le commun des mortels pouvait faire des choses incroyables (et pas forcément utiles, donc indispensables) comme mémoriser l’ordre des cartes d’un paquet de 54 cartes mélangées, retenir une liste de nombres pendant plusieurs semaines, résoudre le rubik’s cube en aveugle (je ne parle pas du temps de mémorisation ni de résolution ça c’est pour les mortels moins communs3), se rappeler de moults numéros de téléphone etc.

Il y a plusieurs techniques, qui ont l’air de se valoir, pour arriver à ce but (certaines étant plus adaptées à des tâches en particulier). Je ne vais pas les présenter, elles sont bien mieux détaillées que ce que je pourrais faire dans les différents liens qui viendront. Je vais décrire celle que j’utilise, qui est une adaptation de ce qui se fait.

4.1 Memory palace

Le « palais de la mémoire » (ou la méthode des lieux) est une façon de se rappeler les choses. Pour cela, on se crée un parcours, dans sa maison, dans sa ville, avec des endroits bien spécifiques, et on utilisera toujours le même parcours. Par exemple, on commence par la chambre, on va aux toilettes, dans la cuisine, puis dans la salle de bains. Pour se souvenir des légumes à prendre aux marchés, on place un légume par endroit quand on fait sa liste, en inventant une petite histoire : les poireaux sont en train de dormir au chaud sous la couette, la carotte lutte pour ne pas tomber au fond du trou, le brocoli se fait attaquer par les céréales qui veulent le noyer dans le bol, et le pâtisson prend sa douche. Et arrivé au marché, on refait le parcours en cherchant qui faisait la grasse mat’ puis celui qui était aux toilettes, etc.

Du coup, il est important, à mon avis, d’avoir plusieurs palais, et d’en changer fréquemment pour ne pas se mélanger avec la liste de la semaine dernière…

On peut également placer plusieurs objets dans une même pièce, voire dans un même endroit (si l’ordre n’a pas d’importance par exemple). Dans ce billet (mnemotechnics.org), l’auteur décrit (et illustre) comment il place 10 objets dans une même pièce.

Bon, tout ça c’est bien beau, mais on ne va pas mettre nos cartes et nos faces de rubik’s cube dans toute la maison. Ça ne nous aiderait pas mieux à retenir.

4.2 Des nombres aux mots

Pour retenir la liste des courses, la méthode du dessus est suffisante. Il suffit de créer des histoires les plus extraordinaires possibles, pour mieux les retenir. Mais pour retenir un numéro de téléphone ? les décimales de tau ? les cartes du paquet ?

Ben pour ça, il va falloir transformer ce que l’on veut retenir en une suite de chiffre, associer chaque chiffre à une lettre, chaque lettre à un mot, et placer ces mots aux quatre coins de la maison.

4.2.1 Des chiffres aux lettres

Non, pas des chiffres et des lettres. C’est autre chose ça.

Pour transformer les chiffres en lettre, il y a plusieurs méthodes, les plus connues étant le code chiffres-sons (!wfr) (ou Major System4, qui utilise toutes les consonnes (donc plusieurs pour un même chiffre) et rien que des consonnes) et le système Dominic (!wen) (ou Dominic System5, qui utilise voyelle et consonne).

Table 1: Chiffre -> lettre
  0 1 2 3 4 5 6 7 8 9
Major S,Z,Ce T,D N M R L CH,J,Ge K,G,Q F,V P,B
Dominic A B C D E S G H N O

L’avantage du premier est qu’il permet de transformer n’importe quel mot en suite de chiffre, et inversement.

Avec ces systèmes, on associe généralement un mot ou un nom (souvent les initiales Prénom Nom) à un nombre sur deux chiffres (de 00 à 99). Par exemple pour le code chiffres-sons, on peut associer PoPeye pour 99, le Père Noël pour 92, NeiGe pour 26, etc (on associe les sons, pas les lettres, donc NeiGe, c’est 26 et pas 27). Pour le système Dominic, on utilise quasiment que des initiales : Albert Einstein pour 04, George Bush pour 61 ou encore Barack Obama pour 19.

J’étais donc parti sur ce système, et étais passé à l’étape suivante, quand quelqu’un qui se reconnaîtra m’a dit que c’était pourri (uu) ; il valait mieux une lettre par chiffre.

Du coup, un coup de ddg.gg plus tard, me voilà avec les 10 consonnes les plus fréquentes en français, que j’organise comme je peux :

  Mon système Mnémotechnique
0 C un 0 pas fermé
1 l 1 barre
2 n 2 barres
3 m 3 barres
4 R quasiment le miroir
5 S même forme
6 d miroir
7 t même forme
8 V 8 japonais à l’envers ?
9 p miroir

Et si je veux, je peux ajouter les consonnes restantes dans les cases pour retomber sur un semblant de code chiffres-sons (j’ai pas encore eu l’utilité, mais sait-on jamais).

4.2.2 Système PAO

J’étais parti pour me faire ma liste de 100 mots6, lorsque je suis tombé sur le système PAO : Personne-Action-Objet7. Au lieu d’avoir un seul mot pour un nombre à deux chiffres, on en a trois ! Un nombre peut correspondre à une personne, une action, et un objet. Donc dans notre Memory Palace, on peut stocker trois fois plus d’informations, et éviter trop de répétitions !

Par exemple, avec le code chiffres-sons, on peut avoir Michaël Jackson, ManGer et MaGie qui sont codés avec 36, PoPeye, PaPouiller et PouPée qui sont codés avec 99, etc.

Lorsque l’on veut retenir une suite de nombre comme 99, 36, 99… on n’associe plus PoPeye, Michaël Jackson, PoPeye dans trois pièces de la maison, mais PoPeye qui ManGe une PouPée dans une seule pièce.

Là aussi, les approches Major/Dominic diffèrent : pour le premier cas, on va plutôt essayer de trouver des actions/objets de deux syllabes avec les consonnes correspondants aux chiffres (comme dans mon exemple : ManGer, PouPée). Dans le second, on va associer un verbe (parfois un objet, mais souvent le système, c’est juste PA, pas PAO) sans rapport avec le codage. Enfin, si, le rapport, c’est que c’est la personne qui est codée : Albert Einstein (04) qui écrit au tableau E=mc², Bill Gates (16) qui programme sur son PC… Pour retrouver 1604, on pensera alors à Bill Gates qui écrit au tableau.

J’ai commencé les deux méthodes, mais suis finalement resté sur la Major. Et puis, en lisant des commentaires sur le système Dominic, celui de RussellP du 2012-11-26 09:37 UTC a retenu mon attention. L’idée : utiliser des thèmes. Je me suis dit que ce serait sympa de faire ça, choisir un thème avec comme initiale la lettre correspondant aux dizaines. Pour les personnes, les actions, et les objets. Ça n’a pas été facile… Je ne suis pas encore totalement satisfait de tous mes thèmes et de leur contenu, mais rien que pour l’exercice, c’était sympa de le faire.

Vous pouvez voir le résultat ici. Si des gens sont tentés par l’aventure, mais sans les thèmes, j’ai mis quelques anciennes tentatives (avec des liens divers).

Voilà, si vous lisez l’anglais, je vous conseille vivement les sites dans les notes de fin page, les wikis, fora, commentaires, etc. pour en apprendre un peu plus, et pourquoi pas pour vous y mettre et faire votre tableau :]

Et si vous connaissez déjà, si vous avez des suggestions, des commentaires, n'hésitez pas à m'envoyer un mail (sur free, on change le pénultième point par un @ (celui avant « free.fr ») et on a l'adresse mail qui correspond au site).

4.3 Bonus

Jetez également un coup d’œil à http://www.ludism.org/mentat/BrainTrainingGames pour entraîner votre mémoire. Le dual n-back est franchement pas facile, mais les études ont l’air de montrer que c’est efficace.

4.3.1 org-drill

Tout est expliqué sur worg : org-drill fonctionne comme les « flashcards » question d’un côté, réponse de l’autre. Pour réviser mes associations chiffre-mot, je me suis donc préparé un fichier pao-drill.org.

Pour ça, je pars du fichier pao.org, et pour chaque tableau, je supprime les lignes et colonnes servant de repères. Puis je supprime le dernier caractère de chaque ligne (avec un C-x r k).

Et c’est parti pour deux macros (qui pourraient être regroupées en une seule, mais bon…) :

Mettre un couple nombre-mot par ligne
  • On prépare pour mettre le compteur sur deux chiffres : C-x C-k C-f %02d
  • On initialise le compteur à 00 : C-x C-k C-c 0
  • Pour chaque caractère |, on va aller à la ligne, et insèrer le compteur : F3 Cs | Enter Space F3 F4
  • On le fait pour tous les autres mots : M-99 F4
Mettre les items org-drill

Tiré de C-h l (sans les espaces) :

<f3> C-s | <return> <backspace> <return> ** Item :drill: <return> P - <delete> M-f <return> *** the answer <return> <delete> <f4> J’ai ajouté P- pour les personnes, A- et O- pour actions et objets pour être interrogé sur les trois tableaux à la fois.

Et là on se rend compte qu’on a oublié de faire M-x org-table-transpose-table-at-point sur les tableaux. Du coup, un petit C-M-%, on remplace ^\(.\)-\([0-9]\)\([0-9]\) par \1-\3\2 et le tour est joué.

Voilà, notre fichier est tout beau tout prêt. Pour s’en servir, M-x org-drill et c’est parti.

Comme je veux m’entraîner fréquemment, je me suis rajouté dans mon .emacs

(defun pao ()
  "reviser son pao"
  (interactive)
  (find-file "~/.emacs.d/pao-drill.org")
  (org-drill)
  )
(global-set-key (kbd "<f11>") ’pao)

4.3.2 Raccourcis et fonctions

J’ai découvert C-u C-c C-x f S pour réorganiser les footnotes. Et j’utilise de plus en plus C-c C-x C-f pour mettre en gras, italique… C-c C-l pour insérer/éditer un lien, et le magique C-c C-c pour aller d’une note à sa définition et inversement. Et en essayant de voir si on pouvait augmenter le nombre de caractères stockés par C-h l, j’ai découvert open-dribble-file.

5 Modifier des fichiers en masse

La problèmatique du jour est la suivante : j'utilise actuellement selenium pour les besoins du boulot. Je vous passe les détails, mais j'ai moults fichiers html qui me permettent de tester le contenu d'un site. Sauf que ce site évolue parfois, et du coup, il me faut modifier relativement fréquemment ces fichiers. Heureusement qu'il y a findus emacs.

5.1 1er cas : changer un lien

Dans certains tests (qui sont nommés trucVariable_toto.html), j'ai à tester la présence d'un lien <a href="toto">trucConstant</a>. Parfois, trucConstant change et devient autreChose. Du coup, pleins de fichiers dans lesquels je dois modifier moi aussi trucConstant par autreChose.

C'est un cas assez fréquent (correction d'une typo…), et assez simple à résoudre :

  • On ouvre le dossier où sont contenus les fichiers .html (avec C-x C-f) et on se trouve dans dired.
  • On marque les fichiers concerné %m TexteDansLeNomDesFichiers.
  • On appuie sur Q (pour Query replace regexp in marked files).
  • trucConstant (mais une regexp est possible).
  • autreChose.
  • Y (Yes, toutes les condordances pour tous les fichiers marqués (y,y,y au début pour voir que ça va bien si jamais on a un doute ;]).
  • Nos fichiers sont modifiés mais pas sauvés, et ouverts dans des buffers. Du coup M-x ibuffer (Parce que C-x C-b n'est parfois pas suffisant (h dans ibuffer pour l'aide)).
  • * u (pour marquer tous les non-sauvés).
  • S (pour sauver les buffers marqués).
  • D (pour supprimer les buffer marqués).
  • q (quitter ibuffer).
  • Profiter du temps gagné.

5.2 Idem mais un peu plus à changer

Parfois, c'est tout un tableau qui est à changer. Et ce tableau est identique pour tous les fichiers. Ça reste dans ce cas relativement simple. Pour ce cas, je copie le tableau, je le mets dans un buffer temporaire, je le prépare pour être « regexp ready », le stocke dans un registre, fais ma modification, stocke dans un second registre, et fais comme au-dessus, sauf qu'au lieu de taper trucConstant et autreChose, je restitue mes registres.

  • Ouvrir un des fichiers et aller au début de la partie à modifier.
  • C-SPC pour poser la marque.
  • Déplacer le curseur à la fin de la partie à modifier.
  • M-w pour copier.
  • Ouvrir un buffer temporaire C-x b auie (ou *scratch*).
  • Coller C-y la région précédemment sauvegardée.
  • Se placer au début du buffer M-<, ou sélectionner tout le buffer C-x h.
  • Changer les [ et ] par \[ et \] pour que Query replace regexp in marked files ne les prennent pas pour des caractères spéciaux : C-M-% changer \(\[\|\]\) par \\\1.
  • ! pour tout substituer.
  • Notre trucConstant un peu plus long est prêt. On sélectionne tout C-x h, et on stocke dans un registre C-x r s a par exemple. On peut faire notre deuxième registre.
  • On supprime avec C-w (comme tout le buffer est sélectionné).
  • On colle la région sauvegardée du début. Pour cela, on remonte dans l'historique du kill-ring avec C-y puis M-y.
  • On fait les modifications nécessaires.
  • On resélectionne tout C-x h, et on stocke notre deuxième registre avec C-x r s b par exemple.
  • On supprime notre buffer temporaire C-x k.
  • On se place dans notre dossier où on marque les fichiers contenant le texte qqChoseDansLeTableau avec % g puis qqChoseDansLeTableau.
  • Q puis on restitue notre premier registre avec C-x r i a.
  • La substitution est assurée par le registre b : C-x r i b.
  • Et comme au dessus, on appelle M-x ibuffer pour sauver/détruire les buffers modifiés.

Pas bien plus compliqué donc. Il faut juste faire attention au fait que Query replace regexp in marked files prend en première partie une regexp, ce qui peut poser quelques problèmes, mais aussi être utile puisqu'on peut se servir de bouts de la regexp pour les restituer avec \1, \2… D'ailleurs, c'est ce que l'on pourrait faire si le tableau n'est pas vraiment identique d'un fichier à l'autre. Mais comme ça risque d'être long et fastidieux, je préfère passer par des macros !

5.3 Supprimer une ligne dans un tableau, utilisation de macros

Pour ceux qui ne suivent que moyennement, je replace le contexte : plein de fichiers .html à changer, avec plus ou moins la même chose à l'intérieur, mais pas vraiment, et du coup, ça pourrait être chiant. Mais au final, pas tant que ça.

Afin de mieux expliquer, voici ce que contient une des pages du site que je dois tester :

.                       .                          .
.                       .                          .
|                       |                          | 
+-----------------------+--------------------------+
|    texte a :          |       valeur             |
+-----------------------+--------------------------+
|    texte b :          |       valeur             |
+-----------------------+--------------------------+
|    texte c :          |                          |
+-----------------------+--------------------------+
|      sstexte i        |       valeur             |
+-----------------------+--------------------------+
|      sstexte ii       |       valeur             |
+-----------------------+--------------------------+
|                       |                          |
.                       .                          .
.                       .                          .

Un tableau, avec des valeurs qui changent selon ce que l'on a fait avant, comment on a navigué, etc.

Mais maintenant, le site a changé, et la ligne avec texte b a disparu :

.                       .                          .
.                       .                          .
|                       |                          | 
+-----------------------+--------------------------+
|    texte a :          |       valeur             |
+-----------------------+--------------------------+
|    texte c :          |                          |
+-----------------------+--------------------------+
|      sstexte i        |       valeur             |
+-----------------------+--------------------------+
|      sstexte ii       |       valeur             |
+-----------------------+--------------------------+
|                       |                          |
.                       .                          .
.                       .                          .

Dans mes tests selenium, j'utilise xpath pour retrouver les éléments. Les éléments du tableau ont pour chemin quelque chose comme :

.                       .                          .
.                       .                          .
|                       |                          | 
+-----------------------+--------------------------+
|  //path/to/elem[x]    |     //path/to/avec[x]    |
+-----------------------+--------------------------+
|  //path/to/elem[x+2]  |                          |
+-----------------------+--------------------------+
|  //path/to/elem[x+4]  |     //path/to/avec[x+4]  |
+-----------------------+--------------------------+
|  //path/to/elem[x+5]  |     //path/to/avec[x+5]  |
+-----------------------+--------------------------+
|                       |                          |
.                       .                          .
.                       .                          .

Et là, on voit bien le problème : le texte c n'est plus à l'indice x+2 à présent, mais x+1. À partir de x, il va falloir décrémenter tous les chiffres.

Ça ferait un bon exercice, mais ne parlant pas encore le (e)lisp couramment, https://duckduckgo.com/?q=!+emacs+increment+number+at+point me donne la réponse plus rapidement…

(defun decrement-number-at-point ()
      (interactive)
      (skip-chars-backward "0123456789")
      (or (looking-at "[0123456789]+")
          (error "No number at point"))
      (replace-match (number-to-string (1- (string-to-number (match-string 0))))))

On va procéder maintenant en deux étapes : enregistrer une macro pour faire le changement dans un fichier, et appeler cette macro pour faire le changement dans tous les fichiers.

5.3.1 Enregistrement de la première macro

On a de la chance, dans le fichier .html (le test selenium) c'est tout bien aligné :

...
<tr>
        <td>verifyText</td>
        <td>//div[@id='unId']/table/tbody/tr[3]/th/span</td>
        <td>Texte a :</td>
</tr>
<tr>
        <td>verifyText</td>
        <td>//div[@id='unId']/table/tbody/tr[3]/td/span</td>
        <td>valeur</td>
</tr>
<tr>
        <td>verifyText</td>
        <td>//div[@id='unId']/table/tbody/tr[4]/th/span</td>
        <td>Texte b :</td>
</tr>
<tr>
        <td>verifyText</td>
        <td>//div[@id='unId']/table/tbody/tr[4]/td/span</td>
        <td>valeur</td>
</tr>
<tr>
        <td>verifyText</td>
        <td>//div[@id='unId']/table/tbody/tr[5]/th</td>
        <td>Texte c :</td>
</tr>
<tr>
        <td>verifyText</td>
        <td>//div[@id='unId']/table/tbody/tr[6]/th/span</td>
        <td>regexp:- sstexte i \* :</td>
</tr>
...
  • On se place sur le premier chiffre à changer.
  • F3 pour commencer l'enregistrement de la macro.
  • M-x decrement-number-at-point.
  • M-5 C-n (on descend de 5 lignes pour se placer sur le prochain chiffre).
  • F4 on termine la macro.

Si on appuie maintenant à nouveau sur F4, on va incrémenter le nombre sous le curseur et se déplacer vers le second chiffre.

Si on fait M-0 F4, on va appliquer la macro tant que c'est possible, et du coup, changer tous les chiffres qui vont bien.

Notre première macro est finie, on peut la garder pour la suite. Pour cela on la nomme pour pouvoir l'appeler comme une fonction : C-x C-k n auie.

5.3.2 Appliquer la première macro dans tous les fichiers

Enfin, tous les fichiers qui contiennent texte a

  • dans dired : %g texte a
  • puis voilà comment je fais en principe :
F3 Début de la macro
M-} Se positionner sur le fichier marqué suivant
Enter Ouvrir le fichier
M-< Aller au début du buffer (on pourrait l'avoir déjà d'ouvert)
C-M-S verifyText.*C-qC-j.*unId.*tr.4.*C-qC-j.*Texte b Texte b apparaissant à un autre endroit, je prends pas de risque
C-u C-p 4 lignes vers le haut
M-16 M-z > Supprimer jusqu'au 16e « > »
C-s 5 Chercher 5
Enter Arrêter la recherche
C-b Positionner le curseur sur le 5
M-0 M-x auie Exécuter tant que possible l'incrément/déplacement vers le bas
C-x C-s Sauver
C-x C-k Tuer le buffer
F4 Arrêt de la macro

Je sauve et tue le buffer, mais on pourrait faire comme précédemment, utiliser ibuffer. En plus, si jamais nos macros sont mal définies, on peut faire des M-x revert-buffer si ça c'est mal passé. Avec ma méthode, ce n'est pas le cas. (Mais bon, mes tests sont versionnés, je prends pas de risque non plus.)

Voilà les trois façons que j'utilise pour modifier tout un tas de fichiers. Ce qui est pratique, c'est que même si mes fichiers sont dans des dossiers rep/ssrep1 et rep/ssrep2, j'ouvre rep dans un buffer, puis i sur ssrep1 et ssrep2 me permet de voir tous les fichiers d'un coup :]

Si vous connaissez plus simple, n'hésitez pas à me dire comment !

6 Les fourmis, suite et fin

J’ai enfin pris le temps de nettoyer le dernier code… Voilà donc l'article qui va avec, plutôt indigeste… Comme d’habitude, trois fichiers :

6.1 display.py

Rien qui change à part la façon de faire les rectangles, ainsi que la position du point de départ et la nourriture :

def populate(self, gridFood, startPos):
    """initialise la grille"""
    w = self.wsiz
    h = self.hsiz
    x = self.dimx
    y = self.dimy
    #on met le point de départ en rouge
    item = self.scene.addRect(startPos[0]*w/x, startPos[1]*h/y, w/x, h/y,
                              self.pen, QtGui.QBrush(QtGui.QColor("red")))
    #que l'on passe en avant
    item.setZValue(2)
    #on place de la même façon la nourriture, en vert
    for i in range(len(gridFood)):
        for j in range(len(gridFood[0])):
            if gridFood[i][j]:
                item = self.scene.addRect(i*w/x, j*h/y, w/x, h/y, self.pen,
                              QtGui.QBrush(QtGui.QColor("green")))
                item.setZValue(2)

6.2 ant.py

Le plus gros changement se fait chez les fourmis. Sur le chemin du retour, elles se « rappellent » de leur chemin, et évite de faire des boucles…

def shorten(lwloop):
    """ On enlève les boucles de la liste """
    i = 0
    while i < len(lwloop):
        item = lwloop[i]
        lwloop.reverse()
        last = len(lwloop) - (lwloop.index(item) + 1)
        lwloop.reverse()
        lwloop.__delslice__(i, last)
        i = i + 1

Pour se déplacer, si elles trouvent de la nourriture à côté d’elles, elles y vont. Une fois qu’elles l’ont, elles retournent au point de départ.

def move(self):
    """
    Un pas, selon l'environnemnt.
    """
    #Si a trouvé de la nourriture
    if self.parentGrid.gridFood[self.coord[0]][self.coord[1]]:
        #retour a la maison
        self.goHome = True
        #sans faire de boucle
        shorten(self.pathDone)

    #si sur le chemin du retour
    if self.goHome:
        #et qu'il reste du chemin
        if self.pathDone:
            self.lastCoord = self.coord
            self.coord = self.pathDone.pop()
        else:
            #sinon, on repart
            self.goHome = False

Sinon, elles errent, ou essayent plus ou moins de suivre un chemin de phéromones.

else:
    #si pas encore trouvé de nourritére
    directions = [(-1, -1), (-1, 0), (-1, 1),
                 (0, -1), (0, 1),
                 (1, -1), (1, 0), (1, 1)]
    gfood = self.parentGrid.gridFood
    food = [(gfood[(self.coord[0] + x) % self.parentGrid.xmax]
                 [(self.coord[1] + y) % self.parentGrid.ymax],
                 [(self.coord[0] + x) % self.parentGrid.xmax,
                  (self.coord[1] + y) % self.parentGrid.ymax])
             for (x, y) in directions]
    food.sort()
    #si de la nourriture juste a coté, on y va
    if (food[-1][0]):
        self.lastCoord = self.coord
        self.coord =  food[-1][1]
    else:
        #sinon où sont les phéromones ?
        grid = self.parentGrid.gridPhero
        phero = [(grid[(self.coord[0] + x) % self.parentGrid.xmax]
                     [(self.coord[1] + y) % self.parentGrid.ymax],
                     [(self.coord[0] + x) % self.parentGrid.xmax,
                      (self.coord[1] + y) % self.parentGrid.ymax])
                 for (x,y) in directions]
        actualPhero = [(i, j) for (i, j) in phero if (i!= 0)]
        lenAP = len(actualPhero)
        if lenAP > 0:
            #À 95%, on suit la plus forte phéromones
                if (randint(0,100) < 95):
                    newCoord = actualPhero[randint(0,lenAP-1)][1]
                else:
                    #sinon, on erre
                    newCoord = phero[randint(0,7)][1]
        else:
            #s'il n'y a pas de phéromones à côté, on erre
            newCoord = phero[randint(0,7)][1]
        while newCoord == self.lastCoord:
            #mais on ne veut pas retourner sur nos pas!
            newCoord = phero[randint(0,7)][1]
        self.lastCoord = self.coord
        self.coord = newCoord
        self.pathDone += [self.coord[:]]

6.3 simu.py

Rien de bien différent si ce n’est la façon de générer les phéromones

#taux de phéromones qu'une fourmi pose
self.pheroUp = 50
#taux d'évaporation des phéromones
self.pheroDown = 0.1

self.dictPhero = {} # { taux : [liste de [x, y]]}
self.gridPhero = [[0 for _ in range(self.ymax)] for _ in range(self.xmax)]

#point de départ et nourriture
self.gridFood = [[0 for _ in range(self.ymax)] for _ in range(self.xmax)]
self.gridFood[10][10] = 1
startPos = [self.xmax/2, self.ymax/2]

#no food on starting pos
self.gridFood[startPos[0]][startPos[1]] = 0

#le widget central est notre affichage de la grille
self.resize(self.wsize, self.hsize)
self.centralWidget = GridDisplay(self.xmax, self.ymax, self.wsize, self.hsize)
self.setCentralWidget(self.centralWidget)

self.centralWidget.populate(self.gridFood, startPos)

6.4 Un dernier mot

Pour dire qu’au final, on a quelque chose qui tient vaguement la route. Si vous voulez rendre les fourmis plus intelligentes, c’est dans la fonction move qu’il faut aller. Pour jouer avec les « 95% » et sur le fait que prendre un random, c’est pas terrible. Le mieux serait de choisir une direction et de garder ± le cap.

Faudrait aussi ajouter quelques p’tites choses comme des boutons pour arrêter, changer la vitesse, modifier les options (nombre de fourmis, taille, etc.), mais ça, vous êtes grand ;]

Oh, et pour les sources, direction bitbucket.

simu4_manger.png

Figure 1: À table !!!

7 Encoder avec mencoder

La page de manuel de mplayer et mencoder est très complète mais un peu dense. Du coup, pour me rappeler comment convertir une vidéo, un petit mémo :

7.1 La ligne à changer

mencoder fichierEnEntree.avi -oac copy -ovc copy -o fichierDeSortie.avi

Les options :

-oac : choix du codec audio, codec copy = pas d’encodage, on recopie

-ovc : choix du codec vidéo, codec copy = pas d’encodage, on recopie

Cette ligne de commande ne fait donc « rien » :þ mais en changeant les codecs audio ou vidéo…

7.2 Changer de format de sortie

7.2.1 Output Codec Audio -oac

Les codecs audio sont à choisir parmi :

pcm (pour du non compressé)

mp3lame

lavc

help pour la liste des codecs disponibles

Deux des codecs en « détails » : mp3lame et lavc

mp3lame

Pour du mp3 qui passe partout. On peut alors ajouter des options avec -lameopts :

lameopts

Là ça devient vite technique. Faites confiance aux sites que vous visitez (ou expérimentez pour trouver votre bonheur), ou utilisez les preset.

Quelques exemples classiques:

-oac mp3lame -lameopts cbr:br=128 (bitrate constant (cbr) à 128kbps)

-oac mp3lame -lameopts preset=15:mode=3 (bitrate moyen de 15kbps, mode=3 pour du mono, 0 pour du stéréo)

Si comme moi, vous n’avez pas une oreille d’expert, fast:preset=standard devrait convenir (voire preset=medium), pour du 170-210kbps. Si vous êtes exigeants preset=insane pour du 320kbps.

lavc

Pour ceux qui connaissent ce qu’ils veulent. Les options avec -lavcopts :

lavcopts

Deux exemples :

acodec=vorbis

acodec=ac3:abitrate=192

le-truc-par-défaut-qui-devrait-marcher-tout-le-temps

-oac mp3lame sans rien du tout pour du mp3

ou

-oac lavc sans rien du tout pour du mp2

7.2.2 Output Codec Video -ovc

Les codecs pour la vidéo que je vais détailler :

raw pour du non compressé

lavc

Sinon, help pour la liste des codecs disponibles

raw

On précise les options avec -vf : -ovc raw -vf format=rgb24

lavc

Les options sont encore avec lavcopts :

lavcopts

vcodec=mpeg4:vbitrate=300 (mpeg4 (qui est la valeur par défaut si on ne mets pas de lavcopts) en 300kbps)

keyint=250 (une trame clé toutes les 250, plus c’est petit plus le fichier de sortie est gros, mais meilleur est le déplacement)

aspect=16/9 (« mieux que le redimensionnement, car la qualité n’en est pas diminuée » dixit man)

7.2.3 On peut également encoder en plusieurs passes :

En 2 passes

mencoder [les options] -ovc lavc -lavcopts foo=bar:vpass=1 (crée un fichier de statistiques)

puis

mencoder [les options] -ovc lavc -lavcopts foo=bar:vpass=2 (crée le fichier vidéo en se servant du fichier de statistiques)

On peut également ajouter « turbo » pour la première passe.

En X passes

mencoder [les options] -ovc lavc -lavcopts foo=bar:vpass=1 (pour créer le fichier de statistiques)

puis X-1 fois

mencoder [les options] -ovc lavc -lavcopts foo=bar:vpass=3 (qui crée le fichier vidéo et modifie celui de stats)

7.2.4 Les options de sous-titres

-sub fichier.sub

-sub-bg-alpha 100 (transparence du fond, de 1 à 255, 1 pas transparent, 255 très transparent, 0 totalementtransparent)

-subdelay 2 (retarde les sous-titres de 2 secondes)

-subfps 25 (rapport trame/sec des sous-titres, utile si les sous-titres se décalent au cours du temps)

7.2.5 Le divers

Si on veut augmenter le son : -af volume=30

Si on veut jouer avec luminosité/contraste : -vf eq=10/0

Si on veut ajouter des bandes noires : -vf expand=0:-50:0:0 (ajoute un bord de 50 pixels en bas de l’image)

7.3 Quelques exemples :

7.3.1 Conversion asf vers flv, l’asf étant tout pourri comme format, le flv pratique pour le web :

mencoder -of lavf -oac mp3lame -lameopts abr:br=56 -ovc lavc -lavcopts vcodec=flv:vbitrate=400:mbd=2:mv0:trell:v4mv:cbp:last_pred=3 -of lavf -lavfopts format=flv -srate 22050 -ofps 24000/1001 -af volume=30 -vf eq=20:0 -o $sortie $1

Tiré d’un de mes scripts, d’où les $1 $2 Qui en décomposé donne :

mencoder -oac mp3lame 
              -lameopts abr:br=56
         -ovc lavc 
             -lavcopts vcodec=flv:vbitrate=400:mbd=2:mv0:trell:v4mv:cbp:last_pred=3
	     #diverses options pour «améliorer la qualité si possible»
         -of lavf
             -lavfopts format=flv
         -srate 22050
         -ofps 24000/1001
         -af volume=30
         -vf eq=20:0
         -o foo.flv bar.asf

7.3.2 Conversion d’un flv en xvid avec incrustation de sous-titres

mencoder -oac mp3lame -lameopts cbr:br=128
        -ovc xvid -xvidencopts bitrate=900
	-sub foo.srt
	-o foo.xvid
	foo.flv

Comme le bitrate est ptêtre un peu trop grand, on peut le récupérer au préalable avec :

mplayer -vo null -ao null -identify -frames 0 foo.flv 2>/dev/null | grep "VIDEO:" | awk '{print int($7)}'

8 Le flux RSS est dispo

8.1 Mais vous réjouissez pas trop vite…

Il est valide (enfin, il devrait), mais les liens qu’il contient sont relatifs, y a pas de date de publication ; bref, le minimum syndical. Et pour le moment, je n’ai pas mis de limite sur le nombre d’articles, mais si ça sera pas trop dur (si le tri est fait comme je pense qu’il est fait).

Bon, je m’suis vraiment pas cassé… j’ai pris la fonction qui fait le sitemap, et je l’ai modifiée pour faire celle qui fait le rss.

Du coup, c’est moche, mais c’est fait…

(defun org-publish-org-rss (project &optional sitemap-filename)
  "Create a rss of pages in set defined by PROJECT."
  (let* ((project-plist (cdr project)) ; (:property value :property value ...) ou (:components ("proj1" "proj2"...)
         (dir (file-name-as-directory
               (plist-get project-plist :base-directory)));on recupere le dossier a traiter
         (exclude-regexp (plist-get project-plist :exclude)) ;s'il y a des exclusions
         (files (nreverse (org-publish-get-base-files project exclude-regexp)));liste des fichiers du projet (sans les exclus)
         (rss-filename (concat dir "other/rss.rss")) ;nom du fichier rss
         (sitemap-filename (concat dir (or sitemap-filename "sitemap.org"))) ;nom du fichier sitemap
         (visiting (find-buffer-visiting rss-filename));est-ce qu'on visite le fichier "rss.org"? (contient le buffer, nil sinon)
         file rss-buffer);fin du let*, file et rss-buffer sont nil
    (with-current-buffer (setq rss-buffer;on travaille temporairement avec ce fichier qui contient
                               (or visiting (find-file rss-filename))); soit le buffer qui le contenait, soit un nouveau buffer qu'on ouvre et qui contient "rss.org"
      (erase-buffer) ;on l'efface
      (insert (concat "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<rss version=\"2.0\">\n")) ; on met le debut
      (insert (concat "<channel>\n"))
      (insert (concat "<description>Flux de fredtantini.free.fr</description>\n"))
      (insert (concat "<link>http://fredtantini.free.fr</link>\n"))
      (insert (concat "<title>Flux de fredtantini.free.fr</title>\n"))
      (while (setq file (pop files)) ; tant qu'il y a des fichiers dans le projet à traiter
        (let ((link (file-relative-name file dir))) ; le nom relatif par rapport au dossier à traiter, lnk
          ;; rss shouldn't list sitemap
          (unless (equal (file-truename sitemap-filename)
                         (file-truename file)) ;cf commentaire
            (insert (concat "<item>\n<title>"))
            (insert (concat (org-publish-find-title file)))
            (insert (concat "</title>\n<link>http://fredtantini.free.fr/"))
            (insert (concat (if (string-match "\\.org$" link)
                                (replace-match ".html" t t link)
                              )))
            (insert (concat "</link>\n<description><![CDATA["))
            (with-temp-buffer
              (insert-file-contents file nil nil nil t)
              (mark-whole-buffer)
              (org-html-convert-region-to-html)
              (copy-region-as-kill (point-min) (point-max))
              )
            (yank)
            (insert (concat "]]>\n</description>\n</item>\n"))
            ))
      (save-buffer));on sauve le fichier
      (insert (concat "</channel>\n"))
      (insert (concat "</rss>\n")) ; on met le debut
      (save-buffer)
      (or visiting (kill-buffer rss-buffer)))));et on tue le buffer si on ne le visitait pas

Oh, il est :)

9 Des fourmis et des phéromones - 3ème partie

9.1 Avec un peu de retard, la pénultième partie

Je pense en effet que la prochaine sera la dernière, même s’il reste du boulot pour avoir des fourmis moins bêtes…

Comme expliqué lors de la seconde partie (oui, on peut dire second(e) même s’il y en a plus que deux), on va mettre en place les phéromones. Pour ça, pas besoin de changer le fichier ant.py, les phéromones sont gérés dans le fichier principal, et lors de l’affichage.

9.2 simu.py

Pour gérer les phéromones, on va utiliser un dictionnaire : pour chaque taux de phéromones présent, on associe la liste des coordonnées sur la grille pour lesquelles il y a des phéromones à ce taux. Ça permet de reconstruire un tableau à deux dimensions qui contient le taux des phéromones. On le déclare dans l’initialisation :

self.phero = {} # { taux : [liste de [x, y]]}

Ensuite, on va changer notre fonction animate pour mettre à jour le dictionnaire de phéromones :

  1. à chaque étape, les phéromones s’évaporent un peu ;
  2. on reconstruit ensuite le tableau des phéromones ;
  3. chaque fourmi dépose un peu de phéromones avant de se déplacer.
#atténuation des phéromones présentes (5 de moins à chaque endroit)
newPhero = {}
for lLev in self.phero:
    newLev = lLev - 5
    if (newLev > 0):
        newPhero[newLev] = self.phero[lLev]
self.phero = newPhero

#reconstruction de la grille des phéromones
gridPhero = [[0 for _ in range(self.ymax)] for _ in range(self.xmax)]
for lLev in self.phero:
    for [i, j] in self.phero[lLev]:
        gridPhero[i][j] = lLev

self.compteur += 1
for fourmi in self.lAnts:
    ##ajout de la phéromone
    ###on récupère l'ancienne valeur
    oldPhero = gridPhero[fourmi.coord[0]][fourmi.coord[1]]
    ###s'il y avait des phéromones, on enlève l'ancienne valeur
    if oldPhero:
        if fourmi.coord in self.phero.get(oldPhero):
            self.phero.get(oldPhero).remove(fourmi.coord)
    ###on met à jour avec la nouvelle valeur (50 de plus)
    gridPhero[fourmi.coord[0]][fourmi.coord[1]] = oldPhero + 50
    self.phero.setdefault(oldPhero + 50, []).append(fourmi.coord[:])

    ##déplacement de la fourmi
    fourmi.move()

#maj de la grille
self.centralWidget.animate(self.phero)

La dernière étape consistant à rafraîchir le widget central en lui donnant le dictionnaire des phéromones.

9.3 display.py

Là aussi, seule la fonction animae change vraiment. À chaque rafraîchissement on va :

  1. supprimer les anciennes phéromones ;
  2. ajouter les nouvelles ;
  3. déplacer les fourmis.

Tout comme les fourmis, on gère les phéromones par des petits rectangles que l’on ajoute/supprime de la scène :

#on supprime de la scène les anciens carrés de phéromones
if self.lPhero:
    print len(self.lPhero)
    for phero in self.lPhero:
        self.scene.removeItem(phero)
        self.lPhero.remove(phero)

#et on ajoute les nouveaux
for lLev in dictPhero:
    for phero in dictPhero[lLev]:
        item = self.scene.addRect(phero[0]*w/x, phero[1]*h/y, w/x, h/y, self.pen,
                           QtGui.QBrush(QtGui.QColor(max(0, 255 - lLev), 255, 255)))
        item.setZValue(1)
        self.lPhero.append(item)

#et on déplace les fourmis
for (nitem, ant) in enumerate(self.lAnts):
    [i, j] = ant.coord
    item = self.lItems[nitem]
    item.setRect(i*w/x, j*h/y, w/x, h/y)
    #que l'on place au premier plan
    item.setZValue(2)

Rien de bien compliqué en somme… Comme d’hab, les sources sont sur bitbucket. La prochaine fois, les fourmis seront moins crétines et arriveront à détecter les phéromones pour être guidées vers de la nourriture et rentrer au bercail.

10 Trier des choses sur une page web

10.1 Pourquoi ?

Comme d’habitude : pourquoi pas ? En fait, sur plusieurs sites, je me suis aperçu que j’aurais bien aimé avoir la possibilité de trier les résultats par note, vote, date…

Par exemple, si on cherche des recettes de dessert sur 750g, sur marmiton, voire yummly, je vois pas trop comment sont triés les résultats… Pas possible non plus de trier selon le nombre de commentaires sur /. ou MeFi, certains tableaux sur wikipedia ne sont pas triés. Ce n’est clairement pas quelque chose que je veux faire tous les jours, mais ça m’arrive. Du coup j’ai pris mon courage à deux mains, mon clavier dans l’autre, et je me suis mis à coder une petite fonction, qui a ses limites, mais qui marche dans la plupart des cas.

10.2 Rapide problème

Je voulais un truc léger (sans jquery), et donc partir de zéro. Puis j’ai été confronté au problème qui fait que, quand on clique sur un span qui se trouve dans un div lui-même dans un li qui est… si on a ajouté une fonction qui écoute les événements pour tous les objets, et bien le span va bien répondre présent, mais aussi le div, le li et tous les autres… Je me suis alors demandé comment avait fait tontof pour kriss pin. Et, comme toute bonne personne qui se respecte, il a mis en commentaire dans son code comment il a résolu ce problème. Ce commentaire c’est « http://www.quirksmode.org/js/events_order.html », et ça explique bien mieux que moi… Et plutôt que de pomper honteusement ses fonctions, je m’suis dit, pourquoi ne pas intégrer ça à kriss pin ?

10.3 Intégration dans kriss pin

J’ai donc forké sur github, fait mes modifications, et un pull request.

Allez voir chez tontof pour savoir comment mettre un bookmarklet. Sinon, pour tester sur des exemples à la con, c'est ici.

Si vous cliquez sur un élément, puis sur un second, appuyez sur la touche p pour trier. Cela trie de façon croissante ou décroissante, selon que le premier élément est plus grand que le second ou non. Les entêtes des tableaux sont également sensés restés en tête du tableau.

10.4 Limites

Ça marche dans la plupart des cas. Mais je sais que ça peut ne pas marcher. Par exemple, si vous triez une ligne d'entête d'une table, elle ne reste plus en place si vous triez une colonne. Il y a également un bug sur les tables qui contiennent des multilignes. Ce n'est non plus pas possible de trier un tableau « horizontal » (et donc à double entrées). De plus, c'est pas forcément possible non plus de trier suivant des étoiles selon comment est codée la page. Par exemple, ça marche bien sur yummly, mais pas sur marmiton. Ça peut également rendre la page très moche :Þ

À part ça, j'en suis plutôt content.

Footnotes:

1

En fait, j’avais déjà commencé à m’y intéresser, mais que vaguement. J’avais dans l’idée d’apprendre les départements avec leur numéro, et j’étais tombé sur ce site : http://villemin.gerard.free.fr/Wwwgvmm/MnemoTe/Departem.htm (que je connaissais déjà pour ses « curiosités » mathématiques, comme http://villemin.gerard.free.fr/Wwwgvmm/Decompos/Amiable.htm par exemple). Je m’étais également déjà renseigné sur le « palais de la mémoire » (memory palace cité dans Sherlock ou The Mentalist). J’avais regardé comment font les gens qui font le rubik’s cube en aveugle. Et puis il y a eu quelque chose qui a fait que je me suis un peu plus penché sur la question. Mais… pas moyen de m’en souvenir :Þ

3

Qui font des choses encore plus incroyables, comme mémoriser 1000 chiffres en une heure, 10 paquets de cartes en une heure (Grand Master Memory (!wen), http://www.recordholders.org/en/list/memory.html), 44 nombres binaires en 1 secondes ! (http://blog.mnemotechnics.org/ramon-campayo-memorizing-binary-1333.html)

6

Si c’est ce que vous souhaitez faire, je conseille de prendre le plus possible 1 seule voyelle pour tous les mots (et d’utiliser toujours la même voyelle exception), comme expliqué ici. J’étais plutôt parti sur le son é lorsque j’ai commencé à essayer de faire ce tableau.

Autres billets

Date:

Generated by Emacs 24.3.1 (Org mode 8.2.4) - Show Org source (htmlized)

CSS inspired by Tontof, colors by Chaotic Soul

Validate