<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet title="XSL formatting" type="text/xsl" href="http://blog.mymind.fr/feed/rss2/xslt" ?><rss version="2.0"
  xmlns:dc="http://purl.org/dc/elements/1.1/"
  xmlns:wfw="http://wellformedweb.org/CommentAPI/"
  xmlns:content="http://purl.org/rss/1.0/modules/content/"
  xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
  <title>Mind... - Tag - Devel</title>
  <link>http://blog.mymind.fr/</link>
  <atom:link href="http://blog.mymind.fr/feed/tag/Devel/rss2" rel="self" type="application/rss+xml"/>
  <description></description>
  <language>fr</language>
  <pubDate>Thu, 01 Dec 2011 21:43:54 +0100</pubDate>
  <copyright>© 2007-2008 Florent Bruneau</copyright>
  <docs>http://blogs.law.harvard.edu/tech/rss</docs>
  <generator>Dotclear</generator>
  
    
  <item>
    <title>Afficher des discussions</title>
    <link>http://blog.mymind.fr/post/2007/11/01/Afficher-des-discussions</link>
    <guid isPermaLink="false">urn:md5:1bc6a0f2c9ce16187b5ff9f62df8c2a4</guid>
    <pubDate>Thu, 01 Nov 2007 17:24:00 +0100</pubDate>
    <dc:creator>Florent Bruneau</dc:creator>
        <category>Polytechnique.org</category>
        <category>Banana</category><category>Devel</category><category>PHP</category>    
    <description>&lt;p&gt;Lorsqu'un logiciel a pour vocation d'afficher des discussions, on attend de sa part qu'il nous permette de voir simplement qui répond à qui, dans quel contexte... Ce n'est pas toujours ce qui est le mieux fait. Par exemple, les programmes de fora en ligne à la mode (phpBB par exemple) affiche les discussion comme une succession de rectangles juxtaposés et seul le contenu du message permet de voir qu'il en cite un autre. D'autres logiciels comme Mail.app ont ce défaut et parfois la fâcheuse manie de ne pas vouloir corriger ce problème.&lt;/p&gt;


&lt;p&gt;L'affichage de l'arborescence dans &lt;a href=&quot;http://opensource.polytechnique.org/banana&quot;&gt;Banana&lt;/a&gt; est une des fonctionnalités clés... et elle va beaucoup changer dans la prochaine version.&lt;/p&gt;    &lt;h2&gt;Une ligne par entrée&lt;/h2&gt;


&lt;p&gt;La solution habituelle pour afficher l'arborescence est d'utiliser un message par ligne de telle, des + ou - pour ouvrir ou fermer les noeuds. C'est la solution actuelle de banana.&lt;/p&gt;


&lt;p&gt;&lt;img src=&quot;http://blog.mymind.fr/public/screenshots/old-thread.png&quot; alt=&quot;Banana Thread up to 1.7&quot; /&gt;&lt;/p&gt;


&lt;p&gt;Avec cette solution, on perd très rapidement en lisibilité&amp;nbsp;: dès que la discussion dépasse une vingtaine de messages, l'arborescence devient très haute et plus ça va, plus le titre dérive vers la droite rendant parfois le lien inaccessible. Lorsqu'il y a un troll, il est de fait très courant que certains nouveaux messages se trouvent perdus plusieurs pages en arrière dans l'arborescence, ou que sur certains navigateurs, il soit difficile d'y accéder. De plus l'interface se trouve souvent surchargée, à la limite de la lisibilité&amp;nbsp;: c'est dur de faire tenir un maximum d'informations en un minimum de place en gardant la lisibilité de l'ensemble.&lt;/p&gt;



&lt;h2&gt;Une solution plus visuelle&lt;/h2&gt;


&lt;p&gt;Je ne sais pas combien de personnes connaissent &lt;a href=&quot;http://home.snafu.de/stk/macsoup/&quot;&gt;MacSoup&lt;/a&gt;. Il s'agit d'un petit client NNTP pour MacOS, qui en soit n'a pas beaucoup d'intérêt (il est payant et est relativement limité). Le principal atout de MacSoup est son interface de visualisation des threads (les utilisateurs diront qu'il y a bien plus que l'interface graphique, mais également l'interface clavier etc...). On trouve sur internet quelques captures d'écran en cherchant dans les &lt;a href=&quot;http://www.exalead.com/image/results?q=macsoup%20screenshot&quot;&gt;moteurs de recherche d'image&lt;/a&gt;&amp;nbsp;:&lt;/p&gt;


&lt;p&gt;&lt;img src=&quot;http://www.fen-net.de/~xx511/bilder/macsoup/Thread.gif&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;


&lt;p&gt;Cette interface est compacte, visuelle et permet d'accéder rapidement à n'importe quel message du thread. Pour la prochaine version de Banana, je me suis fortement inspiré de cette interface pour réécrire de 0 l'affichage de l'arborescence. Ceci donne&amp;nbsp;:&lt;/p&gt;


&lt;p&gt;&lt;img src=&quot;http://blog.mymind.fr/public/screenshots/new-thread.png&quot; alt=&quot;Thread view in Banana&quot; /&gt;&lt;/p&gt;


&lt;p&gt;Il s'agit de la même discussion que précédemment. On voit donc ici facilement l'arborescence. Lorsqu'un message est non lu, la branche à laquelle il est attaché est noire au lieu de grise ce qui permet de l'identifier du premier coup d'oeil. Les couleurs de fond des noeuds (une idée de &lt;a href=&quot;http://www.falco.bz&quot;&gt;Falco&lt;/a&gt;) sont obtenue à partir d'un hash quelconque sur l'émetteur et permettent donc d'identifier les messages envoyés par la même personne. Lorsqu'on laisse la souris sur un noeud, le nom de l'expéditeur et l'heure du post s'affichent (malheureusement le pointeur de la souris n'apparaît pas sur la capture d'écran)... et bien sûr quand on clique sur un noeud, on va sur le message correspondant.&lt;/p&gt;


&lt;p&gt;Lorsqu'on est sur un message, on garde également la vue du thread ce qui permet de toujours savoir où on est dans la discussion&amp;nbsp;:&lt;/p&gt;


&lt;p&gt;&lt;img src=&quot;http://blog.mymind.fr/public/screenshots/new-thread-nav.png&quot; alt=&quot;Thread view with selected message&quot; /&gt;&lt;/p&gt;


&lt;p&gt;Il y a encore un peu de travail à faire pour améliorer les performances de la génération des arbres et pour augmenter sa compacité (éviter les branches qui descendent très bas alors qu'elles auraient pu trouver leur place dans le l'espace vide disponible).&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.mymind.fr/post/2007/11/01/Afficher-des-discussions#comment-form</comments>
      <wfw:comment>http://blog.mymind.fr/post/2007/11/01/Afficher-des-discussions#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.mymind.fr/feed/atom/comments/37</wfw:commentRss>
      </item>
    
  <item>
    <title>Compter les fichiers</title>
    <link>http://blog.mymind.fr/post/2007/08/30/Compter-les-fichiers</link>
    <guid isPermaLink="false">urn:md5:a4d72e31c767c980a39751dea09efb0a</guid>
    <pubDate>Thu, 30 Aug 2007 23:12:00 +0200</pubDate>
    <dc:creator>Florent Bruneau</dc:creator>
        <category>GeekTime</category>
        <category>Devel</category><category>pratique</category><category>zsh</category>    
    <description>&lt;p&gt;C'est un peu la suite de mon post &quot;Outils pratiques&quot; où je donnais deux scripts permettant de rendre les commandes SVN plus conviviales. Encore une fois, je réinvente sans doute la roue (des outils équivalents doivent déjà exister... sans doute en mieux), mais je pense que chercher ce genre d'outils sur internet m'aurait pris plus de temps que ce qu'il m'a fallu pour le développer.&lt;/p&gt;


&lt;p&gt;En ce moment je manipule des fichiers, beaucoup de fichiers (et même, beaucoup de gros fichiers), que j'ouvre, rouvre, et ferme et puis referme. Et à force d'ouvrir, on oublie parfois de refermer, et là, c'est comme une fuite de mémoire, sauf que le nombre limite de fichiers ouverts est beaucoup plus rapidement atteinte que la limite de mémoire... dans la configuration de base sur un linux, un programme n'a le droit qu'à 1024 descripteurs de fichiers. D'où mon problème&amp;nbsp;: comment traquer les &quot;file-handle leaks&quot;&amp;nbsp;?&lt;/p&gt;    &lt;p&gt;Pour le faire, je me suis fait rapidement un petit script qui permet d'analyser les données issues d'un &lt;code&gt;strace&lt;/code&gt;. &lt;code&gt;strace&lt;/code&gt; est, pour ceux qui ne le savent pas, un programme très pratique qui permet de lister les appels systèmes. Dans mon cas présents, surveiller les ouvertures fermetures de fichiers revient à traquer les commandes &lt;code&gt;open&lt;/code&gt; (ouverture d'un fichier), et les commandes &lt;code&gt;close&lt;/code&gt;. Donc, je récupère simplement la liste des appels à &lt;code&gt;open&lt;/code&gt; et &lt;code&gt;close&lt;/code&gt;&amp;nbsp;:&lt;/p&gt;

&lt;pre&gt;
[bash]
strace -f -e trace=open,close mon programme 2&amp;gt; /quelque/part
&lt;/pre&gt;


&lt;p&gt;Et ainsi, le fichier &lt;code&gt;/quelque/part&lt;/code&gt; contient la liste complète des appels à &lt;code&gt;open&lt;/code&gt; et &lt;code&gt;close&lt;/code&gt; effectués par mon programme (et ses processus fils). Il ne reste plus alors qu'à analyser le contenu de &lt;code&gt;/quelque/part&lt;/code&gt;. Pour ceci, il suffit de peu de lignes de code (en perl pour ma part, mais d'autres auraient fait la même chose en shell, python... ou n'importe quel langage de scripting)&amp;nbsp;:&lt;/p&gt;

&lt;pre&gt;
[perl]
#!/usr/bin/perl 
 
my %files; 
my %modes; 
my %lines; 
 
my $lineNb = 0; 
my $maxOpened = 0; 
my $currentOpened = 0; 
my $totalOpened = 0; 
 
for $line (&amp;lt;STDIN&amp;gt;) { 
  if ($line =~ /open\\(&amp;quot;([^&amp;quot;&amp;quot;]+)&amp;quot;, ([^\\)]+)\\)\\s*=\\s*(\\d+)/) { 
    $files{$3} = $1; 
    $modes{$3} = $2; 
    $lines{$3} = $lineNb; 
    $totalOpened++; 
    $currentOpened++; 
    if ($currentOpened &amp;gt; $maxOpened) { 
      $maxOpened = $currentOpened; 
    } 
  } 
  if ($line =~ /close\\((\\d+)\\)/ &amp;amp;&amp;amp; $files{$1} ne '') { 
    $files{$1} = ''; 
    $currentOpened--; 
  } 
  $lineNb++; 
} 
 
print &amp;quot;$totalOpened files opened, max. $maxOpened at the same time
&amp;quot;; 
print &amp;quot;$currentOpened files not closed
&amp;quot;; 
for $id (keys %files) { 
  local $file = $files{$id}; 
  local $mode = $modes{$id}; 
  local $line = $lines{$id}; 
 
  if ($file ne '') { 
    print &amp;quot;[line $line] id=$id, open $file with mode $mode
&amp;quot;; 
  } 
} 
&lt;/pre&gt;


&lt;p&gt;Pour simplifier le tout, on rajoute une fonction dans le &lt;code&gt;zshrc&lt;/code&gt; pour wrapper tout ça, et ça donne (attention, ceci ne fonctionne que sous linux, &lt;code&gt;mktemp&lt;/code&gt; n'a pas la même syntaxe sur MacOS, et surtout, &lt;code&gt;strace&lt;/code&gt; n'est pas disponible sur Mac&lt;/p&gt;

&lt;pre&gt;
[bash]
function checkFiles() { 
  TEMPFILE=`mktemp` 
  strace -f -e trace=open,close $* 2&amp;gt; $TEMPFILE 
  cat $TEMPFILE | ~/.zsh/trackFiles.pl 
  rm $TEMPFILE 
} 
&lt;/pre&gt;


&lt;p&gt;Avec, ça, il ne me répond&amp;nbsp;:&lt;/p&gt;

&lt;pre&gt;
% checkFiles cp test test2
12 files opened, max. 2 at the same time
0 files not closed
&lt;/pre&gt;


&lt;p&gt;Si maintenant, je fais un programme minimaliste qui oublie de fermer un fichier&amp;nbsp;:&lt;/p&gt;

&lt;pre&gt;
[c]
#include &amp;lt;stdio.h&amp;gt; 
 
int main() { 
  FILE* file = fopen(&amp;quot;test&amp;quot;, &amp;quot;r&amp;quot;); 
  return file != NULL ? 0 : 1; 
} 
&lt;/pre&gt;

&lt;pre&gt;
% gcc test.c -o tester
% checkFiles ./tester
3 files opened, max. 1 at the same time
1 files not closed
[line 4] id=3, open test with mode O_RDONLY
&lt;/pre&gt;


&lt;p&gt;Voilà, maintenant je sais que mon programme oublie de fermer un fichier, que ce fichier s'appelle &quot;test&quot;, et qu'il est ouvert en read-only. La ligne &quot;4&quot; est la ligne dans la sortie de &lt;code&gt;strace&lt;/code&gt;, et n'a aucun rapport avec la ligne 4 du fichier source (contrairement aux apparences).&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.mymind.fr/post/2007/08/30/Compter-les-fichiers#comment-form</comments>
      <wfw:comment>http://blog.mymind.fr/post/2007/08/30/Compter-les-fichiers#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.mymind.fr/feed/atom/comments/35</wfw:commentRss>
      </item>
    
  <item>
    <title>Templates en C</title>
    <link>http://blog.mymind.fr/post/2007/08/16/Templates-en-C</link>
    <guid isPermaLink="false">urn:md5:305c30979642387ee13cea31a6b77855</guid>
    <pubDate>Thu, 16 Aug 2007 22:53:00 +0200</pubDate>
    <dc:creator>Florent Bruneau</dc:creator>
        <category>GeekTime</category>
        <category>C</category><category>Cpp</category><category>Devel</category>    
    <description>&lt;p&gt;En C++, il existe un mécanisme extrêmement pratique pour généré du code générique&amp;nbsp;: les templates. Une fonction templatée est une fonction dont le code comporte un trou qui sera remplacé à la compilation par le nom d'un type, ou une valeur... Par exemple&amp;nbsp;:&lt;/p&gt;

&lt;pre&gt;
template &amp;lt;class T&amp;gt; 
T read(const char *buffer) 
{
    T val;
    memcpy(&amp;amp;val, buffer, sizeof(T));
    return val;
} 
&lt;/pre&gt;


&lt;p&gt;Cette fonction lit un objet de type T sur un buffer. L'intérêt de cette fonction est très compréhensible&amp;nbsp;: quel que soit le type qu'on fournit à la fonction, elle va fonctionner, en adaptant la taille à lire au type. C'est donc beaucoup plus rapide que d'écrire une fonction pour chaque type... et l'utilisation est également très simple&amp;nbsp;:&lt;/p&gt;

&lt;pre&gt;
read&amp;lt;int&amp;gt;(const char* buffer) // lit un entier sur le buffer
read&amp;lt;double&amp;gt;(const char* buffer) // lit un double sur le buffer
read&amp;lt;MaClass&amp;gt;(const char* buffer) // lit un objet de type &amp;quot;MaClass&amp;quot;
&lt;/pre&gt;


&lt;p&gt;Mais cette syntaxe n'est qu'un sucre syntaxique, car en fait, on peut également faire des templates en C...&lt;/p&gt;    &lt;h3&gt;Comment fonctionne les templates&amp;nbsp;?&lt;/h3&gt;


&lt;p&gt;En fait un template est, comme son nom l'indique, qu'un modèle de fonction. Lors de la compilation d'un programme qui utilise des templates, le compilateur regarde la liste des instances de cette fonction qui sont utilisées et les génère. Plus explicitement, si j'appelle read&amp;lt;double&amp;gt;(), le compilateur va générer cette fonction&amp;nbsp;:&lt;/p&gt;

&lt;pre&gt;
[cpp]
double read&amp;lt;double&amp;gt;(const char *buffer) 
{
    double val;
    memcpy(&amp;amp;val, buffer, sizeof(double));
    return val;
}
&lt;/pre&gt;


&lt;p&gt;Ainsi, l'appel à read&amp;lt;double&amp;gt; devient un appel de fonction classique.&lt;/p&gt;


&lt;h3&gt;Jeu de préprocesseur&lt;/h3&gt;


&lt;p&gt;Le préprocesseur en C possède des outils sympathique... Nous nous attarderons particulièrement sur le ##. Il s'agit tout simplement d'un opérateur de concaténation. Donc&amp;nbsp;:&lt;/p&gt;

&lt;pre&gt;
[c]
#define Truc(Machin) Truc ## Machin

Truc(Bidule) /* génère TrucBidule */
&lt;/pre&gt;


&lt;p&gt;C'est donc très pratique. On peut facilement par exemple, imaginer une petite macro du genre&amp;nbsp;:&lt;/p&gt;

&lt;pre&gt;
[c]
#define maFonction(Type) maFonction_ ## Type
&lt;/pre&gt;


&lt;p&gt;Si dans ce cas, on défini par exemple maFonction_int, maFonction_double, maFonction_MaStruct (oui, les classes n'existent pas en C), on pourra faire&lt;/p&gt;

&lt;pre&gt;
[c]
maFonction(int)(args); /* appelle maFonction_int */
maFonction(double)(args); /* appelle maFonction_double */
maFonction(MaStruct)(args); /* appelle maFonction_MaStruct */
&lt;/pre&gt;


&lt;p&gt;Maintenant, il ne reste plus qu'à générer les fonctions... sans avoir à toutes les écrire une à une. Pour ceci, nous allons encore une fois profiter de la présence du préprocesseur.&lt;/p&gt;

&lt;pre&gt;
[c]
#define maFonctionBuild(Type) \\
  Type maFonction_ ## Type(const char* buffer) { \\
    Type val; \\
    memcpy(&amp;amp;val, buffer, sizeof(Type)); \\
    return val; \\
  } 

maFonctionBuild(int) /* génère maFonction_int */
maFonctionBuild(double) /* génère maFonction_double */
maFonctionBuild(MaStruct) /* génère maFonction_MaStruct */
&lt;/pre&gt;


&lt;p&gt;Il ne reste donc qu'à appeler maFonctionBuild(Type) sur chacun des types pour lesquels nous avons besoin d'instancier la fonction, et d'appeler maFonction(Type) chaque fois qu'on veut appeler maFonction pour le type en question. D'une certaine manière on peut dès lors dire que les fonctions sont&amp;nbsp;:&lt;/p&gt;

&lt;pre&gt;
[c]
Type maFonction(Type)(const char* buffer);
&lt;/pre&gt;


&lt;h3&gt;Et voilà&amp;nbsp;!&lt;/h3&gt;


&lt;p&gt;Nous avons donc une implémentation générique grâce au préprocesseur associé à un appel typé. Ce n'est évidemment qu'une astuce de préprocesseur, mais cela donne une souplesse syntaxique agréalble&amp;nbsp;: &quot;J'appelle maFonction appliquée sur les entiers avec les arguments args&quot;.&lt;/p&gt;


&lt;p&gt;Tout ceci est certes, moins souple que les templates C++&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;il n'y a pas d'auto-instanciation par le compilateur&amp;nbsp;: il faut &quot;manuellement&quot; instancier la fonction pour tous les types pour lesquels ont l'appelle&lt;/li&gt;
&lt;li&gt;il n'y a pas de &quot;type check&quot;&amp;nbsp;: les seules limites sont celle de la compilation&lt;/li&gt;
&lt;li&gt;le correction des erreurs de compilation est fastidieuse car toutes les erreurs apparaissent comme étant à la ligne d'appel à maFonctionBuild&lt;/li&gt;
&lt;li&gt;il est rapidement fastidieux de rajouter l'antislash à la fin de chaque ligne de la définition de la fonction&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Comme on le voit dans les choix de l'exemple, pour les entrées/sorties, ça permet d'avoir une seule fonction à écrire tout en gardant la flexibilité d'une fonction par type de données.&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.mymind.fr/post/2007/08/16/Templates-en-C#comment-form</comments>
      <wfw:comment>http://blog.mymind.fr/post/2007/08/16/Templates-en-C#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.mymind.fr/feed/atom/comments/34</wfw:commentRss>
      </item>
    
  <item>
    <title>Comprendre du code</title>
    <link>http://blog.mymind.fr/post/2007/08/15/Comprendre-du-code</link>
    <guid isPermaLink="false">urn:md5:166320b7eed5bae3b2f101cffa3b53e9</guid>
    <pubDate>Wed, 15 Aug 2007 01:28:00 +0200</pubDate>
    <dc:creator>Florent Bruneau</dc:creator>
        <category>GeekTime</category>
        <category>Devel</category>    
    <description>&lt;p&gt;J'ai tenté cet après-midi une petite expérience sur IRC. J'ai posté 3 lignes de code en demandant &quot;que font ces trois lignes&quot;. Après quelques minutes (sans doute trop peu), j'ai donné la solution car personne n'avait vraiment trouvé. En effet, même si on réussi facilement à lire le code et à reconstituer la suite d'opération qu'il génère, il est très difficile de vraiment comprendre ce qu'il fait, d'imaginer son application dans un contexte et d'en déduire son usage.&lt;/p&gt;


&lt;p&gt;Juste pour continuer à m'amuser, et pour amuser ceux qui se perdraient ici, voici le code en question.&lt;/p&gt;    &lt;pre&gt;
[c]
do {
  ++(*pos);
} while (*(pos++) == 0);
&lt;/pre&gt;


&lt;p&gt;Vous pouvez remarquer dès à présent que ce code n'est pas volontairement rendu illisible (il serait facile de supprimer des parenthèses et de changer le test de nullité en une négation. Le but est donc de comprendre la suite d'instruction, de dire ce qu'elle fait et ensuite de comprendre dans quel contexte elle est utilisable. La question est aussi de savoir en combien de temps vous allez trouver la solution.&lt;/p&gt;

&lt;script type=&quot;text/javascript&quot; src=&quot;http://blog.mymind.fr/jquery.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;//&lt;![CDATA[
function show_answer() {
  $(&quot;#show_answer&quot;).hide();
  $(&quot;#answer&quot;).show(&quot;slow&quot;);
  return false;
}
//]]&gt;&lt;/script&gt;
&lt;p&gt;
&lt;a href=&quot;http://blog.mymind.fr/post/2007/08/15/&quot; onclick=&quot;return show_answer()&quot; id=&quot;show_answer&quot;&gt;Cliquer ici pour afficher la répondre&lt;/a&gt;
&lt;/p&gt;
&lt;div id=&quot;answer&quot; style=&quot;display: none&quot;&gt;


&lt;h3&gt;Fonctionnement&lt;/h3&gt;


&lt;p&gt;Si on lit le code, on voit qu'il fait la suite d'opération suivante&amp;nbsp;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;on incrémente la valeur pointée par pos&lt;/li&gt;
&lt;li&gt;on regarde si la valeur obtenue est nulle&lt;/li&gt;
&lt;li&gt;on incrémente le pointeur pos&lt;/li&gt;
&lt;li&gt;si le test 2 est vrai, on retourne en 1, sinon, on quitte la boucle&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Il s'agit donc d'une petite boucle qui incrémente des objets successifs jusqu'à ce qu'elle en trouve un qui, une fois incrémenté, n'est pas nul.&lt;/p&gt;


&lt;p&gt;Voilà donc la solution du pauvre au problème, celle qu'on peut trouver en lisant le code, sans chercher à le comprendre.&lt;/p&gt;


&lt;h3&gt;Interprétation&lt;/h3&gt;


&lt;p&gt;Mais en fait, ce code va plus loin. Imaginons maintenant la zone mémoire sur laquelle pos pointe initialement&amp;nbsp;:&lt;/p&gt;
&lt;pre&gt;
 oct1 oct2 oct3 oct4
  ^
 pos
&lt;/pre&gt;


&lt;p&gt;L'octet 1 à une certaine valeur. Je l'incrémente et je m'aperçois que sa nouvelle valeur est 0. Quand un octet incrémenté peut-il retomber à 0&amp;nbsp;? Quand il fait un overflow. On a donc fait déborder le premier octet... et quand cet octet déborde on incrémente le suivant&amp;nbsp;:&lt;/p&gt;
&lt;pre&gt;
    _+1__
   |     |
 oct1 oct2 oct3 oct4
       ^
      pos
&lt;/pre&gt;


&lt;p&gt;Il s'agit donc ni plus ni moins que d'une retenue (comme quand on apprend à faire les additions ou les multiplications)&amp;nbsp;: quand je fais déborder un octet, je déplace le surplus vers le suivant. Finalement, ces 3 lignes de code ne sont que l'implémentation d'une incrémentation, mais sur plusieurs octets... et même sur un nombre non défini d'octets (puisqu'il n'y a pas de limite explicitée sur le nombre d'étapes autorisées).&lt;/p&gt;


&lt;p&gt;Pour être plus précis, il s'agit d'un incrémenteur d'entier stocké en Little Endian sur un nombre illimité d'octets.&lt;/p&gt;


&lt;h3&gt;Encore&amp;nbsp;?&lt;/h3&gt;


&lt;p&gt;Bon, pour ceux qui tiennent vraiment à s'assurer que ce n'est pas du code illisible, voici une version vraiment illisible de la même machine&amp;nbsp;:&lt;/p&gt;
&lt;pre&gt;
[c]
for(++*pos;!*pos++;++*pos);
&lt;/pre&gt;


&lt;p&gt;(Merci Falco)&lt;/p&gt;


&lt;p&gt;Tout ceci n'était bien sûr qu'un exemple. Il est toujours très dur de comprendre du code, alors pour éviter de passer dix minutes sur 3 lignes lors de la prochaine relecture il suffit de documenter ce qu'on écrit.&lt;/p&gt;

&lt;/div&gt;
</description>
    
    
    
          <comments>http://blog.mymind.fr/post/2007/08/15/Comprendre-du-code#comment-form</comments>
      <wfw:comment>http://blog.mymind.fr/post/2007/08/15/Comprendre-du-code#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.mymind.fr/feed/atom/comments/33</wfw:commentRss>
      </item>
    
  <item>
    <title>Khtml2png 2.6.5 est sorti</title>
    <link>http://blog.mymind.fr/post/2007/06/05/Khtml2png-265-est-sorti</link>
    <guid isPermaLink="false">urn:md5:58bbe8d3b518ea224316f6e597d9ddbb</guid>
    <pubDate>Tue, 05 Jun 2007 22:31:00 +0200</pubDate>
    <dc:creator>Florent Bruneau</dc:creator>
        <category>GeekTime</category>
        <category>Devel</category><category>khtml2png</category>    
    <description>    &lt;p&gt;Après 3 mois d'un travail pas très intensif, une nouvelle version de &lt;a href=&quot;http://khtml2png.sf.net&quot;&gt;khtml2png&lt;/a&gt; est disponible. Cette version est partie du fait que les versions précédentes du programme ont parfois du mal à gérer les grandes captures d'écran (en fait, des bugs peuvent apparaître dès que la taille de la zone à capturer est plus grande que la taille affichable).&lt;/p&gt;


&lt;p&gt;Donc, rapidement après la sortie de la 2.6.0, j'avais envoyé un correctif (en fait une réécriture du moteur de rendu) au développeur de &lt;code&gt;khtml2png&lt;/code&gt;. Malheureusement, ce correctif ne fonctionnait pas correctement chez lui. Donc, pendant 3 mois, j'ai fait du débuggage à distance&amp;nbsp;: j'envoie une version modifiée (1 ou 2 lignes à chaque fois), j'attends 2 ou 3 semaine une réponse, etc... Du développement efficace&amp;nbsp;!&lt;/p&gt;


&lt;p&gt;Bon, toujours est-il que maintenant, la version 2.6.5 fonctionne à la fois chez moi (à la fois Debian + xvnc et sur MacOS X), et chez Hauke (sur Debian également, mais avec des réglages différents).&lt;/p&gt;


&lt;p&gt;Le Changelog annonce&amp;nbsp;:&lt;/p&gt;


&lt;blockquote&gt;&lt;p&gt;fix: Now produces screenshots on my Debian Etch system under KDE 3.5.5 without glitches. &lt;br /&gt;
fix: Maybe better working on other systems too. Please test.&lt;/p&gt;&lt;/blockquote&gt;


&lt;p&gt;J'aimerais y rajouter quelques points&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;meilleur moteur de rendu (qui ne scroll plus, mais déplace la fenêtre pour s'affranchir de certains bugs de KDE et/ou Qt)&lt;/li&gt;
&lt;li&gt;meilleure détection de la taille de la capture à réaliser&lt;/li&gt;
&lt;li&gt;possibilité de choisir le comportement de &lt;code&gt;khtml2png&lt;/code&gt; face aux redirections, au javascript, au java, au flash... via la ligne de commande&lt;/li&gt;
&lt;li&gt;la détection automatique de la dimension par un &lt;code&gt;id&lt;/code&gt; devient compatible avec le format utilisé dans les version &amp;lt;= 2.5&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Comme d'habitude, vous pouvez télécharger &lt;a href=&quot;http://blog.mymind.fr/mind/public/khtml2png/khtml2png-fru-last.tar.bz2&quot;&gt;ma dernière version du programme&lt;/a&gt;.&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.mymind.fr/post/2007/06/05/Khtml2png-265-est-sorti#comment-form</comments>
      <wfw:comment>http://blog.mymind.fr/post/2007/06/05/Khtml2png-265-est-sorti#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.mymind.fr/feed/atom/comments/30</wfw:commentRss>
      </item>
    
  <item>
    <title>Et si on oubliait les bases ?</title>
    <link>http://blog.mymind.fr/post/2007/05/26/Et-si-on-oubliait-les-bases</link>
    <guid isPermaLink="false">urn:md5:fe3ef04de8c5c8b32ac7e89741c86760</guid>
    <pubDate>Sat, 26 May 2007 11:40:00 +0200</pubDate>
    <dc:creator>Florent Bruneau</dc:creator>
        <category>GeekTime</category>
        <category>Devel</category><category>Mac</category><category>POSIX</category><category>VirtueDesktops</category>    
    <description>&lt;p&gt;MacOS X est un Unix... compatible POSIX. Voilà ce qu'un certain nombre de personnes semblent oublier assez fréquemment. C'est assez dommage quand ces personnes programment pour MacOS, on se retrouve parfois avec du code complexe pour réécrire des fonctions POSIX (en moins bien ?).&lt;/p&gt;    &lt;p&gt;En fait si je parle de ça, c'est parce que je viens de rencontrer le problème dans le cadre du développement de &lt;a href=&quot;http://blog.mymind.fr/post/2007/05/18/VirtueDesktops-revient&quot;&gt;VirtueDesktops&lt;/a&gt;. Il se trouve qu'en parcourant le tracker du projet je suis tombé sur le &lt;a href=&quot;http://trac.virtuedesktops.info/ticket/115&quot;&gt;ticket 115&lt;/a&gt; qui s'intitule&amp;nbsp;:&lt;/p&gt;


&lt;blockquote&gt;&lt;p&gt;Patch to check group id of 'procmod' group&lt;/p&gt;&lt;/blockquote&gt;


&lt;p&gt;C'est intéressant... jusqu'à maintenant Virtue suppose que le gid du groupe procmod est celui par défaut de MacOS (c'est à dire qu'il vaut 9)... et le problème est donc que si un utilisateur a un procmod différent (ou si Apple décide un jour de changer le gid du groupe), le code actuel peut avoir des résultats inattendus, il faut donc faire un code plus portable qui recherche le gid de procmod au lieu de le stocker en dur. Ce n'est clairement pas une mauvaise idée&amp;nbsp;! Seul problème, le patch soumis est le suivant (au cas où certain voudrait réutiliser ce code, je tiens à signaler que c'est une mauvaise idée !)&amp;nbsp;:&lt;/p&gt;

&lt;pre&gt;
[c]
#define NI_DOMAIN	&amp;quot;.&amp;quot;
#define NI_PATH		&amp;quot;/name=groups/name=procmod&amp;quot;
#define NI_KEY		&amp;quot;gid&amp;quot;

// Sucked from netinfo-369.5/tools/niutil/niutil.c
ni_status ni_read_single_prop(char **property)
{
	const char *args[] = {NI_DOMAIN, NI_PATH, NI_KEY};
	
	char myname[] = &amp;quot;ni_read_single_prop&amp;quot;;
	const bool opt_tag = false;
	const int timeout = 30;
	
	ni_namelist nl;
	void *domain;
	ni_id dir;	
	ni_status ret;

	if ((ret = do_open(myname, args[0], &amp;amp;domain, opt_tag, timeout, NULL, NULL)) != 0) return ret;

	/* args[1] should be a directory specification */
	ret = ni2_pathsearch(domain, &amp;amp;dir, args[1]);
	if (ret != NI_OK) {
		fprintf(stderr, &amp;quot;%s: can't open directory %s: %s
&amp;quot;, myname, args[1], ni_error(ret));
		ni_free(domain);
		return ret;
	}

	/* get the property values for args[2] */
	NI_INIT(&amp;amp;nl);
	ret = ni_lookupprop(domain, &amp;amp;dir, args[2], &amp;amp;nl);
	if (ret != NI_OK) {
		fprintf(stderr, &amp;quot;%s: can't get property %s in directory %s: %s
&amp;quot;, myname, args[2], args[1], ni_error(ret));
		ni_free(domain);
		return ret;
	}
	
	
	if (nl.ni_namelist_len != 1) {
		fprintf(stderr, &amp;quot;%s: expected length = 1, found length = %d
&amp;quot;, myname, nl.ni_namelist_len);
		return NI_FAILED;
	}
	
	*property = (char*)calloc(strlen(nl.ni_namelist_val[0]) + 1, sizeof(char));
	strcpy(*property, nl.ni_namelist_val[0]);
	
	ni_namelist_free(&amp;amp;nl);
	ni_free(domain);
	
	return NI_OK;
}
&lt;/pre&gt;


&lt;p&gt;Donc que fait cette fonction&amp;nbsp;? C'est assez simple&amp;nbsp;: elle utilise l'utilitaire NetInfo d'Apple pour lire les informations relatives au chemin &lt;code&gt;/groups/procmod&lt;/code&gt;. Une fois là dedans elle copie la valeur stockée à la clé &lt;code&gt;gid&lt;/code&gt; et renvoie cette chaîne dans le pointeur passé en argument.&lt;/p&gt;


&lt;p&gt;Il n'y a pas à dire... c'est une solution qui devrait fonctionner (enfin j'ai même un doute, car je ne vois pas le groupe procmod apparaître quand je regarde dans NetInfo). Seulement cette solution montre clairement que la personne qui l'a écrite savait que MacOS utilise un système de groupes, mais avait oublié qu'en fait c'est avant tout un système POSIX. Et là, ce qui est intéressant c'est que sous MacOS X on a accès à l'API POSIX... en particulier à la fonction &lt;code&gt;getgrnam&lt;/code&gt; qui retourne les informations sur un groupe à partir de son nom.&lt;/p&gt;


&lt;p&gt;Donc, pas besoin de dépendance vers NetInfo, pas besoin d'une recherche dans une arborescence abstraite&amp;nbsp;: NetInfo n'est qu'une abstraction de la couche Unix pour simplifier l'accès aux données par les utilisateurs... mais ça ne doit pas être un framework d'abstraction de l'API POSIX ce qui entraîne nécessairement du code moins portable (et surtout, moins lisible dans le cas présent), moins rapide et plus lourd.&lt;/p&gt;


&lt;p&gt;Ici, le code est utilisé dans un programme en C qui est chargé de mettre un objet dans le groupe procmod pour autoriser Virtue à effectuer certaines actions qui nécessitent un accès privilégié au serveur graphique... ce programme ne fait &lt;em&gt;que&lt;/em&gt; changer les permissions. Pourquoi utiliser une API lourde et spécifique à MacOS alors que ce type de programme pourrait clairement être utilisé sur n'importe quel Unix&amp;nbsp;?&lt;/p&gt;


&lt;p&gt;Voici donc une solution qui fait la même chose que la fonction ci-dessus, en mieux et surtout en beaucoup moins de lignes&amp;nbsp;:&lt;/p&gt;

&lt;pre&gt;
[c]
#include &amp;lt;grp.h&amp;gt;

static int getProcmodGid()
{
    struct group* groupDesc; 
    int gid = -1; 
    groupDesc = getgrnam(&amp;quot;procmod&amp;quot;); 
    if (groupDesc) {
        gid = groupDesc-&amp;gt;gr_gid; 
        free(groupDesc); 
    } 
    return gid; 
}
&lt;/pre&gt;


&lt;p&gt;Pourquoi cette solution est-elle meilleure&amp;nbsp;?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;elle retourne un entier... on a donc pas besoin de faire une conversion a posteriori&lt;/li&gt;
&lt;li&gt;elle utilise l'API POSIX et est donc utilisable sur n'importe quel OS POSIX (donc quasiment tous... à l'exception de Windows)&lt;/li&gt;
&lt;li&gt;elle évite toute manipulation inutile de chaîne de caractères&lt;/li&gt;
&lt;li&gt;elle est ne nécessite pas de charger une bibliothèque supplémentaire&amp;nbsp;: &lt;code&gt;getgrnam&lt;/code&gt; est dans la &lt;code&gt;libc&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;elle est drôlement plus courte non&amp;nbsp;?&lt;/li&gt;
&lt;/ul&gt;</description>
    
    
    
          <comments>http://blog.mymind.fr/post/2007/05/26/Et-si-on-oubliait-les-bases#comment-form</comments>
      <wfw:comment>http://blog.mymind.fr/post/2007/05/26/Et-si-on-oubliait-les-bases#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.mymind.fr/feed/atom/comments/28</wfw:commentRss>
      </item>
    
  <item>
    <title>VirtueDesktops revient...</title>
    <link>http://blog.mymind.fr/post/2007/05/18/VirtueDesktops-revient</link>
    <guid isPermaLink="false">urn:md5:5c8f94c8bfb5d09c36d4dd26d5f77d45</guid>
    <pubDate>Fri, 18 May 2007 12:25:00 +0200</pubDate>
    <dc:creator>Florent Bruneau</dc:creator>
        <category>GeekTime</category>
        <category>Devel</category><category>Mac</category><category>VirtueDesktops</category>    
    <description>&lt;p&gt;Voici plus ou moins trois mois que j'ai découvert &lt;a href=&quot;http://synergy2.sf.net&quot;&gt;synergy&lt;/a&gt;, c'est vraiment très agréable de pouvoir contrôler les deux ordinateurs sans changer de clavier/souris continuellement. Seul problème, c'est que sur la machine qui héberge le serveur &lt;code&gt;synergy&lt;/code&gt;, &lt;a href=&quot;http://virtuedesktops.info&quot;&gt;VirtueDesktops&lt;/a&gt;, un &lt;em&gt;excellent&lt;/em&gt; gestionnaire de bureaux virtuels pour MacOS, n'arrête pas de crasher. J'avais donc posté un bugreport sur le trac de Virtue... malheureusement pour diverses raisons, Tony Arnold a décidé peu après de stopper le développement de Virtue.&lt;/p&gt;    &lt;p&gt;J'ai donc pris mon courage à 2 mains, et je me suis doucement plongé dans le code de VirtueDesktops (c'est vraiment bien les applications OpenSource). Il y a maintenant deux semaines, j'ai soumis le patch permettant de corriger le crash dont je souffrais. Depuis, ce patch a été publié ce qui a conduit la &lt;a href=&quot;http://virtuedesktops.info/index.php/2007/05/14/virtuedesktops-054-beta-3/&quot;&gt;release de la bêta 3 de Virtue 0.54&lt;/a&gt;.&lt;/p&gt;


&lt;p&gt;Je me suis relancé dans le développement cette semaine en me fixant comme objectif de corriger plusieurs comportements énervants de Virtue. Par exemple, si je dis que &lt;code&gt;Mail.app&lt;/code&gt; doit être sur le bureau Mail, je veux que &lt;strong&gt;toutes&lt;/strong&gt; les fenêtres de &lt;code&gt;Mail.app&lt;/code&gt; aillent forcément sur ce bureau. Seul problème, c'est que lorsque je reçois une notification de l'arrivée d'un nouveau mail et que je clique sur cette notification, une fenêtre avec le message s'ouvre sur le bureau courant, et Virtue tourne pour atteindre le bureau de Mail.app... résultat&amp;nbsp;: j'ai changé de bureau mais je n'ai pas accès à la fenêtre que je voulais voir. J'ai corrigé ce comportement, désormais, la fenêtre est automatiquement déplacée sur le bureau de &lt;code&gt;Mail.app&lt;/code&gt; lors de son ouverture.&lt;/p&gt;


&lt;p&gt;Autres corrections diverses&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;lorsqu'on ferme une application Virtue reste sur le bureau courant (sauf si il n'y a plus rien sur le bureau courant)&lt;/li&gt;
&lt;li&gt;lorsqu'on choisi de changer de bureau, Virtue active désormais la dernière application active connue pour le nouveau bureau&lt;/li&gt;
&lt;li&gt;lorsqu'on restaure une fenêtre qui était dans le Dock, soit l'application a le droit d'être sur le bureau courant et la fenêtre est affichée sur ce bureau sans chercher à changer de bureau, soit l'application est attribuée à un bureau et dans ce cas la fenêtre est restaurée sur le bureau de l'application et Virtue change de bureau&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ces changements ont abouti à la &lt;a href=&quot;http://virtuedesktops.info/index.php/2007/05/18/virtuedesktops-054-beta-4/&quot;&gt;bêta 4&lt;/a&gt; et se résument à&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Changing to desktops when you launch, activate, deactivate, minimise, restore or quit an application should be much more consistent;&lt;/li&gt;
&lt;li&gt;Window ordering when changing desktops should be much more consistent;&lt;/li&gt;
&lt;/ul&gt;</description>
    
    
    
          <comments>http://blog.mymind.fr/post/2007/05/18/VirtueDesktops-revient#comment-form</comments>
      <wfw:comment>http://blog.mymind.fr/post/2007/05/18/VirtueDesktops-revient#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.mymind.fr/feed/atom/comments/26</wfw:commentRss>
      </item>
    
  <item>
    <title>La Banane et l'escargot</title>
    <link>http://blog.mymind.fr/post/2007/05/07/La-Banane-et-lescargot</link>
    <guid isPermaLink="false">urn:md5:f4eb2372ed96701c79b70613de7c59fe</guid>
    <pubDate>Mon, 07 May 2007 17:44:00 +0200</pubDate>
    <dc:creator>Florent Bruneau</dc:creator>
        <category>Polytechnique.org</category>
        <category>Banana</category><category>Devel</category><category>PHP</category>    
    <description>&lt;p&gt;La release de &lt;a href=&quot;http://opensource.polytechnique.org/banana/&quot;&gt;Banana&lt;/a&gt; 1.6 en même temps que celle de plat/al 0.9.14 a mis en évidence un certain nombre de faiblesses dans Banana. En particuliers la génération du spool (mise en cache de l'arborescence des messages) et des flux RSS s'est révélé extrêmement lourde pour plusieurs raisons&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;l'accès aux mbox des Mailing-Lists nécessite d'appel du &lt;code&gt;mbox-helper&lt;/code&gt;, et donc un &lt;code&gt;fork&lt;/code&gt;... opération lourde, qui répétée plusieurs fois par mbox devient rapidement très lourde lorsqu'on a plusieurs dizaines de Mailing-Lists.&lt;/li&gt;
&lt;li&gt;le traitement des données par PHP est loin d'être immédiats... et il y a clairement des goulots d'étranglement dans le code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;C'est pour ces raisons que j'ai passé Banana au &lt;code&gt;profiler&lt;/code&gt;, c'est à dire que j'ai analysé l'exécution de Banana à l'aide d'un outil qui permet de tracer l'exécution du programme et mettant un accent particuliers sur le temps d'exécution de chaque fonction. L'outil que j'ai trouvé pour faire ça est &lt;a href=&quot;http://www.xdebug.org&quot;&gt;xdebug&lt;/a&gt;, utilisé conjointement à &lt;a href=&quot;http://kcachegrind.sourceforge.net/&quot;&gt;KCacheGrind&lt;/a&gt;.&lt;/p&gt;    &lt;h2&gt;Forks&lt;/h2&gt;


&lt;p&gt;Je dois avouer que lorsque j'avais fait mes tests, je n'avais pas plusieurs centaines de Mailing-Lists à traiter... et je ne m'attendais pas à ce qu'une fois passée en production le script de mise à jour des flux RSS puisse prendre toutes les ressources de la machine pendant plusieurs minutes. Il a donc fallu sérieusement restructurer la gestion des accès aux Mailing-Lists pour restreindre au maximum le nombre d'accès au &lt;code&gt;mbox-helper&lt;/code&gt; (un petit programme écrit en C qui se charge de tous les accès aux mbox), et, en cas d'accès, limiter au maximum le temps passer sur le &lt;code&gt;mbox-helper&lt;/code&gt;.&lt;/p&gt;


&lt;p&gt;Donc désormais le &lt;code&gt;mbox-helper&lt;/code&gt; n'est plus appelé que si la mbox a changé depuis le dernier passage (le changement étant détecté par la taille du fichier). Ce qui permet donc de supprimer le lancement d'environ 500 &lt;code&gt;mbox-helper&lt;/code&gt; lors des rafraîchissements des spools (en effet, un nombre négligeable de Mailing-List aura des nouveaux messages lors du passage du script toutes les 5, 10 ou 20 minutes). Ajouté à cela la correction d'un bug qui faisait que l'appel au &lt;code&gt;mbox-helper&lt;/code&gt; oubliait de spécifier l'offset où chercher le message à traiter et qui forçait donc le &lt;code&gt;mbox-helper&lt;/code&gt; à relire la totalité de la mbox, on peut se permettre de supposer que la prochaine version de Banana sera plus efficace pour la gestion des mbox.&lt;/p&gt;



&lt;h2&gt;Array_shift&lt;/h2&gt;


&lt;h3&gt;Piles&lt;/h3&gt;


&lt;p&gt;Il est souvent extrêment pratique d'utiliser une pile de données. Cela permet de traiter les informations dans l'ordre de la pile sans excès de mémoire puisque chaque élément est dépilé avant d'être traité. C'est une technique que j'aime particulièrement lorsque j'ai une suite de lignes à traiter&amp;nbsp;: je prend un tableau contenant une ligne par entrée et je le parcours avec &lt;code&gt;array_shift&lt;/code&gt; qui permet de dépiler le premier élément du tableau. On obtient ainsi un code de la forme&lt;/p&gt;

&lt;pre&gt;
[php]
while (!is_null($line = array_shift($lines))) {
    do_something($line);
}
do_something($lines);
&lt;/pre&gt;


&lt;p&gt;Un &lt;code&gt;foreach&lt;/code&gt; peut très bien faire la même chose, mais on perd les avantages de la piles. Avec cette structure, pour avoir le même comportement que la boucle précédente, il faut ajouter un &lt;code&gt;unset()&lt;/code&gt;&amp;nbsp;:&lt;/p&gt;

&lt;pre&gt;
[php]
foreach ($lines as $key=&amp;gt;&amp;amp;$value) {
    do_something($line);
    unset($lines[$key]);
}
do_something($lines);
&lt;/pre&gt;


&lt;p&gt;Certes le &lt;code&gt;foreach&lt;/code&gt; sera sensiblement plus rapide que le &lt;code&gt;while&lt;/code&gt;/&lt;code&gt;array_shift()&lt;/code&gt; car il comprend un appel de fonction à chaque itération, mais on peut s'attendre raisonnablement à ce que cet appel soit en O(1), et ait donc un coût négligeable.&lt;/p&gt;


&lt;h3&gt;Profiler&lt;/h3&gt;


&lt;p&gt;Là où il y a un problème c'est que le profiler m'indique que &lt;code&gt;array_shift&lt;/code&gt; prend 57% du temps d'exécution de Banana. Ces 57% sont partagés entre 80000 appels à la fonction, mais le plus marquant c'est que parmi ces 80000 appels, ce ne sont que 24000 d'entre eux qui prennent la quasi-totalité du temps. Pourquoi ces appels particuliers sont-ils si lourd alors que les 60000 autres ont un coût parfaitement négligeable.&lt;/p&gt;


&lt;p&gt;La seule différence entre ces deux cas d'appels c'est que les &lt;em&gt;lourds&lt;/em&gt; traitent un énorme tableau de 24000 lignes, alors que les &lt;em&gt;légers&lt;/em&gt; traitent un grand nombre de petits tableaux de quelques dizaines de lignes chacun. Il est donc extrêmement clair que &lt;code&gt;array_shift&lt;/code&gt; &lt;strong&gt;n'est pas&lt;/strong&gt; une fonction en O(1)... J'ai donc changé la structure de code qui reflétait la structure de données par une simple boucle qui perd en lisibilité dans &lt;a href=&quot;http://opensource.polytechnique.org/viewsvn/diff.php?path=/trunk/banana/mbox.inc.php&amp;amp;rev=248&amp;amp;repname=Banana&quot;&gt;ce patch&lt;/a&gt;. Après ce changement, les 60000 &lt;code&gt;array_shift&lt;/code&gt; restant ne prennent que 0.16% du temps d'exécution de Banana...&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.mymind.fr/post/2007/05/07/La-Banane-et-lescargot#comment-form</comments>
      <wfw:comment>http://blog.mymind.fr/post/2007/05/07/La-Banane-et-lescargot#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.mymind.fr/feed/atom/comments/25</wfw:commentRss>
      </item>
    
  <item>
    <title>0.9.14 en ligne !</title>
    <link>http://blog.mymind.fr/post/2007/04/29/0914-en-ligne</link>
    <guid isPermaLink="false">urn:md5:200148e068514954b2f5974a8553116d</guid>
    <pubDate>Sun, 29 Apr 2007 19:09:00 +0200</pubDate>
    <dc:creator>Florent Bruneau</dc:creator>
        <category>Polytechnique.org</category>
        <category>Devel</category><category>platal</category>    
    <description>&lt;p&gt;Ca y est, comme annoncé dans &lt;a href=&quot;http://blog.mymind.fr/mind/post/2007/03/30/Un-apercu-de-la-version-0914-de-plat/al&quot;&gt;mon billet de fin mars&lt;/a&gt;, la version 0.9.14 de &lt;a href=&quot;http://opensource.polytechnique.org/platal&quot;&gt;plat/al&lt;/a&gt; est en ligne depuis vendredi soir. Comme expliqué précédemment, cette version apporte un grand nombre d'innovations comme &lt;a href=&quot;http://blog.mymind.fr/mind/post/2007/02/25/Un-client-RSS-pour-lire-les-Forums-NNTP-et-les-Mailing-Lists&quot;&gt;le flux RSS pour les Mailing-Lists et les Fora&lt;/a&gt;, la &lt;a href=&quot;http://blog.mymind.fr/mind/post/2007/03/15/Soundex-Francais&quot;&gt;recherche par proximité sonore améliorée&lt;/a&gt; et généralisée, un système d'annonces retravaillé pour offrir un approche plus conviviale, et bien sûr, le passage en UTF-8.&lt;/p&gt;


&lt;p&gt;Mais de tout cela, j'en ai déjà parlé... je tiens par contre à m'étendre sur les quelques fonctionnalités qui ont été développées durant le dernier mois (en fait, durant les dernières deux semaines de développement, le reste du temps ayant été consacré aux tests).&lt;/p&gt;    &lt;h2&gt;Recherche interactive&lt;/h2&gt;


&lt;p&gt;Caribou a réalisé un énorme travail sur la mise en place d'un remplissage automatique (auto-completion pour les geeks) sur la recherche avancée. Ainsi, lorsqu'on tape quelques caractères dans un champ, une liste de propositions apparaît avec pour chaque proposition le nombre de camarades correspondant à la requête. Ce qui donne par exemple&amp;nbsp;:&lt;/p&gt;


&lt;p&gt;&lt;img src=&quot;http://blog.mymind.fr/mind/public/screenshots/select-ville.png&quot; alt=&quot;Auto-Completion sur les villes&quot; /&gt;&lt;/p&gt;


&lt;p&gt;&lt;img src=&quot;http://blog.mymind.fr/mind/public/screenshots/select-pays.png&quot; alt=&quot;Auto-Completion sur les pays&quot; /&gt;&lt;/p&gt;


&lt;p&gt;Par contre, là où cela devient très intéressant, c'est que l'interface reste flexible&amp;nbsp;: si vous préférez choisir dans une liste des valeurs possibles plutôt que d'utiliser l'auto-completion, ce qui est envisageable, il suffit, si c'est disponible pour le champ correspondant, de cliquer sur la petite icône représentant une liste en fin de ligne... Ainsi, pour les pays, cela donne&amp;nbsp;:&lt;/p&gt;


&lt;p&gt;&lt;img src=&quot;http://blog.mymind.fr/mind/public/screenshots/select-pays-dropdown.png&quot; alt=&quot;Choix sur les pays&quot; /&gt;&lt;/p&gt;


&lt;p&gt;Il s'agit du même champ dont le &amp;lt;input type=&quot;text&quot;&amp;gt; a été remplacé par une &amp;lt;select&amp;gt;.&lt;/p&gt;


&lt;h2&gt;Sondages&lt;/h2&gt;


&lt;p&gt;Les sondages étaient la seule fonctionnalité du site qui avait été perdue lors du passage à plat/al il y a maintenant 2 ans et demi. C'est maintenant réparé grâce au travail de pika. Cette fonctionnalité étant de fait encore jeune, on peut s'attendre à ce que l'interface soit retravaillée fortement dans les prochaines versions du site pour s'adapter aux attentes des utilisateurs. Néanmoins, il est à noter que l'édition des sondages a été travaillée de telle sorte qu'un sondage soit facilement éditable&amp;nbsp;: l'utilisateur qui crée un sondage peut aisément ajouter, supprimer ou modifier des questions, et les administrateurs ont accès exactement aux mêmes fonctionnalités pour la maintenance des sondages.&lt;/p&gt;


&lt;p&gt;Nous attendons maintenant l'utilisation de cette fonctionnalité pour avoir des retours de la part de nos utilisateurs. Si l'expérience se révèle concluante, les sondages seront intégrés à Polytechnique.net pour que les animateurs les aient à leur disposition directement depuis l'interface de gestion des groupes.&lt;/p&gt;


&lt;h2&gt;Ensemble d'utilisateurs&lt;/h2&gt;


&lt;p&gt;Il s'agit de la partie sur laquelle j'ai travaillé, et donc celle que je connais le mieux, mais c'est aussi la partie la plus abstraite. Pour l'utilisateur, ça ne change quasiment rien, par contre au niveau du moteur du site, c'est à mon sens un pas en avant important vers des interfaces plus adaptées aux besoins des utilisateurs. C'est pour cette raison que cette partie risque d'être un poil technique.&lt;/p&gt;


&lt;p&gt;Ce dont je parlais au paragraphe précédent est la gestion des ensembles d'utilisateurs... mais qu'est-ce donc&amp;nbsp;? un ensemble d'utilisateur est tout simplement une sélection d'utilisateurs dans l'annuaire, ça peut être les membres d'une Mailing-List, les contacts d'un utilisateur, les membres d'un groupe, les camarades correspondant à une recherche...&lt;/p&gt;


&lt;p&gt;Le problème est que je voudrais que dès que sélectionne un ensemble d'utilisateur, je puisse séparer totalement la représentation de ces utilisateurs de la sélection qui est faite&amp;nbsp;: ainsi si je choisi mes contacts, je veux pouvoir afficher mes contacts sur un planisphère, voir le trombinoscope de mes contacts, mais aussi voir leurs fiches... mais je voudrais avoir les mêmes outils pour toute autre sélection d'utilisateur.&lt;/p&gt;


&lt;p&gt;La résolution propre de ce problème (c'est-à-dire, sans tout recoder à chaque cas possible d'utilisation) est l'utilisation d'un outil orienté Model/View&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;le modèle gère la parti sélection des utilisateurs en fonction de la page&lt;/li&gt;
&lt;li&gt;l'afficheur sélectionne les données à afficher pour les utilisateurs et génère ce que l'utilisateur verra&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Dans plat/al, le Model s'appelle PlSet (duquel hérite un UserSet spécialisé dans les ensembles d'utilisateurs), et le View s'appelle PlView. De cette manière, l'affichage des contacts se fait en 5 lignes de code&amp;nbsp;:&lt;/p&gt;

&lt;pre&gt;
[php]
$view = new UserSet(&amp;quot;INNER JOIN contacts AS c2 ON (u.user_id = c2.contact)&amp;quot;, &amp;quot; c2.uid = $uid &amp;quot;);
$view-&amp;gt;addMod('minifiche', 'Mini-Fiches', true); 
$view-&amp;gt;addMod('trombi', 'Trombinoscope', false, array('with_admin' =&amp;gt; false, 'with_promo' =&amp;gt; true)); 
$view-&amp;gt;addMod('geoloc', 'Planisphère'); 
$view-&amp;gt;apply('carnet/contacts', $page, $action, $subaction); 
&lt;/pre&gt;


&lt;p&gt;On crée le UserSet en lui donnant les critères de sélection des utilisateurs à afficher, puis on ajoute les Views à utiliser, enfin on gère l'affichage (en fonction des arguments passés à l'affichage de la page). C'est le type d'abstraction qui font vraiment plaisir car finalement on se rapproche du slogan de Qt&amp;nbsp;: &lt;q&gt;Code less, Do more&lt;/q&gt;.&lt;/p&gt;


&lt;p&gt;Bien sûr, il faut développer tout le background, mais le temps de développement est négligeable comparé à celui qu'on aurait passé à dupliquer ce code, voire justement à ne pas le dupliquer en raison de la complexité de certains cas. Un autre exemple d'utilisation est sur l'annuaire des groupes sur Polytechnique.net&amp;nbsp;:&lt;/p&gt;

&lt;pre&gt;
[php]
$view = new UserSet(); 
$view-&amp;gt;addMod('trombi', 'Trombinoscope'); 
$view-&amp;gt;addMod('geoloc', 'Planisphère'); 
$view-&amp;gt;apply('annuaire', $page, $action, $subaction); 
&lt;/pre&gt;


&lt;p&gt;Dans ce cas, comme UserSet sait que s'il est appelé dans le cadre d'un groupe-X sur Polytechnique.net, il ne doit pas sélectionner d'utilisateurs hors de l'annuaire de ce groupe, il n'y a aucune restriction à lui indiquer&amp;nbsp;: tout l'annuaire du groupe est sélectionné. On ajoute les deux modules de représentation qu'on désire utiliser&amp;nbsp;: trombinoscope et Planispère, et applique à la page... en 4 lignes c'est fait.&lt;/p&gt;


&lt;p&gt;Je m'extasie devant ce travail parce que je suis content du résultat, mais il n'est pas pour autant parfait. Son problème actuel est dû au background basé sur SQL&amp;nbsp;: chaque élément (PlSet ou PlView) apporte des bribes d'une requête SQL permettant de finalement obtenir toutes les informations à afficher (PlView) pour les utilisateurs sélectionnés (PlSet), mais il peut arriver qu'une même donnée soit utilisée pour la sélection et pour l'affichage. Dans ce cas, la solution la plus simple est de dupliquer les jointures dans la requête, mais c'est une solution qui peut sérieusement alourdir et ralentir la requête.&lt;/p&gt;


&lt;p&gt;L'implémentation actuelle gère la duplication au cas par cas&amp;nbsp;: les PlView peuvent contenir tester s'il faut sélectionner un champ ou non en testant la classe du PlSet utilisé. Cette solution n'est pas particulièrement propre. La meilleure solution envisageable est d'utiliser une abstraction des champs SQL&amp;nbsp;: chaque élément ne donnerait plus une bribe de requête SQL mais des informations sur &quot;comment sélectionner la donnée&quot;... ensuite la génération de la requête consiste à comparer toutes ces informations et à les assembler. Plat/al possède déjà les outils nécessaires pour réaliser ce jeu d'assemblage... ce sera très probablement pour la prochaine release.&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.mymind.fr/post/2007/04/29/0914-en-ligne#comment-form</comments>
      <wfw:comment>http://blog.mymind.fr/post/2007/04/29/0914-en-ligne#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.mymind.fr/feed/atom/comments/23</wfw:commentRss>
      </item>
    
  <item>
    <title>Stats</title>
    <link>http://blog.mymind.fr/post/2007/04/21/Stats</link>
    <guid isPermaLink="false">urn:md5:8fac3526281ad76cf6ecb507a074b66e</guid>
    <pubDate>Sat, 21 Apr 2007 00:59:00 +0200</pubDate>
    <dc:creator>Florent Bruneau</dc:creator>
        <category>GeekTime</category>
        <category>awstats</category><category>Devel</category><category>root</category>    
    <description>    &lt;p&gt;Depuis le début, j'ai installé &lt;a href=&quot;http://awstats.sf.net&quot;&gt;awstats&lt;/a&gt; pour avoir des statistiques sur l'utilisation de mon serveur web.&lt;/p&gt;


&lt;p&gt;J'ai choisi awstats un peu par hasard&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;on avait utilisé &lt;a href=&quot;http://www.mrunix.net/webalizer/&quot;&gt;webalizer&lt;/a&gt; au &lt;a href=&quot;http://www.frankiz.net/binets/reseau&quot;&gt;BR&lt;/a&gt; et je n'étais pas spécialement convaincu par le résultat obtenu&amp;nbsp;: beaucoup de chiffres, graphiquement peu attirant et d'ergonomie d'utilisation assez mauvaise.&lt;/li&gt;
&lt;li&gt;à &lt;a href=&quot;https://www.polytechnique.org&quot;&gt;Polytechnique.org&lt;/a&gt; par contre, on utilise awstats, même si je n'ai pas fait le bilant complet des fonctionnalités, il a au moins l'avantage d'être lisible et agréable à l'oeil.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Donc &lt;a href=&quot;http://stat.mymind.fr/blog&quot;&gt;je l'ai installé&lt;/a&gt;, personnalisé... en particuliers j'ai ajouté des browsers (principalement des syndicateurs) et robots, amélioré les spécifications de certains OS, et j'avais également ajouté à l'outil de configuration le support de &lt;a href=&quot;http://www.mamp.info/en/home/&quot;&gt;MAMP&lt;/a&gt;. J'ai envoyé le patch au mainteneur du projet. Aujourd'hui je fais un &lt;code&gt;cvs up&lt;/code&gt; sur mon installation du projet et je vois&amp;nbsp;:&lt;/p&gt;

&lt;pre&gt;
P docs/awstats_faq.html
RCS file: /cvsroot/awstats/awstats/tools/awstats_configure.pl,v
retrieving revision 1.6
retrieving revision 1.7
Merging differences between 1.6 and 1.7 into awstats_configure.pl
M tools/awstats_configure.pl
M wwwroot/cgi-bin/awstats.model.conf
RCS file: /cvsroot/awstats/awstats/wwwroot/cgi-bin/lib/browsers.pm,v
retrieving revision 1.54
retrieving revision 1.55
Merging differences between 1.54 and 1.55 into browsers.pm
M wwwroot/cgi-bin/lib/browsers.pm
RCS file: /cvsroot/awstats/awstats/wwwroot/cgi-bin/lib/operating_systems.pm,v
retrieving revision 1.20
retrieving revision 1.21
Merging differences between 1.20 and 1.21 into operating_systems.pm
M wwwroot/cgi-bin/lib/operating_systems.pm
RCS file: /cvsroot/awstats/awstats/wwwroot/cgi-bin/lib/robots.pm,v
retrieving revision 1.44
retrieving revision 1.45
Merging differences between 1.44 and 1.45 into robots.pm
M wwwroot/cgi-bin/lib/robots.pm
&lt;/pre&gt;


&lt;p&gt;Bizarrement, tous les fichiers que j'ai modifié ont été modifié également sur la CVS... donc je suis allé faire un tour sur le &lt;a href=&quot;http://awstats.cvs.sourceforge.net/awstats/awstats/&quot;&gt;webvc du projet&lt;/a&gt;, et sur les fichiers correspondants, il y a le commentaire &lt;em&gt;Patch florent bruneau&lt;/em&gt;.&lt;/p&gt;


&lt;p&gt;Voilà, une bonne surprise&amp;nbsp;! Je suis juste un peu déçu de l'avoir vu uniquement sur un update de cvs.&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.mymind.fr/post/2007/04/21/Stats#comment-form</comments>
      <wfw:comment>http://blog.mymind.fr/post/2007/04/21/Stats#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.mymind.fr/feed/atom/comments/22</wfw:commentRss>
      </item>
    
  <item>
    <title>Un aperçu de la version 0.9.14 de plat/al</title>
    <link>http://blog.mymind.fr/post/2007/03/30/Un-apercu-de-la-version-0914-de-plat/al</link>
    <guid isPermaLink="false">urn:md5:ec498a28aa5a6eddefe735a40a71e0e8</guid>
    <pubDate>Fri, 30 Mar 2007 11:39:00 +0200</pubDate>
    <dc:creator>Florent Bruneau</dc:creator>
        <category>Polytechnique.org</category>
        <category>Devel</category><category>platal</category>    
    <description>&lt;p&gt;Le site de &lt;a href=&quot;https://www.polytechnique.org&quot;&gt;Polytechnique.org&lt;/a&gt; est prévu pour être mis à jour régulièrement, de l'ordre d'une fois tous les deux mois. Ainsi, les mises à jours sont suffisamment substantielles pour créer un effet d'annonce autour des améliorations apportées au site, sans pour autant laisser traîner les correctifs de bugs trop longtemps dans la branche de développement sans en faire profiter les utilisateurs.&lt;/p&gt;


&lt;p&gt;La version 0.9.13 est sortie fin janvier, un peu plus d'un mois après la 0.9.12. La 0.9.14 sortira probablement fin avril (en tout cas, ce sera après le passage de &lt;a href=&quot;http://www.debian.org/releases/etch/&quot;&gt;etch&lt;/a&gt; en stable chez debian). Néanmoins, vue la masse de changement de cette nouvelle version, nous avons décidé de lancer les tests plus tôt qu'à l'accoutumée. Voici donc un aperçu des nouveautés (seulement un aperçu car le développement de cette version n'est pas freezé).&lt;/p&gt;


&lt;p&gt;Comme à l'accoutumée, la liste exhaustive des changements se trouve dans le &lt;a href=&quot;http://dev.m4x.org/changelog&quot;&gt;ChangeLog&lt;/a&gt;.&lt;/p&gt;    &lt;h2&gt;Passage en UTF8&lt;/h2&gt;


&lt;p&gt;C'est le changement le moins visible... mais le plus douloureux. En fait pour l'utilisateur a priori, rien ne change... mais en background &lt;strong&gt;toutes&lt;/strong&gt; les pages, sans exception, sont affectées et donc potentiellement buggées. La plupart du temps un bug d'UTF8 (dans le sens latin1 interprété comme de l'UTF8) entraîne l'affichage d'une page vide ou blanche, ce qui est beaucoup plus douloureux que dans l'autre sens (UTF8 interprété comme du latin1).&lt;/p&gt;


&lt;p&gt;Le passage en UTF8 s'accompagne d'un passage de MySQL 4.0 à MySQL 5... a priori la plupart des incompatibilités SQL sont corrigées mais on ne sait jamais. Pour l'instant nous n'utilisons pas vraiment les nouveautés de MySQL 5 (en fait un MySQL 4.1 aurait suffi pour l'usage qu'on en fait). Mais ce changement permet de prévoir à l'avenir un changement de la structure de la base SQL que nous utilisons, ce qui sera sans doute nécessaire lors de la &lt;a href=&quot;http://trackers.polytechnique.org/task/547&quot;&gt;fusion des annuaires&lt;/a&gt;.&lt;/p&gt;


&lt;h2&gt;Syntaxe Wiki généralisée&lt;/h2&gt;


&lt;p&gt;Autre nouveauté majeure, mais cette fois dont l'utilisateur bénéficiera directement&amp;nbsp;: une syntaxe wiki généralisée est désormais mise en place sur la grande majorité des textes que l'utilisateur peut entrer sur le site. La syntaxe utilisée est celle de &lt;a href=&quot;http://www.pmwiki.org/&quot;&gt;PmWiki&lt;/a&gt;, le moteur wiki que nous utilisons déjà pour les pages de documentation du site. Malheureusement la structure de PmWiki interdisant son utilisation comme une bibliothèque (en gros il ne fournit pas de fonction wikiToHtml, comme le fait par exemple &lt;a href=&quot;http://www.dotclear.net&quot;&gt;Dotclear&lt;/a&gt;), il a fallu réimplémenter un nouveau moteur wiki léger.&lt;/p&gt;


&lt;p&gt;Cette &lt;a href=&quot;http://dev.m4x.org/wiki_help&quot;&gt;syntaxe wiki&lt;/a&gt; permet la plupart des formatages attendus&amp;nbsp;: gras, italique, couleur, soulignement, listes, titres et tailles, liens hypertextes. On conserve également un url-catcher qui permet à l'utilisateur qui n'a pas envie de prendre le temps de formater son annonce d'avoir tout de même les URL transformées en lien.&lt;/p&gt;


&lt;p&gt;La syntaxe wiki est utilisable&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;pour le formulaire d'envoi de mail&lt;/li&gt;
&lt;li&gt;pour les champs &quot;freetext&quot; de la fiche (CV et Commentaires)&lt;/li&gt;
&lt;li&gt;pour l'édition d'annonces (pour la page d'accueil et pour la lettre mensuelle)&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Amélioration des annonces&lt;/h2&gt;


&lt;p&gt;Comme indiqué dans le paragraphe précédent, les annonces bénéficieront d'une syntaxe wiki qui permet de formater l'annonce (ce qui n'était jusqu'à présent faisable que par les administrateurs du site, en éditant directement le code HTML de l'annonce). Mais ce n'est pas la seule amélioration. L'amélioration du système d'annonce de Polytechnique.org était un des points les plus importants que j'avais annoncés dans un &lt;a href=&quot;http://blog.mymind.fr/mind/post/2007/03/01/Polytechniqueorg-en-retard&quot;&gt;précédent billet&lt;/a&gt;.&lt;/p&gt;


&lt;p&gt;&lt;a href=&quot;http://blog.mymind.fr/mind/public/screenshots/annonce-0.9.14.png&quot;&gt;&lt;img src=&quot;http://blog.mymind.fr/mind/public/screenshots/.annonce-0.9.14_m.jpg&quot; alt=&quot;Système d&amp;#039;annonces de plat/al 0.9.14&quot; style=&quot;display:block; margin:0 auto;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h3&gt;Classement des annonces&lt;/h3&gt;


&lt;p&gt;Au lieu d'avoir toutes les annonces dans un ordre incompréhensible qui ne permet pas de distinguer les nouvelles des anciennes, les annonces seront désormais classées selon leur date d'arrivée, leur date de péremption et leur importance. Ce classement est &lt;em&gt;'très&lt;/em&gt;' fortement inspiré du classement utilisé sur &lt;a href=&quot;http://www.frankiz.net&quot;&gt;Frankiz (le portail des élèves de l'X)&lt;/a&gt;. L'ordre de traitement (en first-match) est le suivant&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;si une annonce est marquée comme importante, elle va dans la catégorie du même nom.&lt;/li&gt;
&lt;li&gt;si une annonce a été validée (et non postée) il y a moins de 48 heures, elle est dans &quot;Nouvelles annonces&quot;&lt;/li&gt;
&lt;li&gt;si une annonce périme dans moins de 48 heures, elle est dans &quot;Bientôt fini&quot;&lt;/li&gt;
&lt;li&gt;toutes les autres annonces sont dans &quot;Mais encore...&quot;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Une image par annonce...&lt;/h3&gt;


&lt;p&gt;Les annonces autorisent désormais l'ajout d'une image qui illustre l'annonce ou le groupe qui a posté l'annonce. Pour le design, nous sommes cette fois plus proche de ce qui est fait sur le &lt;a href=&quot;http://www.polytechnicien.com&quot;&gt;site de l'AX&lt;/a&gt;&amp;nbsp;: l'image est placée sur le côté de l'annonce, ce qui permet de limiter l'espace inutilisé. Moins il y a de vide, plus on a de chance que les utilisateurs aillent lire le contenu sans trop &quot;scroller&quot;, ce qui est à mon avis mieux pour la lisibilité des annonces.&lt;/p&gt;


&lt;h3&gt;Discussion&lt;/h3&gt;


&lt;p&gt;Enfin la dernière grande nouveauté est l'ajout de la notion de discussion. Lorsqu'une annonce est validée, elle est automatiquement postée sur un newsgroup (grâce à &lt;a href=&quot;http://opensource.polytechnique.org/banana&quot;&gt;banana&lt;/a&gt; et l'annonce elle-même contient un lien vers ce post. Je suis curieux de voir à quel point cela va fonctionner (j'ai tendance à penser que ce sera encore une fonctionnalité inutilisée... en tout cas pendant les premiers mois) mais en tout cas c'est avant tout un début vers une meilleure interactivité entre les utilisateurs.&lt;/p&gt;


&lt;h2&gt;Recherche par proximité sonore généralisée&lt;/h2&gt;


&lt;p&gt;Une autre nouveauté dont j'ai déjà parlé dans &lt;a href=&quot;http://blog.mymind.fr/mind/post/2007/03/15/Soundex-Francais&quot;&gt;un billet précédent&lt;/a&gt;. Alors qu'auparant la recherche par proximité sonore était limitée à la recherche avancée et n'était pas toujours correcte, la nouvelle étant la possibilité à la recherche rapide (selon le choix de l'utilisateur évidemment) et devrait être (je l'espère) plus efficace qu'auparavant grâce au nouvel algorithme de soundex conçu pour mieux s'adapter à la langue française.&lt;/p&gt;


&lt;p&gt;Le seul moyen de se faire une idée est de &lt;a href=&quot;http://dev.m4x.org/search&quot;&gt;tester sur le site&lt;/a&gt; ou de &lt;a href=&quot;http://blog.mymind.fr/mind/post/2007/03/15/Soundex-Francais#test&quot;&gt;tester l'algorithme&lt;/a&gt;.&lt;/p&gt;


&lt;h2&gt;Les forums et les Mailing-Lists en RSS&lt;/h2&gt;


&lt;p&gt;La prochaine version de plat/al intégrera Banana 1.6 dont l'innovation majeure est l'ajout de flux RSS pour les forums. Je ne m'étendrais pas sur le sujet étant donné qu'il y a déjà un &lt;a href=&quot;http://blog.mymind.fr/mind/post/2007/02/25/Un-client-RSS-pour-lire-les-Forums-NNTP-et-les-Mailing-Lists&quot;&gt;billet à ce sujet&lt;/a&gt;. Mais les forums ne sont pas les seuls à se doter d'un flux RSS avec cette nouvelle version, c'est également le cas des pages de documentation. Ainsi il sera possible de suivre les modifications de la documentation (ce qui sera principalement utile pour les administrateurs du site).&lt;/p&gt;


&lt;h2&gt;Mais aussi... en vrac&lt;/h2&gt;


&lt;p&gt;Les versions précédentes du site offraient la possibilité d'ajouter l'annuaire de Polytechnique.org aux moteurs de recherche de Firefox. Désormais ce sera aussi possible de le faire dans Internet Explorer 7 et dans tous les navigateurs qui supportent le format &lt;a href=&quot;http://www.opensearch.org&quot;&gt;OpenSearch&lt;/a&gt;.&lt;/p&gt;


&lt;p&gt;L'ajout d'un nouveau module pour faire des sondages. Ce module est encore en développement et n'est pas actuellement accessible sur le site de développement, mais il devrait être intégré à la prochaine version du site. Les sondages étaient la seule fonctionnalité du site perdue en octobre 2004 lorsque la première version de plat/al avait replacé l'ancienne version du site. C'est un outil très attendu que nous sommes heureux de retrouver grâce au travail de &lt;a href=&quot;https://www.polytechnique.org/profile/fabien.laborde.2004&quot;&gt;pika&lt;/a&gt;.&lt;/p&gt;


&lt;p&gt;Et il y a encore d'autres nouveautés, ainsi qu'un grand nombre de corrections de bugs.&lt;/p&gt;


&lt;h2&gt;Venez tester&amp;nbsp;!&lt;/h2&gt;


&lt;p&gt;N'hésitez donc pas à venir nous aider à tester toutes ces nouvelles fonctionnalités. Pour ceci il suffit d'avoir un compte sur Polytechnique.org (donc d'être un X) et d'aller sur&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://dev.m4x.org&quot;&gt;Le site de test de Polytechnique.org&lt;/a&gt; pour tester le site principal&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://dev.polytechnique.net&quot;&gt;le site de test de Polytechnique.net&lt;/a&gt; pour tester le site des groupes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;La &lt;a href=&quot;http://www.polytechnique.net/Polytechnique.org/lists/members/testeurs&quot;&gt;liste de diffusion des testeurs&lt;/a&gt; est également ouverte à toutes les bonnes volontés et permet de discuter simplement les bugs et de l'avancement des corrections.&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.mymind.fr/post/2007/03/30/Un-apercu-de-la-version-0914-de-plat/al#comment-form</comments>
      <wfw:comment>http://blog.mymind.fr/post/2007/03/30/Un-apercu-de-la-version-0914-de-plat/al#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.mymind.fr/feed/atom/comments/18</wfw:commentRss>
      </item>
    
  <item>
    <title>Deux approches...</title>
    <link>http://blog.mymind.fr/post/2007/03/28/Deux-approches</link>
    <guid isPermaLink="false">urn:md5:659d3158b09c841e3e595d336e25a842</guid>
    <pubDate>Wed, 28 Mar 2007 00:52:00 +0200</pubDate>
    <dc:creator>Florent Bruneau</dc:creator>
        <category>GeekTime</category>
        <category>Devel</category><category>PHP</category><category>Qt</category>    
    <description>&lt;p&gt;Les deux APIs avec lesquelles j'ai eu le plus la chance de travailler sont celle de &lt;a href=&quot;http://doc.trolltech.com/&quot;&gt;Qt&lt;/a&gt; et celle de &lt;a href=&quot;http://www.php.net&quot;&gt;PHP&lt;/a&gt;... il n'y a pas à dire, entre ces deux bibliothèques, c'est comme le jour et la nuit.&lt;/p&gt;    &lt;p&gt;L'API de Qt est intuitive et est conçue pour l'être. Si je veux avoir l'âge du capitaine, je ferais toujours &lt;code&gt;capitaine-&amp;gt;age()&lt;/code&gt;, et si je veux définir son âge, ce sera &lt;code&gt;capitaine-&amp;gt;setAge(42)&lt;/code&gt;. Cette API est tellement prévisible qu'au bout de quelques jours d'utilisation, on n'utilise la documentation que pour chercher de nouvelles fonctionnalités, mais très rarement pour chercher des fonctions courantes. En plus, ce qui est remarquable, c'est qu'au fur et à mesure des versions de Qt, l'accent est mis sur la simplification de l'API... Qt 4 est bien plus intuitive que Qt 3 qui est pourtant déjà très facile à utiliser.&lt;/p&gt;


&lt;p&gt;La qualité de la documentation de Qt y est également pour quelque chose&amp;nbsp;: toutes les méthodes sont documentées, avec la plupart du temps un exemple. Le tout étant très facilement accessible grâce à l'assistant, un petit programme qui permet de consulter la documentation en intégrant des outils pour naviguer simplement entre les pages.&lt;/p&gt;


&lt;p&gt;Par contre, je ne sais pas pourquoi, mais en PHP, l'API est incohérente... l'exemple le plus simple est sans doute celui du remplacement et de la recherche dans une variable. Si, par exemple, je veux rechercher un élément&amp;nbsp;:&lt;/p&gt;
&lt;pre&gt;
[php]
//Dans une chaîne de caractères :
strpos($string, $findme);
//Dans un tableau, c'est l'inverse :
in_array($findme, $array);
array_search($findme, $array);
&lt;/pre&gt;


&lt;p&gt;Si je veux faire un remplacement dans une chaîne de caractères&amp;nbsp;:&lt;/p&gt;
&lt;pre&gt;
[php]
strtr($string, $search, $replace);
str_replace($search, $replace, $string);
preg_replace($search, $replace, $string);
&lt;/pre&gt;


&lt;p&gt;Chic&amp;nbsp;! Grâce à ça, même si je connais le nom de la fonction à utiliser, je suis quasiment forcé à chaque fois d'aller regarder dans la documentation de PHP (ce que j'ai fait pour écrire ce paragraphe, sinon j'aurais &lt;em&gt;'forcément&lt;/em&gt;' inversé les arguments)... heureusement que celle-ci est bien faite et permet de trouver rapidement les fonctions dont on connaît le nom.&lt;/p&gt;


&lt;p&gt;Quand est-ce que PHP se décidera à revoir son API pour qu'elle soit aussi intuitive que celle de Qt&amp;nbsp;? Malheureusement, sans doute jamais&amp;nbsp;: il faut garder (autant que possible) la compatibilité avec les versions précédentes de PHP. Dommage, parce qu'à mon avis, si PHP continue à étoffer son API sans la rendre cohérente, sa popularité va diminuer progressivement dans les années qui viennent.&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.mymind.fr/post/2007/03/28/Deux-approches#comment-form</comments>
      <wfw:comment>http://blog.mymind.fr/post/2007/03/28/Deux-approches#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.mymind.fr/feed/atom/comments/17</wfw:commentRss>
      </item>
    
  <item>
    <title>Joie ! (bis)</title>
    <link>http://blog.mymind.fr/post/2007/03/21/Joie-bis</link>
    <guid isPermaLink="false">urn:md5:593801c609af4bc8d932a7eebc58800d</guid>
    <pubDate>Wed, 21 Mar 2007 20:19:00 +0100</pubDate>
    <dc:creator>Florent Bruneau</dc:creator>
        <category>GeekTime</category>
        <category>Devel</category><category>khtml2png</category><category>khtmld</category>    
    <description>    &lt;p&gt;Voilà, la nouvelle version de &lt;code&gt;&lt;a href=&quot;http://blog.mymind.fr/mind/post/2007/03/14/Demon-pour-khtml2png&quot;&gt;khtmld&lt;/a&gt;&lt;/code&gt; vient d'être releasée...&lt;/p&gt;


&lt;p&gt;Vous pouvez consulter la &lt;a href=&quot;http://wiki.goatpron.de/project/khtmld&quot;&gt;page principale du projet&lt;/a&gt;.&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.mymind.fr/post/2007/03/21/Joie-bis#comment-form</comments>
      <wfw:comment>http://blog.mymind.fr/post/2007/03/21/Joie-bis#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.mymind.fr/feed/atom/comments/16</wfw:commentRss>
      </item>
    
  <item>
    <title>Soundex Français</title>
    <link>http://blog.mymind.fr/post/2007/03/15/Soundex-Francais</link>
    <guid isPermaLink="false">urn:md5:0b44d76db88f4470bb76e4bc56c891fe</guid>
    <pubDate>Thu, 15 Mar 2007 18:06:00 +0100</pubDate>
    <dc:creator>Florent Bruneau</dc:creator>
        <category>Polytechnique.org</category>
        <category>Devel</category><category>PHP</category>    
    <description>&lt;p&gt;Pour faire une recherche phonétique, on utilise souvent ce qu'on appelle une transcription &lt;strong&gt;soundex&lt;/strong&gt; des mots. C'est une réécriture du mot, dans un alphabet restreint et sur un nombre de caractères restreint également. La plupart des algorithmes qu'on peut trouver sur internet sont conçus uniquement à la langue anglaise. Pour utiliser la recherche phonétique en français, il faut donc adapter cet algorithme.&lt;/p&gt;


&lt;p&gt;L'implémentation française la plus courante utilise l'&lt;a href=&quot;http://sqlpro.developpez.com/cours/soundex/&quot;&gt;algorithme décrit par Frédéric Brouard&lt;/a&gt;. Malheureusement cet algorithme ne me satisfait pas vraiment, car il n'est finalement pas très adapté à langue française.&lt;/p&gt;    &lt;p&gt;En effet cet algorithme a pas mal de défauts&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;il est très aléatoire dans le cas de dédoublement de consonnes. Par exemple, il ne permet de trouver que &lt;em&gt;bananne&lt;/em&gt; (soundex &lt;code&gt;BNN&lt;/code&gt;) est une approximation de &lt;em&gt;banane&lt;/em&gt; (soundex &lt;code&gt;BN&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;il est très peu sélectif sur les voyelles. Par exemple &lt;em&gt;poulpe&lt;/em&gt; et &lt;em&gt;palpa&lt;/em&gt; ont le même soundex (&lt;code&gt;PLP&lt;/code&gt;) alors que pour moi, poulpe et palpa sont deux mots éloignés, malgré leur consonnes communes. Par contre, il ne reconnaîtra pas Aymeric (soundex &lt;code&gt;AYMR&lt;/code&gt;) comme étant un homophone de Emeric (soundex &lt;code&gt;EMRC&lt;/code&gt;)...&lt;/li&gt;
&lt;li&gt;il n'est pas vraiment capable de distinguer les conjugaisons. Par exemple &lt;em&gt;palper&lt;/em&gt; (soundex &lt;code&gt;PLPR&lt;/code&gt;) et &lt;em&gt;palpé&lt;/em&gt; (soundex &lt;code&gt;PLP&lt;/code&gt;) sont éloignés l'un de l'autre.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;J'ai donc réalisé une nouvelle implémentation de &lt;code&gt;soundex&lt;/code&gt; qui est plus adaptée (à mon sens) à la langue française. Je n'ai évidemment pas pour ambition de réaliser une solution parfaite (ce qui est impossible à faire à partir d'un système automatisé sans dictionnaire).&lt;/p&gt;


&lt;h2&gt;Algorithme&lt;/h2&gt;


&lt;p&gt;Mon algorithme, comme je l'ai déjà dit, est une adaptation de celui de &lt;a href=&quot;http://sqlpro.developpez.com/cours/soundex/&quot;&gt;Frédéric Brouard&lt;/a&gt;. Il se compose de 2 étapes principales&amp;nbsp;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;le préformatage, qui consiste à transformer le chaîne de caractère brute, en une chaîne analysable.&lt;/li&gt;
&lt;li&gt;l'analyse de la chaîne, et la recherche de entités phoniques élémentaires qui la composent&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;Préformatage&lt;/h3&gt;


&lt;p&gt;Le préformatage est extrêmement simple&amp;nbsp;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;On converti la chaîne en majuscule&lt;/li&gt;
&lt;li&gt;On converti chaque caractère accentué vers son caractère non-accentué correspondant&lt;/li&gt;
&lt;li&gt;On filtre pour ne conserver que les lettres (de A à Z)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Ainsi après ce premier filtrage, &lt;em&gt;Mac-Cartney&lt;/em&gt; devient &lt;em&gt;MACCARTNEY&lt;/em&gt; et &lt;em&gt;palpé&lt;/em&gt; sera &lt;em&gt;PALPE&lt;/em&gt;&lt;/p&gt;


&lt;h3&gt;Traitement des données&lt;/h3&gt;


&lt;p&gt;Le traitement des données consiste à reconnaître les sonorités. Pour ceci on utilise la table de conversion suivante qui associe à chaque sonorité complexe un caractère&amp;nbsp;:&lt;/p&gt;

&lt;table&gt;
  &lt;tr&gt;&lt;th&gt;Combinaison&lt;/th&gt;&lt;th&gt;Caractère&lt;/th&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;G (prononcé GUE), C (prononcé Q), CK, K, QU, Q&lt;/td&gt;&lt;td&gt;K&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;CH, SH, SCH&lt;/td&gt;&lt;td&gt;9&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;ST&lt;/td&gt;&lt;td&gt;T&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;PF (en début de mot), PH&lt;/td&gt;&lt;td&gt;F&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;Z (en fin de mot)&lt;/td&gt;&lt;td&gt;ZE&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;Z, ZZ, C (prononcé SE)&lt;/td&gt;&lt;td&gt;S&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;G (prononcé JE)&lt;/td&gt;&lt;td&gt;J&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;EAU, AU&lt;/td&gt;&lt;td&gt;O&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;IN, UN, AIN, EIN (proncés UN)&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;AON, AOM, EN, AN (prononcés EN)&lt;/td&gt;&lt;td&gt;A&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;EY, EI, AY, AI, OE, OEU, EU, ER&lt;/td&gt;&lt;td&gt;E&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;OI&lt;/td&gt;&lt;td&gt;O&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;ILLE, I&lt;/td&gt;&lt;td&gt;Y&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;OU, OW&lt;/td&gt;&lt;td&gt;U&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;ON, OM&lt;/td&gt;&lt;td&gt;O&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;KN (en début de mot)&lt;/td&gt;&lt;td&gt;N&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;



&lt;p&gt;Une fois qu'on a cette table de correspondances (elle n'est peut-être pas exhaustive... je n'hésiterais pas à l'améliorer), on applique toutes les modifications, on supprime les lettres qui sont présentes en doublon et finalement on supprime les H restants. Il faut également supprimer les caractères muets en fin de mot. En français, ce seront les X, T, D, S (et le L qui les précède si il existe) ou les E.&lt;/p&gt;


&lt;p&gt;Ensuite, il faut faire un nettoyage sur la chaîne de caractère. Ce nettoyage consiste à rechercher les phonèmes importants et à supprimer les caractères muets ou peu audibles&amp;nbsp;: on veut identifier ce qui fait la particularité d'une syllabe. Frédéric Brouard considère que toutes les voyelles (exceptés les Y précédés d'une voyelle) placées autre part qu'en début de mot sont insignifiantes... ça me paraît le gros point faible de sa méthode. Personnellement j'ai essayé d'identifier une liste de sonorité dominantes. Voici celles que j'ai actuellement&amp;nbsp;:&lt;/p&gt;

&lt;table&gt;
  &lt;tr&gt;&lt;th&gt;Sonorité&lt;/th&gt;&lt;th&gt;Informations&lt;/th&gt;&lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;K, T, P&lt;/td&gt;
    &lt;td&gt;Ce sont les consonnes qui sont très marquées, qui rythment le mot&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;A, U, O, 1&lt;/td&gt;
    &lt;td&gt;Ce sont les son qu'on entend le mieux, contrairement aux I ou aux E qui mettent plus en avant les consonnes. Le A est à mon avis particulier, car il est faible mais suffisamment marquant pour effacer des consonnes comme le R&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;Y&lt;/td&gt;
    &lt;td&gt;Y n'est marquant que lorsqu'il a un rôle de consonne : quand il permet de lier deux parties du mot, comme dans ''voyelle'', où il lie le ''vo'' et le ''elle''. Il est donc important lorsqu'il est encadré par une ou des voyelles. Dans les autres cas, c'est une voyelle faible&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;L&lt;/td&gt;
    &lt;td&gt;Contrairement aux K, T et P, le L permet d'adoucir le mot, en particulier lorsqu'il sert de liaison entre une consonne et une voyelle. Il est donc important de le conserver&lt;/tr&gt;
  &lt;/tr&gt;
&lt;/table&gt;



&lt;p&gt;Ces choix sont relativement arbitraires. Le comportement de l'algorithme est alors simple&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Si une voyelle est liée à une consonne de liaison (qui fait le lien entre la voyelle et une autre consonne, c'est souvent le cas du L ou du R, on exclut de ce cas les consommes fortes)&lt;/li&gt;
&lt;li&gt;Si en plus il s'agit d'une voyelle forte
&lt;ul&gt;
&lt;li&gt;alors, on supprime la consonne de liaison et on garde la voyelle&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ensuite, on supprime les voyelles faibles (sauf si elles commencent le mot). Pour cette suppression, on considère le A comme une voyelle faible.&lt;/p&gt;


&lt;p&gt;Pour terminer on coupe la chaîne obtenue à 4 caractères (mais il est parfaitement envisageable de prendre un soundex sur plus (ou moins) de caractères. Simplement, dans la plupart des cas, 4 caractères suffisent amplement à avoir un mot significatif.&lt;/p&gt;


&lt;h2&gt;Implémentation&lt;/h2&gt;


&lt;p&gt;Mon implémentation en PHP est téléchargeable &lt;a href=&quot;http://blog.mymind.fr/soundex_fr.php?action=download&quot;&gt;ici&lt;/a&gt;. Elle est testable &lt;a href=&quot;http://blog.mymind.fr/mind/post/2007/03/15/Soundex-Francais#test&quot;&gt;plus bas dans cette même page&lt;/a&gt;. Voici le code de la fonction soundex_fr (je ne garantis pas que le code disponible sur cette page reste constamment à jour, contrairement au lien de téléchargement) :&lt;sup&gt;[&lt;a href=&quot;http://blog.mymind.fr/post/2007/03/15/Soundex-Francais#pnote-14-1&quot; id=&quot;rev-pnote-14-1&quot;&gt;1&lt;/a&gt;]&lt;/sup&gt;&lt;/p&gt;

&lt;pre&gt;
[php]
function soundex_fr($sIn) 
{ 
    static $convVIn, $convVOut, $convGuIn, $convGuOut, $accents; 
    if (!isset($convGuIn)) { 
        $accents = array('É' =&amp;gt; 'E', 'È' =&amp;gt; 'E', 'Ë' =&amp;gt; 'E', 'Ê' =&amp;gt; 'E', 
                    'Á' =&amp;gt; 'A', 'À' =&amp;gt; 'A', 'Ä' =&amp;gt; 'A', 'Â' =&amp;gt; 'A', 'Å' =&amp;gt; 'A', 'Ã' =&amp;gt; 'A', 
                    'Ï' =&amp;gt; 'I', 'Î' =&amp;gt; 'I', 'Ì' =&amp;gt; 'I', 'Í' =&amp;gt; 'I', 
                    'Ô' =&amp;gt; 'O', 'Ö' =&amp;gt; 'O', 'Ò' =&amp;gt; 'O', 'Ó' =&amp;gt; 'O', 'Õ' =&amp;gt; 'O', 'Ø' =&amp;gt; 'O', 
                    'Ú' =&amp;gt; 'U', 'Ù' =&amp;gt; 'U', 'Û' =&amp;gt; 'U', 'Ü' =&amp;gt; 'U', 
                    'Ç' =&amp;gt; 'C', 'Ñ' =&amp;gt; 'N', 'Ç' =&amp;gt; 'S', '¿' =&amp;gt; 'E', 
                    'é' =&amp;gt; 'e', 'è' =&amp;gt; 'e', 'ë' =&amp;gt; 'e', 'ê' =&amp;gt; 'e', 
                    'á' =&amp;gt; 'a', 'à' =&amp;gt; 'a', 'ä' =&amp;gt; 'a', 'â' =&amp;gt; 'a', 'å' =&amp;gt; 'a', 'ã' =&amp;gt; 'a', 
                    'ï' =&amp;gt; 'i', 'î' =&amp;gt; 'i', 'ì' =&amp;gt; 'i', 'í' =&amp;gt; 'i', 
                    'ô' =&amp;gt; 'o', 'ö' =&amp;gt; 'o', 'ò' =&amp;gt; 'o', 'ó' =&amp;gt; 'o', 'õ' =&amp;gt; 'o', 'ø' =&amp;gt; 'o', 
                    'ú' =&amp;gt; 'u', 'ù' =&amp;gt; 'u', 'û' =&amp;gt; 'u', 'ü' =&amp;gt; 'u', 
                    'ç' =&amp;gt; 'c', 'ñ' =&amp;gt; 'n'); 
        $convGuIn  = array( 'GUI', 'GUE', 'GA', 'GO', 'GU', 'SCI', 'SCE', 'SC', 'CA', 'CO', 
                            'CU', 'QU', 'Q', 'CC', 'CK', 'G', 'ST', 'PH'); 
        $convGuOut = array( 'KI', 'KE', 'KA', 'KO', 'K', 'SI', 'SE', 'SK', 'KA', 'KO', 
                            'KU', 'K', 'K', 'K', 'K', 'J', 'T', 'F'); 
        $convVIn   = array( '/E?(AU)/', '/([EA])?[UI]([NM])([^EAIOUY]|$)/', '/[AE]O?[NM]([^AEIOUY]|$)/', 
                            '/[EA][IY]([NM]?[^NM]|$)/', '/(^|[^OEUIA])(OEU|OE|EU)([^OEUIA]|$)/', '/OI/', 
                            '/(ILLE?|I)/', '/O(U|W)/', '/O[NM]($|[^EAOUIY])/', '/(SC|S|C)H/', 
                            '/([^AEIOUY1])[^AEIOUYLKTPNR]([UAO])([^AEIOUY])/', '/([^AEIOUY]|^)([AUO])[^AEIOUYLKTP]([^AEIOUY1])/', '/^KN/', 
                            '/^PF/', '/C([^AEIOUY]|$)/',  '/E(Z|R)$/', 
                            '/C/', '/Z$/', '/(?&amp;lt;!^)Z+/', '/H/', '/W/'); 
        $convVOut  = array( 'O', '1\\3', 'A\\1', 
                            'E\\1', '\\1E\\3', 'O', 
                            'Y', 'U', 'O\\1', '9',- 
                            '\\1\\2\\3', '\\1\\2\\3', 'N', 
                            'F', 'K\\1', 'E', 
                            'S', 'SE', 'S', '', 'V'); 
    } 
    // Si il n'y a pas de mot, on sort immédiatement
    if ( $sIn === '' ) return '    '; 
    // On supprime les accents- 
    $sIn = strtr( $sIn, $accents); 
    // On met tout en minuscule- 
    $sIn = strtoupper( $sIn ); 
    // On supprime tout ce qui n'est pas une lettre
    $sIn = preg_replace( '`[^A-Z]`', '', $sIn ); 
    // Si la chaîne ne fait qu'un seul caractère, on sort avec.
    if ( strlen( $sIn ) === 1 ) return $sIn . '   '; 
    // on remplace les consonnances primaires
    $sIn = str_replace( $convGuIn, $convGuOut, $sIn ); 
    // on supprime les lettres répétitives 
    $sIn = preg_replace( '`(.)\\1`', '$1', $sIn ); 
    // on réinterprète les voyelles 
    $sIn = preg_replace( $convVIn, $convVOut, $sIn); 
 
    // on supprime les terminaisons T, D, S, X (et le L qui précède si existe)
    $sIn = preg_replace( '`L?[TDX]?S?$`', '', $sIn ); 
    // on supprime les E, A et Y qui ne sont pas en première position 
    $sIn = preg_replace( '`(?!^)Y([^AEOU]|$)`', '\\1', $sIn); 
    $sIn = preg_replace( '`(?!^)[EA]`', '', $sIn); 
    return substr( $sIn . '    ', 0, 4); 
} 
&lt;/pre&gt;


&lt;h2&gt;Tests&lt;/h2&gt;


&lt;p&gt;Avec cette implémentation, on a par exemple&amp;nbsp;:&lt;/p&gt;

&lt;table&gt;
  &lt;tr&gt;&lt;th&gt;Mot&lt;/th&gt;&lt;th&gt;Soundex&lt;/th&gt;&lt;th&gt;Mot&lt;/th&gt;&lt;th&gt;Soundex&lt;/th&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;Aymeric&lt;/td&gt;&lt;td&gt;EMRK&lt;/td&gt;&lt;td&gt;Emeric&lt;/td&gt;&lt;td&gt;EMRK&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;Banane&lt;/td&gt;&lt;td&gt;BNN&lt;/td&gt;&lt;td&gt;Bananne&lt;/td&gt;&lt;td&gt;BNN&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;Palper&lt;/td&gt;&lt;td&gt;PLP&lt;/td&gt;&lt;td&gt;Palpé&lt;/td&gt;&lt;td&gt;PLP&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;Palpa&lt;/td&gt;&lt;td&gt;PLP&lt;/td&gt;&lt;td&gt;Poulpe&lt;/td&gt;&lt;td&gt;PULP&lt;/td&gt;&lt;/tr&gt;
  &lt;tr&gt;&lt;td&gt;Mario&lt;/td&gt;&lt;td&gt;MRYO&lt;/td&gt;&lt;td&gt;Marion&lt;/td&gt;&lt;td&gt;MRYO&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;



&lt;p&gt;On a par contre des résultats moyens lorsque des H séparent des voyelles faibles&amp;nbsp;: par exemple &lt;em&gt;Mouahaha&lt;/em&gt; donne MU (contre M avec la version précédente).&lt;/p&gt;


&lt;p&gt;&lt;a name=&quot;test&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;http://blog.mymind.fr/ajax.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
function get_soundex()
{
    Ajax.update_html(&quot;sdx_result&quot;, &quot;/soundex_fr.php?text=&quot; + encodeURIComponent(document.getElementById(&quot;sdx_form&quot;).value));
    return false;
}
&lt;/script&gt;
&lt;div&gt;
&lt;form action=&quot;http://blog.mymind.fr/post/2007/03/15/&quot; method=&quot;get&quot; onsubmit=&quot;return false;&quot;&gt;
   &lt;p&gt;
      &lt;strong&gt;Entrer un texte à convertir : &lt;/strong&gt;
      &lt;input type=&quot;text&quot; id=&quot;sdx_form&quot; name=&quot;sdx_form&quot; value=&quot;&quot; /&gt;
      &lt;input type=&quot;submit&quot; name=&quot;submit&quot; value=&quot;Obtenir le Soundex&quot;  onclick=&quot;get_soundex(); return false;&quot;/&gt;&lt;br /&gt;
      &lt;strong&gt;Résultat : &lt;span id=&quot;sdx_result&quot; style=&quot;color: red&quot;&gt; &lt;/span&gt;&lt;/strong&gt;
   &lt;/p&gt;
&lt;/form&gt;
&lt;/div&gt;



&lt;p&gt;&lt;em&gt;N'hésitez pas à faire des tests et à me faire part des résultats qui semblent anormaux.&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;Conclusion&lt;/h2&gt;


&lt;p&gt;Cette version est loin d'être parfaite, mais elle est plus adaptée au français que celle de Frédéric Brouard. Elle n'est d'ailleurs pas terminée et risque d'évoluer dans un futur proche, en particuliers pour ce qui est des tables de transcriptions et de prédominances.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;&lt;h4&gt;Notes&lt;/h4&gt;
&lt;p&gt;[&lt;a href=&quot;http://blog.mymind.fr/post/2007/03/15/Soundex-Francais#rev-pnote-14-1&quot; id=&quot;pnote-14-1&quot;&gt;1&lt;/a&gt;] L'algorithme prend en compte les modifications fournies par les lecteurs et dont vous retrouverez le détail dans les commentaires. Merci donc aux commentateurs, et particulièrement à &lt;a href=&quot;http://azur.ironie.org/&quot;&gt;David&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;
</description>
    
    
    
          <comments>http://blog.mymind.fr/post/2007/03/15/Soundex-Francais#comment-form</comments>
      <wfw:comment>http://blog.mymind.fr/post/2007/03/15/Soundex-Francais#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.mymind.fr/feed/atom/comments/14</wfw:commentRss>
      </item>
    
  <item>
    <title>Démon pour khtml2png</title>
    <link>http://blog.mymind.fr/post/2007/03/14/Demon-pour-khtml2png</link>
    <guid isPermaLink="false">urn:md5:58e9608d38ac069663e670c212792f8b</guid>
    <pubDate>Wed, 14 Mar 2007 18:24:00 +0100</pubDate>
    <dc:creator>Florent Bruneau</dc:creator>
        <category>Polytechnique.org</category>
        <category>C</category><category>Devel</category><category>khtml2png</category><category>khtmld</category>    
    <description>&lt;p&gt;Une fois qu'on a un outils pour faire les vignettes de site, il devient utile de pouvoir automatiser le travail. Pour ceci, il existe un &lt;a href=&quot;http://wiki.goatpron.de/project/khtmld&quot;&gt;démon pour khtml2png&lt;/a&gt;. Malheureusement (encore une fois), cet outil ne correspondait pas exactement à mes besoins. Donc je l'ai partiellement réécrit (mais rien d'extraordinaire).&lt;/p&gt;    &lt;p&gt;Ce démon qui s'appelle &lt;code&gt;khtmld&lt;/code&gt; fonctionne simplement&amp;nbsp;: il lit une file et à chaque entrée dans cette file, il lance &lt;code&gt;khtml2png&lt;/code&gt;. Donc, il y a deux étapes.&lt;/p&gt;


&lt;p&gt;La première consiste à lancer le démon. Pour ceci, j'ai développé un script d'init... qui sera donc probablement lancé par l'utilisateur &lt;code&gt;root&lt;/code&gt;. Il suffit de modifier ce script pour régler les variables en fonction de son installation, puis dans lancer la commande&amp;nbsp;:&lt;/p&gt;
&lt;pre&gt;
[bash]
./init-script.sh start
&lt;/pre&gt;


&lt;p&gt;Ensuite il n'y a plus qu'à donner au démon la liste des actions à réaliser sous la forme&lt;sup&gt;[&lt;a href=&quot;http://blog.mymind.fr/post/2007/03/14/Demon-pour-khtml2png#pnote-13-1&quot; id=&quot;rev-pnote-13-1&quot;&gt;1&lt;/a&gt;]&lt;/sup&gt;&amp;nbsp;:&lt;/p&gt;
&lt;pre&gt;
[bash]
echo &amp;quot;url fichier&amp;quot; &amp;gt;&amp;gt; /tmp/khtmld.spool
&lt;/pre&gt;


&lt;p&gt;Le principal développement que j'ai réalisé sur &lt;code&gt;khtmld&lt;/code&gt; permet de donner au processus de &lt;code&gt;khtml2png&lt;/code&gt; les droits d'un utilisateur du choix de la personne qui a lancé le démon (certes rien d'extraordinaire, mais ça manquait au programme).&lt;/p&gt;


&lt;p&gt;Voilà, donc un système pour automatiser la réalisation de vignettes même si il reste quelques points sur lesquels il faut réfléchir&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;on ne veut pas un service ouvert (faire un screenshot est une opération lourde)&lt;/li&gt;
&lt;li&gt;on ne peut pas mettre ce service sur un serveur de prod (il est hors de question de lancer un X en production)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Donc il faut s'orienter sur la réalisation d'un serveur de screenshot avec authentification et modération... non-trivial.&lt;/p&gt;


&lt;p&gt;Pour ceux qui voudraient récupérer ma version, elle est disponible dans &lt;a href=&quot;http://blog.mymind.fr/mind/public/khtml2png/khtmld-fru-last.tar.bz2&quot;&gt;les téléchargements&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;&lt;h4&gt;Notes&lt;/h4&gt;
&lt;p&gt;[&lt;a href=&quot;http://blog.mymind.fr/post/2007/03/14/Demon-pour-khtml2png#rev-pnote-13-1&quot; id=&quot;pnote-13-1&quot;&gt;1&lt;/a&gt;] Attention à ne pas mettre d'espace dans le nom du fichier et dans l'url.&lt;/p&gt;&lt;/div&gt;
</description>
    
    
    
          <comments>http://blog.mymind.fr/post/2007/03/14/Demon-pour-khtml2png#comment-form</comments>
      <wfw:comment>http://blog.mymind.fr/post/2007/03/14/Demon-pour-khtml2png#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.mymind.fr/feed/atom/comments/13</wfw:commentRss>
      </item>
    
  <item>
    <title>Outils pratiques</title>
    <link>http://blog.mymind.fr/post/2007/03/13/Outils-pratiques</link>
    <guid isPermaLink="false">urn:md5:9493e53484f0ab915a8ca15e826de2fc</guid>
    <pubDate>Tue, 13 Mar 2007 19:21:00 +0100</pubDate>
    <dc:creator>Florent Bruneau</dc:creator>
        <category>GeekTime</category>
        <category>Devel</category><category>pratique</category><category>SVN</category><category>zsh</category>    
    <description>&lt;p&gt;Etant donné que je travaille énormément avec &lt;a href=&quot;http://subversion.tigris.org&quot;&gt;SVN&lt;/a&gt;. C'est un outils très addictif... à tel point que je l'utilise dès que je travaille sur un projet (seul ou à plusieurs), je crée un reposoire pour le projet (c'est un excellent moyen de ne pas perdre son travail suite à une fausse manoeuvre). Comme en plus je ne supporte pas les front-end pour SVN, je travaille toujours en ligne de commandes...&lt;/p&gt;    &lt;p&gt;Pour pouvoir améliorer la sortie des commandes SVN dans mes consoles, j'ai fait surchargé la commande &lt;code&gt;svn&lt;/code&gt; par une fonction &lt;code&gt;zsh&lt;/code&gt;&amp;nbsp;:&lt;/p&gt;

&lt;pre&gt;
[bash]
function svn() {
    if [[ $1 == &amp;quot;ci&amp;quot; || $1 == &amp;quot;commit&amp;quot; || $1 == &amp;quot;propedit&amp;quot; || $1 == &amp;quot;propset&amp;quot; || $1 == &amp;quot;help&amp;quot; ]]; then
        /usr/local/bin/svn $*
    elif [[ $1 == &amp;quot;preci&amp;quot; || $1 == &amp;quot;precommit&amp;quot; ]]; then
        /usr/local/bin/svn status | grep -v '?' | ~/.zsh/zshcolorsvn
    else
        /usr/local/bin/svn $* | ~/.zsh/zshcolorsvn
    fi
}
&lt;/pre&gt;


&lt;p&gt;Cette fonction est donc très simple&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;si la commande nécessite un interaction de l'utilisateur, on appel directement le programme &lt;code&gt;svn&lt;/code&gt; (le cas de &lt;code&gt;help&lt;/code&gt; permet de ne pas casser la tab-completion de &lt;code&gt;zsh&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;sinon on envoi la sortie de svn dans &lt;a href=&quot;http://blog.mymind.fr/mind/public/misc/zshcolorsvn&quot;&gt;un script&lt;/a&gt; qui réalise sa coloration syntaxique&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ceci donne un résultat de la forme suivante&amp;nbsp;:&lt;/p&gt;


&lt;p&gt;&lt;a href=&quot;http://blog.mymind.fr/public/screenshots/svn-diff.jpg&quot;&gt;&lt;img src=&quot;http://blog.mymind.fr/public/screenshots/.svn-diff_m.jpg&quot; alt=&quot;Exemple de svn diff&quot; /&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;&lt;a href=&quot;http://blog.mymind.fr/public/screenshots/svn-update.jpg&quot;&gt;&lt;img src=&quot;http://blog.mymind.fr/public/screenshots/.svn-update_s.jpg&quot; alt=&quot;Exemple de svn update&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;http://blog.mymind.fr/public/screenshots/svn-status.jpg&quot;&gt;&lt;img src=&quot;http://blog.mymind.fr/public/screenshots/.svn-status_s.jpg&quot; alt=&quot;Exemple de svn status&quot; /&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;C'est donc extrêmement pratique&amp;nbsp;; ça permet de distinguer facilement les modifications, ça permet aussi de voir d'un seul coup d'oeil les conflits et la liste des fichiers modifiés. En plus ça fonctionne également avec des commandes comme &lt;code&gt;cvs&lt;/code&gt; ou &lt;code&gt;diff&lt;/code&gt;&amp;nbsp;:&lt;/p&gt;

&lt;pre&gt;
[bash]
# SVN
function svn() {
    if [[ $1 == &amp;quot;ci&amp;quot; || $1 == &amp;quot;commit&amp;quot; || $1 == &amp;quot;propedit&amp;quot; || $1 == &amp;quot;propset&amp;quot; || $1 == &amp;quot;help&amp;quot; ]]; then
        /usr/local/bin/svn $*
    elif [[ $1 == &amp;quot;preci&amp;quot; || $1 == &amp;quot;precommit&amp;quot; ]]; then
        /usr/local/bin/svn status | grep -v '?' | ~/.zsh/zshcolorsvn
    else
        /usr/local/bin/svn $* | ~/.zsh/zshcolorsvn
    fi; fi
}

# SVN avec conversion de la sortie en latin1
function svn_utf8() {
    if [[ $1 == &amp;quot;ci&amp;quot; || $1 == &amp;quot;commit&amp;quot; ]]; then
        svn $*
    else
        svn $* | iconv -f utf8 -t iso-8859-1
    fi
}

function cvs() {
    if [[ $1 == &amp;quot;diff&amp;quot; ]]; then
        shift 1
        /usr/bin/cvs diff -ubN $* 2&amp;gt; /dev/null | ~/.zsh/zshcolorsvn
    elif [[ $1 == &amp;quot;ci&amp;quot; || $1 == &amp;quot;commit&amp;quot; || $1 == &amp;quot;propedit&amp;quot; || $1 == &amp;quot;propset&amp;quot; || $1 == &amp;quot;help&amp;quot; ]]; then
        /usr/bin/cvs $*
    else
        /usr/bin/cvs $* 2&amp;gt; /dev/null | ~/.zsh/zshcolorsvn
    fi;
}

function diff() { /usr/bin/diff -u $* | ~/.zsh/zshcolordiff }
&lt;/pre&gt;


&lt;p&gt;Les scripts nécessaires sont disponibles&amp;nbsp;: &lt;a href=&quot;http://blog.mymind.fr/public/misc/zshcolorsvn&quot;&gt;zshcolorsvn&lt;/a&gt; et &lt;a href=&quot;http://blog.mymind.fr/public/misc/zshcolordiff&quot;&gt;zshcolordiff&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;Seul défaut&amp;nbsp;: pour pouvoir utiliser les commandes sans coloration... il faut taper chemin complet.&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.mymind.fr/post/2007/03/13/Outils-pratiques#comment-form</comments>
      <wfw:comment>http://blog.mymind.fr/post/2007/03/13/Outils-pratiques#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.mymind.fr/feed/atom/comments/12</wfw:commentRss>
      </item>
    
  <item>
    <title>Joie !</title>
    <link>http://blog.mymind.fr/post/2007/03/13/Joie</link>
    <guid isPermaLink="false">urn:md5:743fbd8ffc8c000770bdc17a8eb188f2</guid>
    <pubDate>Tue, 13 Mar 2007 12:41:00 +0100</pubDate>
    <dc:creator>Florent Bruneau</dc:creator>
        <category>GeekTime</category>
        <category>Devel</category><category>khtml2png</category>    
    <description>    &lt;p&gt;Mon travail sur &lt;a href=&quot;http://khtml2png.sourceforge.net/&quot;&gt;khtml2png&lt;/a&gt; vient d'être releasé (version 2.6.0) par Hauke (le programmeur principal du projet). Cette version corrige tous les bugs dont j'ai pu parler dans mes précédents billets&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Des failles de sécurité&lt;/li&gt;
&lt;li&gt;Problème de bandes grises si X n'est pas assez grand&lt;/li&gt;
&lt;li&gt;Blocage du programme en cas de popup&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Elle supprime la dépendance à ImageMagick (ce qui permet au passage de simplifier le code). Ainsi, mon code permettait de passer de 600 lignes à 320 lignes, avec le travail de Hauke au dessus (principalement de l'alignement de code), le fichier source fait 390 lignes...&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.mymind.fr/post/2007/03/13/Joie#comment-form</comments>
      <wfw:comment>http://blog.mymind.fr/post/2007/03/13/Joie#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.mymind.fr/feed/atom/comments/11</wfw:commentRss>
      </item>
    
  <item>
    <title>A croire que certains le font exprès !</title>
    <link>http://blog.mymind.fr/post/2007/03/10/A-croire-que-certains-le-font-expres</link>
    <guid isPermaLink="false">urn:md5:d6e16a34562220853a6bcc75151964c7</guid>
    <pubDate>Sat, 10 Mar 2007 19:57:00 +0100</pubDate>
    <dc:creator>Florent Bruneau</dc:creator>
        <category>Polytechnique.org</category>
        <category>Cpp</category><category>Devel</category><category>khtml2png</category><category>Qt</category><category>Sécurité</category>    
    <description>&lt;p&gt;Depuis trois jours, je travaille sur la mise ne place d'un outil permettant de faire des aperçus graphiques de site web (des vignettes façon &lt;a href=&quot;http://www.exalead.fr&quot;&gt;Exalead&lt;/a&gt; par exemple). C'est une fonctionnalité très à la mode... et c'est aussi un bon moyen d'avoir un aperçu d'un site. Donc dans ce cadre, j'ai commencé à travailler sur &lt;a href=&quot;http://khtml2png.sourceforge.net&quot;&gt;khtml2png&lt;/a&gt;. Malheureusement, comme il ne correspondait pas exactement à mes besoins, j'ai commencé à en modifier le code source... et j'ai eu quelques surprises&amp;nbsp;!&lt;/p&gt;    &lt;h3&gt;Strings&lt;/h3&gt;


&lt;p&gt;Ma première (mauvaise) surprise a été de constater que le code était loin d'être propre. Il s'agit d'un programme écrit avec la bibliothèque &lt;a href=&quot;http://www.trolltech.com/qt&quot;&gt;Qt&lt;/a&gt; (KHTML oblige), et pourtant la gestion des chaînes de caractère est faite pour moitié avec QString, pour moitié avec l'API C... sans vérification de la taille des buffers.&lt;/p&gt;


&lt;p&gt;Par exemple&amp;nbsp;:&lt;/p&gt;
&lt;pre&gt;
[cpp]
QString filename = &amp;quot;/tmp/khtml2png.png&amp;quot;;
int g = sprintf(nrStr,&amp;quot;_x%iy%i&amp;quot;,xNr,yNr);
nrStr[g]='\\0';
filename+=QString(nrStr);
&lt;/pre&gt;


&lt;p&gt;Quitte à utiliser l'API C autant le faire proprement, en vérifiant la taille du buffer (dans le cas présent, le buffer nrStr avait une taille de 10)... mais en plus pourquoi faire ça de cette manière alors que Qt fournit l'API suffisant pour coder ces 4 lignes sans le moindre risque de buffer overflow&amp;nbsp;?&lt;/p&gt;


&lt;p&gt;//
&lt;a href=&quot;http://blog.mymind.fr/post/2007/03/10/cpp&quot; title=&quot;cpp&quot;&gt;cpp&lt;/a&gt;
QString filename = QString( &quot;/tmp/khtml2png.png_x%1y%2&quot;).arg(xNr).arg(yNr);
//&lt;/p&gt;


&lt;p&gt;Ensuite (toujours dans la gestion des chaînes de caractères), la méthode pour éviter le buffer overflow était le &quot;Je fais un gros buffer, au moins je suis sûr que ça ne débordera pas&quot;... mais le problème, c'est que ça peut déborder&amp;nbsp;!&lt;/p&gt;

&lt;pre&gt;
[cpp]
char 	[5000], //command line string

memset(cmd,0,sizeof(cmd));

//append the row images from top to bottom to one image
strcpy(cmd,&amp;quot;convert &amp;quot;);

for (int y=0; y &amp;lt; yNr; y++)
    sprintf(cmd,&amp;quot;%s /tmp/khtml2png.png_r%i&amp;quot;,cmd,y);
		
sprintf(cmd,&amp;quot;%s -append %s&amp;quot;,cmd,args-&amp;gt;arg(1));
system(cmd);
&lt;/pre&gt;


&lt;p&gt;Dans ce cas précis, &lt;code&gt;args-&amp;gt;arg(1)&lt;/code&gt; est contrôlé par l'utilisateur (c'est en fait le fichier destination de la capture demandée... le &lt;code&gt;sprintf&lt;/code&gt; est donc une &lt;strong&gt;erreur impardonnable&lt;/strong&gt;... sans compter qu'en plus cet argument qui est passé à un exécutable externe sans le moindre check sur le contenu de la chaîne. On risque non seulement le buffer overflow, mais également l'injection de code dans le &lt;code&gt;system&lt;/code&gt; (par exemple, je peux appeler mon fichier &lt;code&gt;fichier;sh&lt;/code&gt;, ça me lancera un shell avec les droits de l'utilisateur qui a lancé le programme.&lt;/p&gt;


&lt;p&gt;Une solution (non testée) pourrait être&amp;nbsp;:&lt;/p&gt;

&lt;pre&gt;
[cpp]
QProcess process(&amp;quot;convert&amp;quot;);
for (int y=0 ; y &amp;lt; yNr ; y++) {
    process.addArgument(QString(&amp;quot;/tmp/khtml2png.png_r%i&amp;quot;).arg(y);
}
process.addArgument(&amp;quot;-append&amp;quot;);
process.addArgument(args-&amp;gt;arg(1));
process.start();
while (process.isRunning()) {
    wait(10); // nombre choisi aléatoirement
}
&lt;/pre&gt;


&lt;p&gt;Cette solution a le mérite&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;d'être safe car elle ne permet pas d'injecter des commandes dans notre code&lt;/li&gt;
&lt;li&gt;d'être safe car elle ne permet pas de buffer overflow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bien sûr ceci repose sur la confiance qu'on peut avoir en Qt...&lt;/p&gt;



&lt;h3&gt;Images&lt;/h3&gt;


&lt;p&gt;Pour générer le screenshot, khtml2png fait plusieurs captures dans une fenêtre en scrollant à l'intérieur de manière à recouvrir une zone aillant la taille demandée par l'utilisateur. C'est très bien... malheureusement, encore une fois je me demande quel est l'intérêt d'utiliser Qt dans le cas présent. La technique de khtml2png (version 2.5.0) est de faire une capture d'écran à chaque fois... puis de la stocker dans un fichier temporaire indexé avec le numéro du morceau en X et en Y.&lt;/p&gt;


&lt;p&gt;Une fois tous les morceaux obtenus, le programme utilise &lt;code&gt;convert&lt;/code&gt; de ImageMagick pour coller les morceaux de chaque ligne, puis une deuxième fois (enfin, ce n'est pas la deuxième fois, mais la deuxième boucle) pour coller les différentes lignes et convertir dans le format voulu (c'est en fait le dernier morceau de code que j'ai collé ci-dessus).&lt;/p&gt;


&lt;p&gt;Pourquoi faire si compliqué&amp;nbsp;?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;On ne peut pas lancer deux fois khtml2png en même temps (le programme utilisant toujours le même nom pour les fichiers temporaires)&lt;/li&gt;
&lt;li&gt;Qt aussi est capable d'enregistrer les fichiers dans différents formats... pas besoin de ImageMagick pour ça&lt;/li&gt;
&lt;li&gt;khtml2png dépend d'un programme extérieur qu'il n'est pas certain de trouver sur les machines des utilisateurs...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ma technique est beaucoup plus simple, ne nécessite de lancer &lt;strong&gt;aucun&lt;/strong&gt; programme externe... et en plus se révèle plus légère en quantité de mémoire (parce que j'utilise des pointeurs au lieu de recopier les images dans tous les sens en en créant plusieurs instances à chaque fois)&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;tout d'abord je crée une image vierge de la taille voulue par l'utilisateur&lt;/li&gt;
&lt;li&gt;je fais les captures du site et au lieu de les stockers dans un fichier, je les colle au bon endroit dans mon image&lt;/li&gt;
&lt;li&gt;j'utilise Qt pour enregistrer l'image au format désiré par l'utilisateur (en fonction de l'extension)...&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Ainsi, j'ai supprimé la &lt;em&gt;totalité&lt;/em&gt; du code qui utilisait des traitements de chaînes de caractères (qui n'étaient autres que les appels à &lt;code&gt;convert&lt;/code&gt;), ce qui supprime toutes les failles dont j'ai parlé ci-dessus... en gardant les mêmes fonctionnalités que la version publique du programme.&lt;/p&gt;



&lt;h3&gt;Besoins particuliers&lt;/h3&gt;


&lt;p&gt;J'ai également rencontré un besoin qui a mon avis n'était pas prévu par les développeurs du programme&amp;nbsp;: étant donné que je le fais tourner dans un environnement graphique inaccessible (en fait dans un &lt;code&gt;vncserver&lt;/code&gt;), je ne vois pas ce qu'il se passe. Or, KHTML déclenche automatiquement une boîte de dialogue modale dès qu'il rencontre un objet d'un type mime inconnu... dans mon cas il s'agissait d'un applet active-x qui traîne sur le &lt;a href=&quot;http://www.polytechnique.fr&quot;&gt;site de l'Ecole Polytechnique&lt;/a&gt;.&lt;/p&gt;


&lt;p&gt;J'ai donc cherché pendant 2 jours comment contourner le programme&amp;nbsp;: il me faut pouvoir avoir accès à la boîte de dialogue créée, et la supprimer puisque l'API de &lt;a href=&quot;http://api.kde.org/3.1-api/khtml/html/classKHTMLPart.html&quot;&gt;KHML&lt;/a&gt; ne permet pas de désactiver ces intrusions directement depuis le programme.&lt;/p&gt;


&lt;p&gt;Tout d'abord j'ai cru qu'en réimplémentant la méthode &lt;code&gt;showError&lt;/code&gt; ça marcherait... mais en fait non, elle n'est pas appelée dans le cas présent, c'est uniquement généré à l'intérieur du moteur KHTML... la classe &lt;code&gt;KHTMLPart&lt;/code&gt; n'est jamais notifiée de l'apparition de cette boîte de dialogue.&lt;/p&gt;


&lt;p&gt;J'ai donc cherché qui pouvait bien être le père de ce &lt;code&gt;QMessageBox&lt;/code&gt;... et en fait, c'est le &lt;code&gt;KHTMLPart::view()&lt;/code&gt;. N'ayant pas vraiment la possibilité de substituer à cet objet, un objet de mon choix, j'ai ajouté un &lt;code&gt;eventFilter&lt;/code&gt; qui filtre les messages reçus par la fenêtre de rendu... et lorsque apparaît un &lt;code&gt;QDialog&lt;/code&gt; (classe mère de &lt;code&gt;QMessageBox&lt;/code&gt;), je me charge directement de le rendre non modal, de le découpler du view et de le détruire)... et là, victoire !!!&lt;/p&gt;


&lt;p&gt;Je comprends parfaitement que les développeurs n'aient pas pensé que ces boîtes de dialogues puissent être gênantes car ils doivent travailler dans un environnement graphique et les voir... moi non&amp;nbsp;! Mais en fait, ce que je comprends moins bien c'est qu'ils ont clairement déjà rencontré le problème dans le cadre de la réalisation du screenshot. En effet, on y trouve le code (pour sélectionner les fenêtres-filles qui méritent d'apparaître dans le screenshot)&amp;nbsp;:&lt;/p&gt;

&lt;pre&gt;
[cpp]
if ( child-&amp;gt;isWidgetType() &amp;amp;&amp;amp;
    ((QWidget *)child)-&amp;gt;geometry().intersects( w-&amp;gt;rect() ) &amp;amp;&amp;amp;
    ! child-&amp;gt;inherits( &amp;quot;QDialog&amp;quot; ) ) {
&lt;/pre&gt;


&lt;p&gt;Les développeurs ont donc déjà rencontré des QDialog... pourquoi ne pas déjà les avoir désactivés&amp;nbsp;?&lt;/p&gt;



&lt;h3&gt;Conclusion&lt;/h3&gt;


&lt;p&gt;J'ai donc maintenant un khtml2png adapté à mes besoins. Je vais soumettre mon code aux développeurs du projet.&lt;/p&gt;


&lt;p&gt;À savoir qu'à l'heure actuelle (et je n'ai pas fini le nettoyage), mon code fait 80 lignes de moins que le code dont je suis parti... et ce malgré l'ajout de fonctionnalités.&lt;/p&gt;


&lt;p&gt;&lt;a href=&quot;http://blog.mymind.fr/mind/public/khtml2png/khtml2png-fru-last.tar.bz2&quot;&gt;Télécharger la dernière version&lt;/a&gt;&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.mymind.fr/post/2007/03/10/A-croire-que-certains-le-font-expres#comment-form</comments>
      <wfw:comment>http://blog.mymind.fr/post/2007/03/10/A-croire-que-certains-le-font-expres#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.mymind.fr/feed/atom/comments/9</wfw:commentRss>
      </item>
    
  <item>
    <title>Polytechnique.org en retard ?</title>
    <link>http://blog.mymind.fr/post/2007/03/01/Polytechniqueorg-en-retard</link>
    <guid isPermaLink="false">urn:md5:ad2416e637423f187d754928f7039285</guid>
    <pubDate>Thu, 01 Mar 2007 16:28:00 +0100</pubDate>
    <dc:creator>Florent Bruneau</dc:creator>
        <category>Polytechnique.org</category>
        <category>Devel</category><category>Ergonomie</category><category>platal</category>    
    <description>&lt;p&gt;&lt;a href=&quot;https://www.polytechnique.org&quot;&gt;Polytechnique.org&lt;/a&gt; est, comme l'indique le nom du logiciel OpenSource sur lequel le site repose (&lt;a href=&quot;http://opensource.polytechnique.org/platal/&quot;&gt;plat/al&lt;/a&gt;), une plateforme pour les anciens élèves de l'&lt;a href=&quot;http://www.polytechnique.fr&quot;&gt;École&lt;/a&gt;... c'est à dire que Polytechnique.org devrait&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;apporter de la vie dans la communauté&lt;/li&gt;
&lt;li&gt;faciliter les mises en relation entre les membres&lt;/li&gt;
&lt;li&gt;offrir des services à la communauté&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Polytechnique.org offre ces trois services... mais pourtant moins d'un utilisateur sur 5 se connecte régulièrement au site (une fois par semaine - et le plus souvent c'est pour accéder à des sites qui utilisent l'authentification de Polytechnique.org), environ un sur 3 se connecte une fois par mois, et un sur 3 ne se connecte tout bonnement jamais. Face à cela, on dénombre un grand nombre d'utilisateurs qui sont intéressés par un groupe Polytechnique sur des outils comme Linked-In... pourquoi&amp;nbsp;? parce que le rôle de Polytechnique.org n'est rempli qu'à moitié et ce pour plusieurs raisons&amp;nbsp;:&lt;/p&gt;    &lt;h2&gt;Ergonomie&lt;/h2&gt;


&lt;p&gt;La catastrophe sur Polytechnique.org c'est l'ergonomie... ce n'est certes pas la fin du monde (on peut encore s'y retrouver), mais le site ne donne pas envie de s'y arrêter. Je vais essayer de détailler les divers problèmes&amp;nbsp;:&lt;/p&gt;


&lt;h3&gt;Le menu&lt;/h3&gt;


&lt;p&gt;&lt;a href=&quot;http://blog.mymind.fr/mind/public/screenshots/menu.jpg&quot;&gt;&lt;img src=&quot;http://blog.mymind.fr/mind/public/screenshots/.menu_t.jpg&quot; alt=&quot;Menu du site&quot; style=&quot;float:left; margin: 0 1em 1em 0;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;Le menu de Polytechnique.org témoigne de la richesse du site&amp;nbsp;: il est long. Comme tout menu, il a fallu choisir l'ordre des entrées. Le choix de cet ordonnancement laisse clairement à désirer. Par exemple&amp;nbsp;: où chercher un lien vers l'annuaire&amp;nbsp;? Dans &lt;em&gt;Services&lt;/em&gt; ou &lt;em&gt;Communauté X&lt;/em&gt;&amp;nbsp;? Etant un utilisateur du site depuis longtemps, je mets toujours autant de temps avant de trouver ce que je cherche dans le menu.&lt;/p&gt;


&lt;p&gt;Peut-être devrions-nous revoir tout bonnement l'organisation du menu, par exemple avec des catégories plus parlantes, par exemple un premier jet pourrait donner (mais ça mérite d'être travaillé)&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mes emails
&lt;ul&gt;
&lt;li&gt;Mes redirections&lt;/li&gt;
&lt;li&gt;Mes abonnements&lt;/li&gt;
&lt;li&gt;Antispam&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Annuaire
&lt;ul&gt;
&lt;li&gt;Rechercher&lt;/li&gt;
&lt;li&gt;Mon profil&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Communauté
&lt;ul&gt;
&lt;li&gt;Annonces&lt;/li&gt;
&lt;li&gt;Lettre mensuelle&lt;/li&gt;
&lt;li&gt;Discussions&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Emploi&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Deux sites séparés&lt;/h3&gt;


&lt;p&gt;Polytechnique.org c'est aussi Polytechnique.net&amp;nbsp;: le site des groupes. Le fait d'avoir 2 sites totalement séparés pose un grand nombre de problème, depuis le partage de l'authentification, jusqu'à la cohérence des données.&lt;/p&gt;


&lt;p&gt;Il faut clairement envisager de fusionner les deux sites dans un avenir plus ou moins proche si on veut que les utilisateurs s'y retrouvent. De la même manière qu'on peut réorganiser le menu, on peut réorganiser l'accès général au site... Par exemple, on pourrait envisager de créer un menu tabulé&amp;nbsp;: dans chaque tab, on retrouve un menu spécifique. Par exemple, on pourrait, au lieu d'avoir un menu à deux niveaux, des tabs (Mes emails, Annuaire, Annonces...) et dans chaque tabs un menu spécifique donnant accès aux fonctionnalités correspondantes.&lt;/p&gt;


&lt;p&gt;&lt;strong&gt;Avantages :&lt;/strong&gt; On aurait ainsi un proprement rangé... le site étant modulaire, chaque module pourrait lui même générer ses entrées dans les menus/tabs, l'intégration des Polytechnique.net à Polytechnique.org ne serait que l'ajout d'un tab &quot;Mes groupes X&quot;&lt;br /&gt;
&lt;strong&gt;Défauts :&lt;/strong&gt; On a pas d'accès facile à l'ensemble des fonctionnalités... c'est le seul défaut (pas des moindres) que je vois.&lt;/p&gt;


&lt;p&gt;C'est une solution qui mérite qu'on s'y intéresse... le choix de la meilleur ergonomie possible nécessitera de toute façon des tests.&lt;/p&gt;


&lt;h3&gt;Dinosaure&lt;/h3&gt;


&lt;p&gt;&lt;strong&gt;Toutes&lt;/strong&gt; les skins de Polytechnique.org sont carrées... En particulier la skin par défaut a très mal vieilli. Les polices y sont énormes, toutes les informations sont dans des boîtes carrées. Le site à sérieusement besoin d'une petite cure de jouvence pour retrouver un design aguichant.&lt;/p&gt;



&lt;h2&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Web_2.0&quot;&gt;Web 2.0&lt;/a&gt;&lt;/h2&gt;


&lt;p&gt;Dire que son site est Web 2.0 est à la mode... Polytechnique.org ne l'est pas vraiment, et ceci pour diverses raisons.&lt;/p&gt;


&lt;h3&gt;La pointe de la technologie&lt;/h3&gt;


&lt;p&gt;Tout d'abord le site est trop statique. Quand la page d'accueil est chargée, elle est chargée... à la rigueur on peut fermer quelques boites mais c'est tout. Le site est statique... Le Web actuel s'ouvre vers des pages vivantes avec lesquels l'utilisateur peut interagir... Le plus souvent cela repose sur des technologies du type Ajax. Polytechnique.org utilise un peu Ajax, mais on va dire que c'est &lt;em&gt;artisanal&lt;/em&gt;... il y a un gros boulot à faire de ce côté si on veut que le site devienne un outil convivial pour l'utilisateur.&lt;/p&gt;


&lt;p&gt;Une autre technologie qui fait le succès du web est l'édition dynamique de contenu. Polytechnique.org utilise du wiki pour l'édition de sa documentation... mais, en grande majorité, ceci se limite à la simplification du travail d'administration du site. Par contre pour tous les contenus dynamiques, nous n'offrons que du texte brut à nos utilisateurs. Là où se trouve le vrai problème, c'est sur l'outil d'hébergement que nous offrons aux groupes&amp;nbsp;: &lt;a href=&quot;http://opensource.polytechnique.org/diogenes&quot;&gt;Diogenes&lt;/a&gt;.&lt;/p&gt;


&lt;p&gt;Diogenes a mal vieilli parce que sont apparus face à lui des outils plus simples à utiliser. Aujourd'hui Diogenes mérite un gros décrassage si on veut pouvoir continuer à l'utiliser.&lt;/p&gt;


&lt;h3&gt;Vie sociale&lt;/h3&gt;


&lt;p&gt;Là où Polytechnique.org est le plus en retard, c'est sur les outils qui permettent de donner vie à la communauté. Certes nous avons nos forums, mais ils ne sont pas vraiment mis en avant sur le site... Nous n'avons en effet nulle part des liens qui permettent aux utilisateurs de commenter l'actualité de la communauté. Pour améliorer ça, nous pourrions par exemple associer à chaque annonce une discussion sur un forum dédié (discussion qui serait initiée par la publication de l'annonce en question sur le forum en plus de la page d'accueil).&lt;/p&gt;


&lt;h2&gt;Conclusion&lt;/h2&gt;


&lt;p&gt;Voilà, tout ceci un peu en vrac pour dire que nous avons des outils, de très bons outils même, largement en avance sur l'utilisation qu'en font les utilisateurs. Malheureusement nous souffrons d'un manque d'adaptation à l'utilisateur&amp;nbsp;: l'utilisateur recherche avant tout un site facile à utiliser sur lequel il puisse faire ce qu'il cherche le plus rapidement possible.&lt;/p&gt;


&lt;p&gt;Il est nécessaire de réorienter fortement le développement vers l'ergonomie dans les mois qui viennent&amp;nbsp;: à terme il faudrait que les utilisateurs puissent utiliser Polytechnique.org comme une page d'accueil conviviale offrant des services tels qu'on en trouve couramment sur les principaux portails (recherche Internet, outils de gestion &lt;a href=&quot;http://en.wikipedia.org/wiki/Personal_information_manager&quot;&gt;PIM&lt;/a&gt;...) tout en offrant les services de base d'une plateforme pour alumnis.&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.mymind.fr/post/2007/03/01/Polytechniqueorg-en-retard#comment-form</comments>
      <wfw:comment>http://blog.mymind.fr/post/2007/03/01/Polytechniqueorg-en-retard#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.mymind.fr/feed/atom/comments/7</wfw:commentRss>
      </item>
    
  <item>
    <title>Un client RSS pour lire les Forums NNTP et les Mailing-Lists...</title>
    <link>http://blog.mymind.fr/post/2007/02/25/Un-client-RSS-pour-lire-les-Forums-NNTP-et-les-Mailing-Lists</link>
    <guid isPermaLink="false">urn:md5:ccec4d2a8525474fc851b3082b3f91ad</guid>
    <pubDate>Sun, 25 Feb 2007 19:05:00 +0100</pubDate>
    <dc:creator>Florent Bruneau</dc:creator>
        <category>Polytechnique.org</category>
        <category>Banana</category><category>Devel</category><category>Mailing-Lists</category><category>NNTP</category><category>PHP</category><category>RSS</category>    
    <description>    &lt;p&gt;Si il y a un bout de code dont je suis content au sein de &lt;a href=&quot;https://www.polytechnique.org&quot;&gt;Polytechnique.org&lt;/a&gt;, c'est &lt;a href=&quot;http://opensource.polytechnique.org/banana/&quot;&gt;Banana&lt;/a&gt;. Banana est à l'origine un client Web pour le protocole NNTP (c'est à dire le protocole utilisé par Usenet). Depuis sa dernière version (la 1.5), Banana est capable d'utiliser n'importe quel protocole comme source (les protocoles actuellement implémentés étant le NNTP et la lecture de MBox, mais on pourrait envisager d'ajouter le support des Maildir ou d'IMAP sans problème), ainsi, à Polytechnique.org, nous utilisons Banana pour offrir une plateforme Web vers &lt;a href=&quot;https://www.polytechnique.org/banana&quot;&gt;nos forums&lt;/a&gt; et pour mettre en ligne les archives des Mailing-Lists que nous hébergeons.&lt;/p&gt;


&lt;p&gt;Banana est à mon avis un bon outils&amp;nbsp;: il permet un rendu plus que correct de la plupart des mails HTML (même ceux dont le formatage est défini dans une feuille de style), il affiche les discussions proprement et rapidement (grâce à un système de cache du côté serveur). C'est donc un gros plus en comparaison des interfaces habituelles de consultation d'archives de Mailing-List qu'on peut trouver sur Internet... et puis, ce n'est pas un forum php, pas de fioritures à la phpbb&amp;nbsp;: Banana est clair, lisible et rapide... et facile à installer. Pour s'en convaincre, il suffit de regarder la &lt;a href=&quot;http://opensource.polytechnique.org/viewsvn/filedetails.php?repname=Banana&amp;amp;path=/trunk/examples/index.php&amp;amp;rev=0&amp;amp;sc=1&quot;&gt;fichier d'exemple&lt;/a&gt; qui fournit un banana totalement fonctionnel (à chacun ensuite d'y ajouter sa couche d'authentification si nécessaire).&lt;/p&gt;


&lt;p&gt;La grande nouveauté de la prochaine version de Banana est l'intégration de flux RSS... ainsi il sera possible de lire les forums sans se connecter au site et sans client news, ou de suivre les discussions des mailing-lists sans relever son courrier (le premier des 2 cas étant certainement le plus intéressant). Pour les utilisateurs de Polytechnique.org, la fonctionnalité est d'ores et déjà disponible sur &lt;a href=&quot;http://dev.m4x.org/~x2003bruneau/banana&quot;&gt;ma version de développement&lt;/a&gt;. Deux types de flux son disponibles&amp;nbsp;: soit un flux par groupe, soit un flux regroupant tous les groupes auxquels on est abonné.&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.mymind.fr/post/2007/02/25/Un-client-RSS-pour-lire-les-Forums-NNTP-et-les-Mailing-Lists#comment-form</comments>
      <wfw:comment>http://blog.mymind.fr/post/2007/02/25/Un-client-RSS-pour-lire-les-Forums-NNTP-et-les-Mailing-Lists#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.mymind.fr/feed/atom/comments/4</wfw:commentRss>
      </item>
    
</channel>
</rss>
