<?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... - GeekTime</title>
  <link>http://blog.mymind.fr/</link>
  <atom:link href="http://blog.mymind.fr/feed/category/GeekTime/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>Yet another policy daemon for postfix</title>
    <link>http://blog.mymind.fr/post/2009/04/06/Yet-another-policy-daemon-for-postfix2</link>
    <guid isPermaLink="false">urn:md5:4b28b577e017c0d4387574e76226efec</guid>
    <pubDate>Mon, 06 Apr 2009 22:04:00 +0200</pubDate>
    <dc:creator>Florent Bruneau</dc:creator>
        <category>GeekTime</category>
            
    <description>    &lt;p&gt;&lt;a href=&quot;http://blog.madism.org/index.php/2007/08/29/136-postfix-and-srs&quot;&gt;MadCoder announced it months ago&lt;/a&gt;, he has been working on the pfixtools. The second tool of the &lt;a href=&quot;http://www.postfix.com&quot;&gt;postfix&lt;/a&gt;-related toolsuite is named &lt;strong&gt;postlicyd&lt;/strong&gt;.&lt;/p&gt;


&lt;p&gt;postlicyd is a versatile &lt;a href=&quot;http://www.postfix.org/SMTPD_POLICY_README.html&quot;&gt;policy daemon&lt;/a&gt; written in C. It does greylisting (far faster than postgrey), it performs R(H)BL access (both locally directly from rbldns zone files and remotely by using DNS), ... So, it can be used as a replacement for &lt;a href=&quot;http://packages.qa.debian.org/w/whitelister.html&quot;&gt;whitelister&lt;/a&gt; and &lt;a href=&quot;http://postgrey.schweikert.ch/&quot;&gt;postgrey&lt;/a&gt; with a significant improvement of the performances.&lt;/p&gt;


&lt;p&gt;On the same server (with the same email trafic), postlicyd is more than 20 times faster than postgrey:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Process load: postgrey ~20% CPU, postlicyd less than 1% CPU&lt;/li&gt;
&lt;li&gt;Data base cleanup for 1M entries: postgrey 20 minutes, postlicyd 40 seconds&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Moreover, it is aware of the 'session' feature of the POLICY protocol. Thus, you can write complex configurations and define policies that do not depend on a single SMTP command (like RCPT) but on the whole SMTP transaction...&lt;/p&gt;


&lt;p&gt;More informations: &lt;a href=&quot;http://pfixtools.mymind.fr&quot; title=&quot;http://pfixtools.mymind.fr&quot;&gt;http://pfixtools.mymind.fr&lt;/a&gt;&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.mymind.fr/post/2009/04/06/Yet-another-policy-daemon-for-postfix2#comment-form</comments>
      <wfw:comment>http://blog.mymind.fr/post/2009/04/06/Yet-another-policy-daemon-for-postfix2#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.mymind.fr/feed/atom/comments/42</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>Spaces</title>
    <link>http://blog.mymind.fr/post/2007/06/02/Spaces</link>
    <guid isPermaLink="false">urn:md5:be17c145e8a970e2e9cccd4d3e6c66a7</guid>
    <pubDate>Sat, 02 Jun 2007 14:44:00 +0200</pubDate>
    <dc:creator>Florent Bruneau</dc:creator>
        <category>GeekTime</category>
        <category>Mac</category><category>VirtueDesktops</category>    
    <description>&lt;p&gt;Comme un certain nombre de personnes le sait déjà, j'ai repris le développement de &lt;a href=&quot;http://virtuedesktops.info&quot;&gt;VirtueDesktops&lt;/a&gt; depuis quelques semaines. Dans un premier temps je n'avais pas regardé le fonctionnement bas niveau du programme, mais la semaine dernière j'ai commencé à rechercher dans les sources &quot;Comment Virtue fait-il pour cacher les fenêtres, faire les transitions etc... ?&quot;.&lt;/p&gt;    &lt;p&gt;A ma grande surprise, tout ceci est en fait géré nativement par MacOS X... la bibliothèque CoreGraphics contient en effet quelques fonctions cachées qui gèrent l'attribution d'une fenêtre à un Workspace et les transitions entre ces Workspaces. On peut trouver la liste complète de ces fonctions sur la &lt;a href=&quot;http://trac.virtuedesktops.info/browser/trunk/Shared/Headers/CGSPrivate.h&quot;&gt;SVN de VirtueDesktops&lt;/a&gt;.&lt;/p&gt;

&lt;pre&gt;
[c_mac]
extern OSStatus CGSMoveWorkspaceWindowList(const CGSConnection connection, CGSWindow *wids, int count, int toWorkspace);
extern OSStatus CGSGetWorkspace(const CGSConnection cid, int *workspace);
extern OSStatus CGSGetWindowWorkspace(const CGSConnection cid, const CGSWindow wid, int *workspace);
extern OSStatus CGSSetWorkspace(const CGSConnection cid, int workspace);
&lt;/pre&gt;


&lt;p&gt;VirtueDesktops (et également DesktopsManager) n'est qu'une interface graphique qui tente d'utiliser ces fonctions. Et là &lt;a href=&quot;http://www.apple.com/fr/macosx/leopard/spaces.html&quot;&gt;Spaces&lt;/a&gt; part avec une longueur d'avance car contrairement à VirtueDesktops, il sera facile pour Apple de gérer les ouvertures, fermetures et masquage d'application ce qui est à mon avis le plus gros point faible de Virtue. J'ai beaucoup travaillé là-dessus et je pense arriver actuellement aux limites de ce qu'il est possible de faire avec un gestionnaire de bureaux virtuels sur Tiger.&lt;/p&gt;


&lt;p&gt;Un autre problème de VirtueDesktops est l'accès à l'ordonnancement des fenêtres. Comment être sûr que lorsqu'on arrive sur un bureau les fenêtres sont dans le bon ordre&amp;nbsp;? Idéalement il faudrait enregistrer l'ordre en temps réel et le restaurer lors du retour sur le bureau. Ceci permettrait également de toujours savoir quelle application activer lorsqu'on arrive sur un bureau, simplement en utilisant la fenêtre qui se trouve au premier plan.&lt;/p&gt;


&lt;p&gt;Voilà, je me suis certes lancé dans une cause perdue d'avance, mais je suis tout de même content du résultat obtenu lors de ces dernières semaines. Virtue a désormais un comportement qui correspond à ce que j'attends d'un gestionnaire de bureaux virtuels&amp;nbsp;: quand je change d'application il va sur le bureau adéquat, et quand je change de bureau, il active bien la dernière application que j'ai utilisée sur ce bureau.&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.mymind.fr/post/2007/06/02/Spaces#comment-form</comments>
      <wfw:comment>http://blog.mymind.fr/post/2007/06/02/Spaces#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.mymind.fr/feed/atom/comments/29</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>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>Trous de mémoire</title>
    <link>http://blog.mymind.fr/post/2007/04/04/Trous-de-memoire</link>
    <guid isPermaLink="false">urn:md5:a217a1a7306caf893a19e127b1e72e5b</guid>
    <pubDate>Wed, 04 Apr 2007 00:01:00 +0200</pubDate>
    <dc:creator>Florent Bruneau</dc:creator>
        <category>GeekTime</category>
        <category>Mac</category>    
    <description>&lt;p&gt;Quand j'utilise mon ordinateur, j'aime bien que son fonctionnement soit fluide. C'est à dire que lorsque je passe d'une application à l'autre (ce qui arrive régulièrement), je ne veux pas qu'il y ait 10 secondes de latence parce que ma machine &quot;swap&quot;. Malheureusement, je ne connais aucun OS sur lequel ça ne swap pas. Par exemple, sur mon portable à l'instant même j'ai 2Go de swap (donc 700Mo utilisés) sachant qu'à côté j'ai 600Mo de RAM utilisés (et les quelques 400Mo de RAM qui restent servent de cache disque...).&lt;/p&gt;


&lt;p&gt;Comment un ordinateur sur lequel tourne un navigateur web, un client IRC et un client mail peut avoir autant de RAM occupée ???&lt;/p&gt;    &lt;p&gt;La réponse n'est pas très dure à trouver... il suffit de se munir de différents petits outils&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;un logiciel de monitoring (par exemple le &lt;em&gt;Moniteur d'activité&lt;/em&gt; de Mac OS)&lt;/li&gt;
&lt;li&gt;d'un outil comme le programme &lt;code&gt;leaks&lt;/code&gt; qui détecte les zone de mémoire perdues (les memory-leaks)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Et là, c'est assez surprenant. Commençons par trier les programmes par mémoire occupée dans le moniteur&amp;nbsp;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Le noyau arrive en premier... bon, je ne sais pas ce qui est compté comme mémoire utilisée par le noyau, on va dire que c'est normal&lt;/li&gt;
&lt;li&gt;Le serveur graphique en deuxième...&lt;/li&gt;
&lt;li&gt;Colloquy (client IRC) avec 47Mo de mémoire &lt;em&gt;réelle&lt;/em&gt; (284Mo de mémoire virtuelle)&lt;/li&gt;
&lt;li&gt;Mail avec 39Mo/270Mo&lt;/li&gt;
&lt;li&gt;Vienna (syndicateur RSS) 34Mo/286Mo&lt;/li&gt;
&lt;li&gt;Safari (browser) 31Mo/240Mo... mais je viens juste de le relancer et je n'ai que 2 onglets ouverts dessus&lt;/li&gt;
&lt;li&gt;VirtueDesktop (gestionnaire de bureaux virtuels) 27Mo/247Mo&lt;/li&gt;
&lt;li&gt;GeekTool (un petit outil qui permet de plaquer des logs/images... sur le bureau) 26Mo/230Mo&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Bon, là où ce n'est pas drôle je viens de relancer Safari et GeekTool. A la rigueur, à part GeekTool qui n'a absolument rien à faire dans le top8, le classement n'est pas très surprenant. Là où il y a un problème c'est quand on regarde la sortie de &lt;code&gt;leaks&lt;/code&gt;. Pour ceux qui ne peuvent pas tester, ça ressemble à ça&amp;nbsp;:&lt;/p&gt;

&lt;pre&gt;
Leak: 0x0066abd0  size=16       string ''
Leak: 0x006e1680  size=16       string ''
Leak: 0x0d5f8cf0  size=16       instance of 'NSCFString'
        0xa080c260 0x0001078c 0x74737504 0x4346006c     `........ustl.FC
Leak: 0x0d590470  size=16
        0x00000000 0x00000000 0x00000000 0x00010001     ................
...
&lt;/pre&gt;


&lt;p&gt;Donc, comme je ne vais pas lire toute la sortie, je vais faire &lt;code&gt;leaks &lt;a href=&quot;http://blog.mymind.fr/post/2007/04/04/programme&quot; title=&quot;programme&quot;&gt;programme&lt;/a&gt; | grep Leak | wc -l&lt;/code&gt; sur les programmes qui tournent sur mon Mac ce qui donnera le nombre de trous de mémoire. Tout d'abord commençons par ceux que je viens de relancer (GeekTool et Safari)&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GeekTool&amp;nbsp;: 1632 leaks dont la taille varie de 16 à 1024 octets&lt;/li&gt;
&lt;li&gt;Safari&amp;nbsp;: 6 leaks dont la taille varie également de 16 à 1024 octets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Puisque Colloquy est en tête du top des programmes qui utilisent le plus de mémoire... un petit test s'impose&amp;nbsp;: 15212 leaks (je l'ai relancé il y a 24 heures). Le temps de faire ce test je revérifie GeekTool qui lui même est passé à 1747 leaks (juste pendant le temps que j'ai pris pour écrire ces quelques lignes).&lt;/p&gt;


&lt;p&gt;Pour me rassuré je décide de tester sur différents autres programmes&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;WindowServer (le serveur graphique de Mac OS)&amp;nbsp;: 360 leaks&lt;/li&gt;
&lt;li&gt;Address Book&amp;nbsp;: 1460 leaks (bon, il a 11 jours d'uptime aussi, c'est pas rien)&lt;/li&gt;
&lt;li&gt;Terminal&amp;nbsp;: 0 (mais je viens de le relancer... il a planté alors que je lançais &lt;code&gt;leaks&lt;/code&gt; sur &lt;code&gt;Terminal&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Finder&amp;nbsp;: 334&lt;/li&gt;
&lt;li&gt;Mail&amp;nbsp;: 321&lt;/li&gt;
&lt;li&gt;Dock&amp;nbsp;: 15&lt;/li&gt;
&lt;li&gt;GeekTool&amp;nbsp;: 1995 (et oui, ça a encore augmenté)&lt;/li&gt;
&lt;li&gt;ssh&amp;nbsp;: 6&amp;nbsp;!&lt;/li&gt;
&lt;li&gt;Vienna&amp;nbsp;: 10824 (il a 24 heures d'uptime)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Je me décide à lancer Firefox, juste pour voir... juste après le lancement, Firefox est déjà à 1580 memory leaks... bon, peut-être que Camino est plus léger, c'est vrai qu'avec ses 236 leaks, il fait bonne figure.&lt;/p&gt;


&lt;p&gt;Pour résumer&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Les programmes Apple sont peut troués (la plupart de ceux que j'ai cité ci-dessus ont un uptime comparable à celui de ma machine, c'est à dire 11 jours... 300 trous de mémoire en 11 jours, ce n'est pas miraculeux, mais c'est &lt;em&gt;tolérable&lt;/em&gt;).&lt;/li&gt;
&lt;li&gt;Les programmes de tierce partie sont des monstres. Comment un navigateur comme Firefox qui cherche à s'imposer comme une référence peut-il se permettre d'avoir déjà perdu 1580 zones mémoires en 5 secondes de fonctionnement&amp;nbsp;? Comment un outil qui ne fait rien comme GeekTool peut-il prendre plus de mémoire que Safari (il vient juste de le dépasser dans mon moniteur d'activité) et perdre plusieurs centaines de zones mémoire par minute&amp;nbsp;?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Quand on développe un programme, la gestion de la mémoire est une priorité... et ce, quel que soit le langage qu'on utilise. Je n'ai pas envie d'acheter 1Go de RAM supplémentaire alors que tous les programmes que j'utilise devrait rentrer dans 512Mo de RAM, mais malheureusement, comme les programmeurs semblent avoir oublié qu'un programme ce n'est pas que un tas de fonctionnalités mises bout à bout, ma machine rame de telle sorte que parfois il faut plusieurs secondes pour passer d'un programme à l'autre.&lt;/p&gt;


&lt;p&gt;Je me demandais pourquoi Apple avait mis en place un GC pour l'objective-C dans le prochain MacOS, au moins maintenant je suis fixé&amp;nbsp;: ça permettra aux programmes faits par des personnes qui ne savent pas coder de ne pas pourrir ma machine. Heureusement que les gens qui savent programmer se mettent au service de ceux qui ne le savent pas pour faire des outils qui transforment les mauvais programme en programme correct.&lt;/p&gt;


&lt;p&gt;Désolé d'être aussi méchant, mais ça m'énerve (tiens GeekTool prend encore 2Mo de RAM supplémentaires&lt;sup&gt;[&lt;a href=&quot;http://blog.mymind.fr/post/2007/04/04/Trous-de-memoire#pnote-19-1&quot; id=&quot;rev-pnote-19-1&quot;&gt;1&lt;/a&gt;]&lt;/sup&gt;&lt;sup&gt;[&lt;a href=&quot;http://blog.mymind.fr/post/2007/04/04/Trous-de-memoire#pnote-19-2&quot; id=&quot;rev-pnote-19-2&quot;&gt;2&lt;/a&gt;]&lt;/sup&gt;&lt;sup&gt;[&lt;a href=&quot;http://blog.mymind.fr/post/2007/04/04/Trous-de-memoire#pnote-19-3&quot; id=&quot;rev-pnote-19-3&quot;&gt;3&lt;/a&gt;]&lt;/sup&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/04/04/Trous-de-memoire#rev-pnote-19-1&quot; id=&quot;pnote-19-1&quot;&gt;1&lt;/a&gt;] Le temps de relire, GeekTool et Safari ont supplanté Vienna au top8, GeekTool est passé à 7135 leaks !!!, Colloquy est passé à 15318 et Safari reste à 6&lt;/p&gt;
&lt;p&gt;[&lt;a href=&quot;http://blog.mymind.fr/post/2007/04/04/Trous-de-memoire#rev-pnote-19-2&quot; id=&quot;pnote-19-2&quot;&gt;2&lt;/a&gt;] Après une bonne nuit de sommeil le classement a changé : GeekTool est désormais entre le noyau et le serveur graphique avec plus de 36222 leaks et 106Mo de mémoire utilisés, Vienna est passé à 11400 leaks, Colloquy à 16300 et Safari à 111&lt;/p&gt;
&lt;p&gt;[&lt;a href=&quot;http://blog.mymind.fr/post/2007/04/04/Trous-de-memoire#rev-pnote-19-3&quot; id=&quot;pnote-19-3&quot;&gt;3&lt;/a&gt;] Avec 24h d'uptime, Safari et GeekTool tiennent la tête du classement avec respectivement 117 et 114Mo de RAM utilisée. 683 leaks pour Safari et 43479 leaks pour GeekTool. Colloquy est monté à 18110 leaks et Vienna à 14902&lt;/p&gt;&lt;/div&gt;
</description>
    
    
    
          <comments>http://blog.mymind.fr/post/2007/04/04/Trous-de-memoire#comment-form</comments>
      <wfw:comment>http://blog.mymind.fr/post/2007/04/04/Trous-de-memoire#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.mymind.fr/feed/atom/comments/19</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>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>Pourquoi ?</title>
    <link>http://blog.mymind.fr/post/2007/03/07/Pourquoi</link>
    <guid isPermaLink="false">urn:md5:d393e9996bfb832f6a93493ea0a6f022</guid>
    <pubDate>Wed, 07 Mar 2007 14:05:00 +0100</pubDate>
    <dc:creator>Florent Bruneau</dc:creator>
        <category>GeekTime</category>
            
    <description>&lt;p&gt;Pourquoi est-ce que les utilisateurs se sentent obligés de laisser des commentaires sur les articles qu'ils lisent dès que c'est possible&amp;nbsp;? Dans certains cas, ces commentaires sont intéressants, mais dans 95% des cas, c'est uniquement du &quot;Kikoo lol asv mdr :) :) :) ;) ;)&quot;... &lt;strong&gt;insupportable !&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;Le problème c'est que ça ne concerne pas uniquement les Skyblog... mais également les sites d'informations (même les sites plutôt sérieux), les sites de documentation (comme celui de PHP par exemple)...&lt;/p&gt;


&lt;p&gt;Par exemple, pourquoi un gars poste-t-il un algorithme pour remplacer &lt;code&gt;str_repeat&lt;/code&gt; sur php.net&amp;nbsp;:&lt;/p&gt;
&lt;pre&gt;
[php]
&amp;lt;?php
if(!function_exists(&amp;quot;str_repeat&amp;quot;)) {
    function str_repeat($word, $length) {
        $repeated = &amp;quot;&amp;quot;;
        for($i=0; $i &amp;lt; $length; $i++) {
            $repeated .= $word;
        }
        return $repeated;
    }
}
?&amp;gt;
&lt;/pre&gt;


&lt;p&gt;Non seulement, j'espère que les utilisateurs qui n'ont pas la fonction en question (PHP &amp;lt; 4) sauront d'eux-même reproduire cette algorithme sans avoir à le recopier (sans quoi on peut se demander pourquoi ils utilisent PHP vu qu'ils ne savent tout bonnement pas programmer un algorithme trivial)... mais en plus cet algorithme est absolument sous-optimal (à chaque tour de boucle il faut réallouer le buffer stockant &lt;code&gt;$repeated&lt;/code&gt; et le recopier...) et il n'y a donc pas de quoi être fier d'avoir écrit cette fonction.&lt;/p&gt;


&lt;p&gt;Pourquoi à la suite d'un article indiquant de l'arrivée prochaine du SATA 2.6, quelqu'un vient poster (et uniquement ce texte)&amp;nbsp;:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Vite vite dépecher vous&lt;/p&gt;&lt;/blockquote&gt;


&lt;p&gt;Quel est l'intérêt de ce commentaire ?&lt;br /&gt;
Le pire est que pour trouver cet exemple j'ai choisi au hasard un article sur &lt;a href=&quot;http://www.clubic.com&quot;&gt;Clublic&lt;/a&gt; et que le commentaire que j'ai pris était le premier sur cet article... Bon effectivement vu qu'il ne doit pas y avoir plus d'un commentaire intéressant par jour sur Clubic, c'était facile d'en trouver un inintéressant.&lt;/p&gt;


&lt;p&gt;Et je ne parle pas des commentaires sur les articles d'actualité en référence avec la campagne électorale en cours...&lt;/p&gt;


&lt;p&gt;Donc, si c'est possible&amp;nbsp;: avant d'ajouter un commentaire sur Internet, réfléchissez pour savoir si ça vaut &lt;em&gt;vraiment&lt;/em&gt; le coup, ça permettrait au moins à ceux qui cherchent vraiment des informations de ne pas avoir à lire 90% de texte inintéressant avant de trouver &lt;strong&gt;le&lt;/strong&gt; commentaire intéressant de la page de doc de php.net (par exemple).&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.mymind.fr/post/2007/03/07/Pourquoi#comment-form</comments>
      <wfw:comment>http://blog.mymind.fr/post/2007/03/07/Pourquoi#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.mymind.fr/feed/atom/comments/8</wfw:commentRss>
      </item>
    
</channel>
</rss>
