<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet title="XSL formatting" type="text/xsl" href="http://blog.nicoleau-fabien.net/index.php?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>eponyme's blog : linux, dev &amp; cie</title>
  <link>http://blog.nicoleau-fabien.net/index.php?</link>
  <atom:link href="http://blog.nicoleau-fabien.net/index.php?feed/rss2" rel="self" type="application/rss+xml"/>
  <description></description>
  <language>fr</language>
  <pubDate>Sat, 17 Mar 2012 11:02:27 +0100</pubDate>
  <copyright></copyright>
  <docs>http://blogs.law.harvard.edu/tech/rss</docs>
  <generator>Dotclear</generator>
  
    
  <item>
    <title>fail2ban : punir les récidivistes</title>
    <link>http://blog.nicoleau-fabien.net/index.php?post/2011/10/14/fail2ban-%3A-punir-les-r%C3%A9cidivistes</link>
    <guid isPermaLink="false">urn:md5:0ae6e013d4163db2bf77ffd9a848eebe</guid>
    <pubDate>Fri, 14 Oct 2011 00:08:00 +0200</pubDate>
    <dc:creator>Fabien Nicoleau</dc:creator>
        <category>Linux</category>
        <category>fail2ban</category>    
    <description>&lt;p&gt;&lt;a hreflang=&quot;en&quot; href=&quot;http://www.fail2ban.org/wiki/index.php/Main_Page&quot;&gt;Fail2ban&lt;/a&gt; permet de bannir des adresses IP tentant de s'attaquer à
votre système. Elles sont repérées grâce aux fichiers de log des
différents services. &lt;em&gt;Fail2ban&lt;/em&gt; les consulte et agit en fonction des
expressions régulières qui lui sont données, et d'une tolérance
d'erreurs donnée.&lt;/p&gt;
&lt;p&gt;Les &quot;bans&quot; ont une durée, mais parfois on se rend compte qu'aussitôt
son ban terminé, une adresse tente de nouveau de s'attaquer au système.
Une solution simple peut être de mettre une rêgle permanante avec &lt;em&gt;
iptables&lt;/em&gt;, ce qui règlera définitivement le problème. Cependant cette
solution ne me convient pas totalement car je n'aime pas le fait
d'ajouter des règles à iptables qui ne seront peut être pas toujours
utiles (l'attaquant peut s'arrêter, ou son adresse peut changer). De
plus, j'aime assez l'idée qu'un serveur puisse être un minimum autonome.
Si je ne consulte pas les logs de mon serveur pendant 1 mois et que je
ne me rend pas compte qu'une adresse m'attaque à longueur de journée, mon serveur risque d'être en danger.&lt;/p&gt;
&lt;p&gt;Pour régler ce problème, il suffit de créer un &lt;em&gt;jail&lt;/em&gt; dans &lt;em&gt;fail2ban&lt;/em&gt; qui
scrutera son propre log. Ainsi il sera possible de bannir pour une très
longue durée une IP qui déjà été bannie plusieurs fois. Cette technique
est expliquée &lt;a hreflang=&quot;en&quot; href=&quot;http://whyscream.net/wiki/index.php/Fail2ban_monitoring_Fail2ban&quot;&gt;dans un article en anglais&lt;/a&gt;, je propose ici une
explication en&amp;nbsp; français.&lt;/p&gt;    &lt;p&gt;La première chose à faire est de créer un filtre, qu'on placera dans &lt;em&gt;/etc/fail2ban/filter.d/fail2ban-recidivist.conf&lt;/em&gt; . En voici le contenu :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;[Definition]&lt;br /&gt;failregex = fail2ban.actions: WARNING \[(.*)\] Ban &amp;lt;HOST&amp;gt;&lt;br /&gt;ignoreregex = fail2ban.actions: WARNING \[fail2ban-recidivist\] Ban &amp;lt;HOST&amp;gt;&lt;/p&gt;
&lt;p&gt;La ligne du &lt;em&gt;failregex&lt;/em&gt; indique la &lt;em&gt;regex&lt;/em&gt; qui permettra de repérer les lignes de ban dans le fichier de log de &lt;em&gt;fail2ban&lt;/em&gt;. La dernière ligne permet d'ignorer les bans ajoutés par notre nouvelle règle. Cela évitera de les comptabiliser et donc de fausser le nombre de bans à prendre en compte pour une IP. Notez ici que nous ignorons les bans pour le jail &lt;strong&gt;fail2ban-recidivist&lt;/strong&gt;. Si vous changez le nom du &lt;em&gt;jail&lt;/em&gt;, pensez aussi à modifier le filtre pour que l'&lt;em&gt;ignoreregex&lt;/em&gt; soit correcte.&lt;/p&gt;
&lt;p&gt;Il faut ensuite ajouter un &lt;em&gt;jail&lt;/em&gt; dans le fichier &lt;em&gt;/etc/fail2ban/jail.conf&lt;/em&gt;, dont voici la définition :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;[fail2ban-recidivist]&lt;br /&gt;enabled&amp;nbsp; = true&lt;br /&gt;filter&amp;nbsp;&amp;nbsp; = fail2ban-recidivist&lt;br /&gt;action&amp;nbsp;&amp;nbsp; = iptables-allports[name=recidivist]&lt;br /&gt;logpath&amp;nbsp; = /var/log/messages&lt;br /&gt;maxretry = 5&lt;br /&gt;# 1 semaine&lt;br /&gt;findtime = 604800&lt;br /&gt;# 1 semaine&lt;br /&gt;bantime&amp;nbsp; = 604800&lt;/p&gt;
&lt;p&gt;Comme pour les autres jails, on indique ici le nom du filtre utilisé (et dont nous avons donné la définition précédemment), l'action à effectuer (je choisis ici de bannir sur tous les ports l'attaquant, et de passer le nom &quot;recidivist&quot; à iptables pour la règle. Il serait aussi possible, voir même judicieux, d'envoyer un e-mail pour vous prévenir de ce ban particulier grâce à l'action &lt;em&gt;sendmail-whois&lt;/em&gt;), le fichier de log à scruter, qui est pour ce &lt;em&gt;jail&lt;/em&gt; celui de &lt;em&gt;fail2ban&lt;/em&gt; (qui utilise &lt;strong&gt;SYSLOG&lt;/strong&gt; dans mon cas), le nombre de tentatives infructueuses, la plage de temps sur laquelle on fait le décompte, et enfin le temps de banissement.&lt;/p&gt;
&lt;p&gt;Pour ce cas précis, je bannis pendant une semaine une personne qui a déja été bannie 5 fois durant la dernière semaine par d'autres règles. Sachant que chaque règle a elle aussi un nombre de tentatives d'essais (3 par défaut), cela donne tout de même une bonne tolérance.&lt;/p&gt;
&lt;p&gt;Il faut noter que si vous utilisez une action qui ne prend pas en compte de nom (ici &lt;strong&gt;recidivist&lt;/strong&gt;), et qui enregistre simplement l'adresse IP, ce système ne fonctionnera pas. En effet, si une personne est bannie parce qu'elle a essayé de s'authentifier sans succès plusieurs fois, pour une durée d'un jour, et qu'ensuite ce &lt;em&gt;jail&lt;/em&gt; bannit l'IP pour une semaine, au bout d'une journée, le premier ban sera retiré, l'IP donc retirée, et le ban d'une semaine annulé. Ce problème n'apparait pas avec &lt;em&gt;iptables&lt;/em&gt; car il prend en compte le nom de l'action, et ne confond donc pas les bans. En revanche, cela semble pouvoir se produire avec &lt;em&gt;ipfw&lt;/em&gt;, &lt;em&gt;hostsdeny&lt;/em&gt; et &lt;em&gt;shorewall&lt;/em&gt;. &lt;/p&gt;
&lt;p&gt;Voilà grâce à cette règle un serveur un peu plus autonome, qui sévira de façon plus dure s'il est attaqué trop souvent par la même personne.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;Fabien (eponyme)&lt;/p&gt;</description>
    
    
    
      </item>
    
  <item>
    <title>fail2ban : classement des IP les plus bannies</title>
    <link>http://blog.nicoleau-fabien.net/index.php?post/2011/10/08/fail2ban-%3A-classement-des-IP-les-plus-bannies</link>
    <guid isPermaLink="false">urn:md5:acaf049988ca68804dc8e51d740cf841</guid>
    <pubDate>Sat, 08 Oct 2011 19:22:00 +0200</pubDate>
    <dc:creator>Fabien Nicoleau</dc:creator>
        <category>Linux</category>
        <category>fail2ban</category>    
    <description>    &lt;p&gt;J'utilise depuis très longtemps &lt;a hreflang=&quot;en&quot; href=&quot;http://www.fail2ban.org/wiki/index.php/Main_Page&quot;&gt;fail2ban&lt;/a&gt;, qui permet de bannir des IP générant trop d'erreurs (le plus souvent des échecs d'authentification). Il se base sur les &lt;em&gt;logs&lt;/em&gt; des différents services et des expressions régulières pour retrouver les tentatives et les bannir.&lt;/p&gt;
&lt;p&gt;Je m'y suis un peu plus intéressé ces derniers temps car j'ai été attaqué par des scripts vraiment insistants (ce sera l'objet d'un prochain billet). Dans un premier temps, j'ai voulu obtenir une liste des adresses bannies, avec le nombre de fois, afin de déceler des &quot;récidivistes&quot;. Voici la commande utilisée (fail2ban log avec SYSLOG sur mon serveur) :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;cat /var/log/messages|grep Ban|awk '{print $7&quot; &quot;$9}'|sort|uniq -c|sort -r&lt;/p&gt;
&lt;p&gt;Voici l'explication de la commande :&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;cat : affichage du fichier de log&lt;/li&gt;
&lt;li&gt;grep Ban : on ne conserve que les lignes concernant un bannissement&lt;/li&gt;
&lt;li&gt;awk : on extrait simplement les 7ème et 9ème parties, c'est à dire le &quot;jail&quot; utilisé pour le ban, et l'IP bannie&lt;/li&gt;
&lt;li&gt;un premier sort pour faire en sorte que les IP identiques soient listées les unes en dessous des autres&lt;/li&gt;
&lt;li&gt;uniq -q : réunies les lignes communes et affiche devant le nombre de fois qu'elles apparaissent&lt;/li&gt;
&lt;li&gt;un dernier sort (avec l'option reverse) pour faire un tri inverse&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On se retrouve ainsi avec une liste indiquant le nombre de fois qu'a été bannie une IP, le jail utilisé et l'IP bannie, le tout dans l'ordre décroisant. Voici un exemple :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 8 [ssh-iptables] 188.138.98.75&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2 [apache-dfind] 93.174.2.202&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2 [apache-dfind] 81.196.179.210&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2 [apache-dfind] 217.70.51.154&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1 [ssh-iptables] 96.8.121.185&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1 [ssh-iptables] 87.106.132.104&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1 [ssh-iptables] 58.211.5.130&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1 [ssh-iptables] 221.207.229.6&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1 [ssh-iptables] 201.140.103.17&lt;/p&gt;
&lt;p&gt;Le défaut de cette commande est que l'odre est faire sur du texte, et donc si une IP est bannie plus de 9 fois, elle apparaitra en bas, au lieu d'être en haut.&lt;/p&gt;
&lt;p&gt;Cela permet cependant de repérer rapidement une IP trop &quot;agressive&quot; pour la bannir définitivement par exemple.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;Fabien (eponyme)&lt;/p&gt;</description>
    
    
    
      </item>
    
  <item>
    <title>Mise à jour de quvi pour rawhide : éclatement des paquets</title>
    <link>http://blog.nicoleau-fabien.net/index.php?post/2011/10/08/Mise-%C3%A0-jour-de-quvi-pour-rawhide-%3A-%C3%A9clatement-des-paquets</link>
    <guid isPermaLink="false">urn:md5:1e639f07671d1a2e8b0a98bfa55f8052</guid>
    <pubDate>Sat, 08 Oct 2011 19:00:00 +0200</pubDate>
    <dc:creator>Fabien Nicoleau</dc:creator>
        <category>Linux</category>
        <category>fedora</category><category>libquvi</category><category>libquvi-scripts</category><category>quvi</category><category>RPM</category>    
    <description>    &lt;p&gt;Je &lt;em&gt;paquage&lt;/em&gt; le logiciel &quot;&lt;em&gt;quvi&lt;/em&gt;&quot; pour &lt;strong&gt;Fedora&lt;/strong&gt;. Ce logiciel fournit une bibliothèque (&lt;em&gt;libquvi&lt;/em&gt;) permettant de &lt;em&gt;parser&lt;/em&gt; les vidéos des sites tels que &lt;em&gt;youtube&lt;/em&gt; ou &lt;em&gt;dailymotion&lt;/em&gt; (et beaucoup d'autres) ainsi qu'un outil (&lt;em&gt;quvi&lt;/em&gt;) utilisant &lt;em&gt;libquvi&lt;/em&gt; pour parser les vidéos. La dernière version, la 0.4.0, est maintenant divisée en 3 sources : &lt;em&gt;libquvi&lt;/em&gt; (la bibliothèque), &lt;em&gt;libquvi-scripts&lt;/em&gt; (les scripts lua utilisés par &lt;em&gt;libquvi&lt;/em&gt; permettant de parser les sites) et &lt;em&gt;quvi&lt;/em&gt;, l'utilitaire. &lt;/p&gt;
&lt;p&gt;J'ai donc aujourd'hui fait les demandes de revue pour les paquets &lt;em&gt;libquvi&lt;/em&gt; et&lt;em&gt; libquvi-scripts&lt;/em&gt;. Je mettrai à jour &lt;em&gt;quvi&lt;/em&gt; quand les deux dépendances auront été importées dans les dépôts:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;&lt;a class=&quot;moz-txt-link-freetext&quot; href=&quot;https://bugzilla.redhat.com/show_bug.cgi?id=744430&quot;&gt;https://bugzilla.redhat.com/show_bug.cgi?id=744430&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;moz-txt-link-freetext&quot; href=&quot;https://bugzilla.redhat.com/show_bug.cgi?id=744433&quot;&gt;https://bugzilla.redhat.com/show_bug.cgi?id=744433&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ces changements sont importants et ne seront donc effectués que dans &lt;em&gt;rawhide&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;Fabien (eponyme)&lt;/p&gt;</description>
    
    
    
      </item>
    
  <item>
    <title>NomNom présent dans les dépôts !</title>
    <link>http://blog.nicoleau-fabien.net/index.php?post/2011/09/19/NomNom-pr%C3%A9sent-dans-les-d%C3%A9p%C3%B4ts-%21</link>
    <guid isPermaLink="false">urn:md5:ae85576bde12645f645fb82de479410d</guid>
    <pubDate>Mon, 19 Sep 2011 22:40:00 +0200</pubDate>
    <dc:creator>Fabien Nicoleau</dc:creator>
        <category>Linux</category>
        <category>abby</category><category>cclive</category><category>clive</category><category>fedora</category><category>nomnom</category><category>RPM</category><category>umph</category>    
    <description>    &lt;p&gt;&lt;a hreflang=&quot;en&quot; href=&quot;http://clive.sourceforge.net/&quot;&gt;clive&lt;/a&gt; et &lt;a hreflang=&quot;en&quot; href=&quot;http://cclive.sourceforge.net/&quot;&gt;cclive&lt;/a&gt; sont deux logiciels (du même &lt;a hreflang=&quot;en&quot; href=&quot;http://sourceforge.net/users/legatvs&quot;&gt;auteur&lt;/a&gt;) permettant de récupérer les vidéos de sites tels que &lt;em&gt;youtube&lt;/em&gt; ou &lt;em&gt;dailymotion&lt;/em&gt; (et beaucoup d'autres !). Il existait auparavant un &quot;frontend&quot; à ces utilitaires, toujours du même auteur : &lt;a hreflang=&quot;en&quot; href=&quot;http://code.google.com/p/abby/&quot;&gt;abby&lt;/a&gt;. Ce dernier a été remplacé par &lt;a hreflang=&quot;en&quot; href=&quot;http://nomnom.sourceforge.net/&quot;&gt;NomNom&lt;/a&gt; (encore et toujours du même auteur), et permet de visionner les vidéos directement en &lt;em&gt;streaming&lt;/em&gt;, ou simplement de les télécharger. Il permet aussi de profiter des options de &lt;a hreflang=&quot;en&quot; href=&quot;http://code.google.com/p/umph/&quot;&gt;umph&lt;/a&gt; (dont je vous laisse deviner l'auteur ..) pour télécharger toute une liste de lecture, ou de favoris de &lt;em&gt;YouTube&lt;/em&gt;. &lt;strong&gt;NomNom&lt;/strong&gt; peut être une bonne alternative à ceux ne souhaitant pas utiliser de &lt;em&gt;plugin flash&lt;/em&gt; avec leur navigateur.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;umph&lt;/strong&gt; et &lt;strong&gt;NomNom&lt;/strong&gt; n'étaient pas présents dans les dépôts. Je les ai donc &lt;em&gt;packagés&lt;/em&gt; et&amp;nbsp; proposés. Ces deux paquets ont été acceptés et sont maintenant disponnibles dans les dépôts de &lt;strong&gt;Fedora&lt;/strong&gt;, à partir de la version &lt;strong&gt;15&lt;/strong&gt;. Pour installer &lt;strong&gt;NomNom&lt;/strong&gt;, en root :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;# yum install nomnom&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;Fabien (eponyme)&lt;/p&gt;</description>
    
    
    
      </item>
    
  <item>
    <title>Orphan de certains de mes paquets</title>
    <link>http://blog.nicoleau-fabien.net/index.php?post/2011/09/19/Orphan-de-certains-de-mes-paquets</link>
    <guid isPermaLink="false">urn:md5:613bcd3f44f10171d48e3d5415bffa82</guid>
    <pubDate>Mon, 19 Sep 2011 22:21:00 +0200</pubDate>
    <dc:creator>Fabien Nicoleau</dc:creator>
        <category>Linux</category>
        <category>abby</category><category>gestikk</category><category>immix</category><category>itaka</category><category>perl-WWW-Curl</category><category>RPM</category><category>trustyRC</category><category>vbindiff</category><category>xcftools</category>    
    <description>    &lt;p&gt;Bonjour,&lt;/p&gt;
&lt;p&gt;En raison de manque de temps, et souhaitant me concentrer sur les paquets que j'utilise avec Fedora, j'ai pris la décision &quot;d'orphan&quot; 6 des paquets que je maintiens dans les dépôts :&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;&lt;a hreflang=&quot;en&quot; href=&quot;https://admin.fedoraproject.org/pkgdb/acls/name/gestikk&quot;&gt;gestikk&lt;/a&gt; : permet de lancer des logiciels avec un simple mouvement de souris&lt;/li&gt;
&lt;li&gt;&lt;a hreflang=&quot;en&quot; href=&quot;https://admin.fedoraproject.org/pkgdb/acls/name/immix&quot;&gt;immix&lt;/a&gt; : mixage de photos&lt;/li&gt;
&lt;li&gt;&lt;a hreflang=&quot;en&quot; href=&quot;https://admin.fedoraproject.org/pkgdb/acls/name/itaka&quot;&gt;itaka&lt;/a&gt; : serveur de capture d'écran&lt;/li&gt;
&lt;li&gt;&lt;a hreflang=&quot;en&quot; href=&quot;https://admin.fedoraproject.org/pkgdb/acls/name/perl-WWW-Curl&quot;&gt;perl-WWW-Curl&lt;/a&gt; : extension perl pour manipuler libcurl&lt;/li&gt;
&lt;li&gt;&lt;a hreflang=&quot;en&quot; href=&quot;https://admin.fedoraproject.org/pkgdb/acls/name/vbindiff&quot;&gt;vbindiff&lt;/a&gt; : visualiseur de fichiers en hexadécimal, avec prise en charge de fichiers à forte taille&lt;/li&gt;
&lt;li&gt;&lt;a hreflang=&quot;en&quot; href=&quot;https://admin.fedoraproject.org/pkgdb/acls/name/xcftools&quot;&gt;xcftools&lt;/a&gt; : suite d'utilitaires en ligne de commande permettant de manipuler les fichiers au format XCF&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;J'ai de plus retiré deux paquets :&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;&lt;a hreflang=&quot;en&quot; href=&quot;https://admin.fedoraproject.org/pkgdb/acls/name/abby&quot;&gt;abby&lt;/a&gt; : cette interface graphique à clive et cclive a été remplacée par nomnom, que j'ai ajouté dans les dépôts (j'en parlerai bientôt)&lt;/li&gt;
&lt;li&gt;&lt;a hreflang=&quot;en&quot; href=&quot;https://admin.fedoraproject.org/pkgdb/acls/name/trustyrc&quot;&gt;trustyrc&lt;/a&gt; : mon robot IRC, que je ne maintiens plus&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ceux qui souhaitent maintenir ces paquets pourrons compter sur moi en cas de besoins/questions.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;Fabien (eponyme)&lt;/p&gt;</description>
    
    
    
      </item>
    
  <item>
    <title>Adieu amen, bonjour 1&amp;1 !</title>
    <link>http://blog.nicoleau-fabien.net/index.php?post/2011/08/28/Adieu-amen%2C-boujours-11-%21</link>
    <guid isPermaLink="false">urn:md5:b067cc5a8c984aca54ec6f79383b87a2</guid>
    <pubDate>Mon, 05 Sep 2011 22:10:00 +0200</pubDate>
    <dc:creator>Fabien Nicoleau</dc:creator>
        <category>Général</category>
            
    <description>    &lt;p&gt;Ce blog était hébergé depuis 2 ans chez &lt;a hreflang=&quot;fr&quot; href=&quot;http://amen.fr/&quot;&gt;amen&lt;/a&gt;. Je n'avais pas hésité longtemps à l'époque car c'était les seuls à proposer une config pour 5 euros HT. Evidemment, &quot;on en a pour son argent&quot;, mais ça fonctionnait plutôt bien &lt;a href=&quot;http://blog.nicoleau-fabien.net/index.php?post/2009/05/20/Mon-serveur-priv%C3%A9-virtuel-chez-AMEN&quot;&gt;pour mes faibles besoins&lt;/a&gt;. Cependant au fil du temps, et des mises à jour je suppose, le serveur ne faisait plus l'affaire. Impossible de faire une mise à jour sans planter yum, en manque de RAM. Amen ne proposait plus depuis quelques temps cette config, mais la laissait disponible en renouvellement. Après une réinitialisation du serveur, je me suis retrouvé avec un serveur &quot;nu&quot;, impossible à mettre à jour, et avec un yum inutilisable. Bref, un serveur qui ne sert pas. &lt;/p&gt;
&lt;p&gt;En attendant le remboursement de mon abonnement je me suis mis à la recherche d'un nouveau VPS, pas cher, mais suffisamment robuste tout de même. C'est 1&amp;amp;1 qui propose l'une des &lt;a hreflang=&quot;fr&quot; href=&quot;http://commander.1and1.fr/xml/order/VirtualServerL&quot;&gt;meilleures config pour 12 euros TTC&lt;/a&gt;, prix le plus bas en France pour une config potable. De plus 1&amp;amp;1 a plutôt une bonne réputation, c'est assez rassurant. Je paye le double, certes, mais la config est largement supérieure.&lt;/p&gt;
&lt;p&gt;Voilà donc ce blog reparti, après une semaine offline, hébergé chez 1&amp;amp;1 !&lt;/p&gt;
&lt;p&gt;Fabien (eponyme)&lt;/p&gt;</description>
    
    
    
      </item>
    
  <item>
    <title>Bye bye adSense</title>
    <link>http://blog.nicoleau-fabien.net/index.php?post/2011/07/12/Bye-bye-adSense</link>
    <guid isPermaLink="false">urn:md5:0e98e596335ee53b2ce3d534778f83ab</guid>
    <pubDate>Tue, 12 Jul 2011 20:12:00 +0200</pubDate>
    <dc:creator>Fabien Nicoleau</dc:creator>
        <category>Général</category>
            
    <description>    &lt;p&gt;Beaucoup de place occupée, peu de revenus ... je me suis décidé à retirer les publicités adSense qui se trouvaient sur ce site. Le revoilà vierge de toute propagande (qui n'était pas toujours en armonie avec le but de ce blog) !&amp;nbsp; :D&lt;/p&gt;
&lt;p&gt;Fabien (eponyme)&lt;/p&gt;</description>
    
    
    
      </item>
    
  <item>
    <title>Créer un fichier Excel à partir d'un script</title>
    <link>http://blog.nicoleau-fabien.net/index.php?post/2011/06/09/Cr%C3%A9er-un-fichier-Excel-%C3%A0-partir-d-un-script</link>
    <guid isPermaLink="false">urn:md5:390a9d5a6f9c47e31a7a01ddae59ed3e</guid>
    <pubDate>Thu, 09 Jun 2011 18:47:00 +0200</pubDate>
    <dc:creator>Fabien Nicoleau</dc:creator>
        <category>Développement</category>
            
    <description>    &lt;p&gt;J'ai récemment eu besoin de générer despuis un script un &quot;vrai&quot; fichier Excel. J'entends par &quot;vrai&quot;, un fichier qui ne s'importe pas, mais qui s'ouvre directement et qui puisse contenir de la mise en forme. En recherchant sur internet, j'ai découvert que OpenOffice et Microsoft Excel (et peut-être d'autres tableurs) savent ouvrir un fichier content une description de table au format HTML. En plus, ils savent gérer des styles (de type CSS). Tout est donc imaginable, sauf que se pose le problème récurent des formats de cellule. N'ayant à travailler que pour Excel (on ne choisit pas toujours ses outils!), j'ai trouvé sur internet une solution pour celui-ci. En effet, il prends en compte la directive mso-number-format permettant de définir le format de la cellule. Ce &lt;a hreflang=&quot;en&quot; href=&quot;http://cosicimiento.blogspot.com/2008/11/styling-excel-cells-with-mso-number.html&quot;&gt;billet&lt;/a&gt; indique différents exemples de valeurs possibles pour définir les formats.&lt;/p&gt;
&lt;p&gt;Ainsi j'ai pu, à grand coup de &lt;em&gt;echo &lt;/em&gt;et de &lt;em&gt;redirection de flux&lt;/em&gt;, générer des fichiers Excel avec de bons formats pour les dates, les chiffres, forcer du texte (notamment pour les chaines ne contenant que des chiffres), et ajouter un peu de mise en forme. &lt;/p&gt;
&lt;p&gt;Histoire de servir d'exemple, et pour moi de pense-bête, voici le contenu d'un fichier xls qui peut être généré avec différents exemples de formatage de cellule :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;&amp;lt;style&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; .date {mso-number-format:&quot;dd/mm/yy&quot;}&lt;br /&gt;&amp;nbsp;&amp;nbsp; .txt {mso-number-format:&quot;\@&quot;;}&lt;br /&gt;&amp;nbsp;&amp;nbsp; .gras {font-weight:bold;}&lt;br /&gt;&amp;nbsp;&amp;nbsp; .centreGras {font-weight:bold; text-align:center}&lt;br /&gt;&amp;nbsp;&amp;nbsp; .fondRouge {background-color : red}&lt;br /&gt;&amp;nbsp;&amp;nbsp; .enJaune {color:yellow}&lt;br /&gt;&amp;nbsp;&amp;nbsp; .titreVoyant {background-color:green;color:cyan;font-weight:bold}&lt;br /&gt;&amp;nbsp;&amp;nbsp; .3dec {mso-number-format:&quot;\#\, \#\#0\.000&quot;}&lt;br /&gt;&amp;lt;/style&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;table border=&quot;1&quot;&amp;gt;&lt;br /&gt;&amp;lt;tr&amp;gt;&amp;lt;td class=&quot;txt&quot;&amp;gt;00001&amp;lt;/td&amp;gt;&amp;lt;td class=&quot;gras&quot;&amp;gt;En gras&amp;lt;/td&amp;gt;&amp;lt;td class=&quot;centreGras&quot;&amp;gt;Au centre, en gras&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;00001&amp;lt;/td&amp;gt;&amp;lt;td class=&quot;fondRouge&quot;&amp;gt;fond rouge&amp;lt;/td&amp;gt;&amp;lt;td class=&quot;enJaune&quot;&amp;gt;en jaune&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;&amp;lt;tr&amp;gt;&amp;lt;td class=&quot;titreVoyant&quot;&amp;gt;FLASH !&amp;lt;/td&amp;gt;&amp;lt;td class=&quot;date&quot;&amp;gt;25/01/2011&amp;lt;/td&amp;gt;&amp;lt;td class=&quot;3dec&quot;&amp;gt;10254,25689744541&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;&amp;lt;tr class=&quot;gras&quot;&amp;gt;&amp;lt;td&amp;gt;toute la &amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;ligne &amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;en gras&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;&amp;lt;/table&amp;gt;&lt;/p&gt;
&lt;p&gt;Voici le rendu dans Excel :&lt;/p&gt;
&lt;p&gt;&lt;img title=&quot;excelhtml.JPG, juin 2011&quot; style=&quot;margin: 0 auto; display: block;&quot; alt=&quot;excelhtml.JPG&quot; src=&quot;http://blog.nicoleau-fabien.net/public/excelhtml.JPG&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Notez que les cases A1 et A2 contiennent la même valeur, mais A1 étant formaté en texte, les zéros sont bien affichés. Pour l'instant je n'ai pas réussi à appliquer plusieurs classes à une même cellule, ce qui force à créer des classes spécifiques avec plusieurs mises en forme.&lt;/p&gt;
&lt;p&gt;Voilà donc une solution rapide qui permettra, lorsque le langage de programmation ou de script utilisé ne contient pas de module pour gérer le format xls, de générer des fichiers Excel correctement formatés.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;Fabien (eponyme)&lt;/p&gt;</description>
    
    
    
      </item>
    
  <item>
    <title>GNOME 3 : passer de Gnome-Shell au mode restreint (et inversement) facilement</title>
    <link>http://blog.nicoleau-fabien.net/index.php?post/2011/05/29/GNOME-3-%3A-passer-de-Gnome-Shell-au-mode-restreint-%28et-inversement%29-facilement</link>
    <guid isPermaLink="false">urn:md5:862a67f4dd6e32691fdedef5ebed9671</guid>
    <pubDate>Sun, 29 May 2011 19:02:00 +0200</pubDate>
    <dc:creator>Fabien Nicoleau</dc:creator>
        <category>Linux</category>
        <category>fedora</category><category>gnome</category>    
    <description>    &lt;p&gt;Il est facile, dans la configuration de &lt;a hreflang=&quot;en&quot; href=&quot;http://gnome3.org/&quot;&gt;GNOME 3&lt;/a&gt;, de forcer le mode restreint. Il suffit d'aller dans les paramètres système, Informations système, carte graphique, et d'activer le &quot;Mode restreint forcé&quot;. Il faut ensuite relancer sa session &lt;strong&gt;GNOME&lt;/strong&gt;. C'est cette dernière étape qui me pose soucis. En effet j'ai besoin de passer en mode restreint pour pouvoir jouer confortablement aux jeux en 3D, et il devient vite contraignant de devoir relancer ma session juste pour une partie. &lt;/p&gt;
&lt;p&gt;Pour contourner ce problème, j'ai créé un petit script qui permet de passer de Gnome-Shell au mode restreint, sans redémarrer sa session, et évidemment de passer du mode restreint à &lt;a hreflang=&quot;en&quot; href=&quot;http://live.gnome.org/GnomeShell&quot;&gt;Gnome-Shell&lt;/a&gt;. Le seul prérequis pour que cela fonctionne est de désactiver l'option &quot;AutoRestart&quot; de &lt;strong&gt;Gnome-Shell&lt;/strong&gt;, sinon, il essaiera de se relancer par dessus &lt;strong&gt;gnome-panel&lt;/strong&gt; ...&lt;/p&gt;
&lt;p&gt;Pour que cette modification n'affecte que ma session, j'ai importé dans mon compte le fichier de lancement de &lt;strong&gt;Gnome-Shell&lt;/strong&gt; :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;$ cp /usr/share/applications/gnome-shell.desktop ~/.config/autostart/&lt;/p&gt;
&lt;p&gt;On désactive ensutie l'&lt;em&gt;AutoRestart&lt;/em&gt; :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;$ sed -i -e 's/AutoRestart=true/AutoRestart=false/' ~/.config/autostart/gnome-shell.desktop&lt;/p&gt;
&lt;p&gt;Il faut maintenant redémarrer votre session &lt;strong&gt;GNOME&lt;/strong&gt; pour que cette option soit prise en compte. Une fois votre session réouverte, vous pouvez utiliser ce script (téléchargeable dans les fichiers joints au billet) , que j'ai nommé &lt;em&gt;gnome-mode.sh&lt;/em&gt; :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;#!/bin/sh&lt;br /&gt;case $1 in&lt;br /&gt;&amp;nbsp;&amp;nbsp; &quot;panel&quot;|0)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; gnome-panel --replace &amp;amp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; killall gnome-shell&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; metacity --replace &amp;amp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; break&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ;;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &quot;shell&quot;|1)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; gnome-shell --replace &amp;amp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; break&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ;;&lt;br /&gt;&amp;nbsp;&amp;nbsp; *)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; echo &quot;usage : $0 panel|shell&quot;&lt;br /&gt;esac&lt;/p&gt;
&lt;p&gt;Il est assez simple. Lorsque vous utilisez &lt;strong&gt;Gnome-Shell&lt;/strong&gt;, pour passer en mode restreint (avec &lt;strong&gt;gnome-panel)&lt;/strong&gt; :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;$ ./gnome-mode.sh panel&lt;/p&gt;
&lt;p&gt;Notez que l'on peut utiliser &lt;strong&gt;0&lt;/strong&gt; au lieu de &lt;strong&gt;panel&lt;/strong&gt; comme paramètre.&lt;/p&gt;
&lt;p&gt;Lorsque vous êtes en mode restreint, pour réactiver &lt;strong&gt;Gnome-Shell&lt;/strong&gt; :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;$ ./gnome-mode.sh shell&lt;/p&gt;
&lt;p&gt;Notez que l'on peut utiliser &lt;strong&gt;1&lt;/strong&gt; au lieu de &lt;strong&gt;shell&lt;/strong&gt; comme paramètre.&lt;/p&gt;
&lt;p&gt;Voilà, ce petit script vous permettra donc de passer d'un mode à l'autre facilement, quand le besoin s'en fait sentir, pour les jeux par exemple, quand comme moi, votre configuration matériel ne permet pas de faire tourner &lt;strong&gt;Gnome-Shell&lt;/strong&gt; en même temps que des applciations 3D.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;Fabien (eponyme)&lt;/p&gt;</description>
    
          <enclosure url="http://blog.nicoleau-fabien.net/public/gnome-mode.sh"
      length="251" type="text/plain" />
    
    
      </item>
    
  <item>
    <title>umph : récupération de liens à partir de flux Youtube</title>
    <link>http://blog.nicoleau-fabien.net/index.php?post/2011/05/28/umph-%3A-r%C3%A9cup%C3%A9ration-de-liens-%C3%A0-partir-de-flux-Youtube</link>
    <guid isPermaLink="false">urn:md5:6c73b83705007ccf3e3770b3f38ca76c</guid>
    <pubDate>Sat, 28 May 2011 16:51:00 +0200</pubDate>
    <dc:creator>Fabien Nicoleau</dc:creator>
        <category>Linux</category>
        <category>cclive</category><category>clive</category><category>fedora</category><category>nomnom</category><category>RPM</category><category>umph</category>    
    <description>    &lt;p&gt;Il y avait longtemps que je n'avais pas proposé un nouveau paquet au &lt;a hreflang=&quot;fr&quot; href=&quot;http://fedoraproject.org/&quot;&gt;projet Fedora&lt;/a&gt;. Je travaille actuellement sur l'empaquetage de &lt;a hreflang=&quot;en&quot; href=&quot;http://nomnom.sourceforge.net/&quot;&gt;NomNom&lt;/a&gt;, un logiciel permettant de télécharger ou visionner en &lt;em&gt;streaming&lt;/em&gt; des vidéos provennant de sites comme &lt;em&gt;Youtube&lt;/em&gt;, &lt;em&gt;Dailymotion&lt;/em&gt;, et bien d'autres, en utilisant les outils &lt;a hreflang=&quot;en&quot; href=&quot;http://quvi.sourceforge.net/&quot;&gt;quvi&lt;/a&gt; et &lt;a hreflang=&quot;en&quot; href=&quot;http://clive.sourceforge.net/&quot;&gt;clive&lt;/a&gt;/&lt;a hreflang=&quot;en&quot; href=&quot;http://cclive.sourceforge.net/&quot;&gt;cclive&lt;/a&gt; que je package déjà (Pikatchu_2014 a d'ailleurs permit d'allonger la liste des sites supportés en me faisant corriger une option de compilation de &lt;em&gt;quvi&lt;/em&gt; :D ). &lt;em&gt;NomNom&lt;/em&gt; (qui devrait donc succéder à &lt;a hreflang=&quot;en&quot; href=&quot;http://code.google.com/p/abby/&quot;&gt;abby&lt;/a&gt;, projet devenu inactif, mais du même auteur), permet aussi de récupérer des vidéos à partir d'un flux youtube. Pour cela il se repose sur l'outil &lt;a hreflang=&quot;en&quot; href=&quot;http://code.google.com/p/umph/&quot;&gt;umph&lt;/a&gt;, du même auteur, qui permet de récupérer sous différentes formes les informations d'un flux Youtube (voir les exemple sur la page du projet). &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;umph&lt;/strong&gt; n'est donc pas d'une immense utilité en lui même mais devient très pratique lorsqu'il est associé aux autres utilitaires de &quot;&lt;a hreflang=&quot;en&quot; href=&quot;http://code.google.com/u/legatvs/&quot;&gt;legatvs&lt;/a&gt;&quot;, et est naturellement une dépendance pour &lt;strong&gt;NomNom&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;J'ai donc packagé cet utilitaire et en ai &lt;a hreflang=&quot;en&quot; href=&quot;https://bugzilla.redhat.com/show_bug.cgi?id=708554&quot;&gt;proposé la revue&lt;/a&gt;, qui j'espère ne devrait pas poser de problèmes.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;Fabien (eponyme)&lt;/p&gt;</description>
    
    
    
      </item>
    
  <item>
    <title>emesene pour MSN</title>
    <link>http://blog.nicoleau-fabien.net/index.php?post/2011/05/28/emesene-pour-MSN</link>
    <guid isPermaLink="false">urn:md5:5e38d52cdc6de9e17e60033ecb5affb3</guid>
    <pubDate>Sat, 28 May 2011 15:04:00 +0200</pubDate>
    <dc:creator>Fabien Nicoleau</dc:creator>
        <category>Linux</category>
        <category>emesene</category><category>fedora</category>    
    <description>    &lt;p&gt;A chaque nouvelle version de &lt;strong&gt;Fedora&lt;/strong&gt;, j'essaie une alternative à l'un des logiciels que j'utilise quotidiennement, histoire de voir ce qui se fait ailleurs, de changer mes habitudes, de découvrir des fonctionnalités ... C'est d'ailleurs ainsi que j'ai adopté &lt;a hreflang=&quot;en&quot; href=&quot;http://code.google.com/p/quodlibet/&quot;&gt;quodlibet&lt;/a&gt; pour ma musique !&lt;/p&gt;
&lt;p&gt;Pour la version &lt;strong&gt;15&lt;/strong&gt; de &lt;strong&gt;Fedora&lt;/strong&gt;, j'ai décidé d'utiliser &lt;a hreflang=&quot;en&quot; href=&quot;http://blog.emesene.org/&quot;&gt;emesene&lt;/a&gt; en lieu et place d'&lt;a hreflang=&quot;en&quot; href=&quot;http://www.amsn-project.net/&quot;&gt;aMsn&lt;/a&gt;, que j'utilise, je crois, depuis toujours sous linux. Le fait qu'&lt;em&gt;aMsn&lt;/em&gt; ait des petits soucis de systray avec &lt;a hreflang=&quot;en&quot; href=&quot;http://live.gnome.org/GnomeShell&quot;&gt;Gnome-Shell&lt;/a&gt; (cette fois-ci c'est vrai ! :D) aura joué en sa défaveur ! Et puis je n'ai jamai été vraiment fan de l'interface en tk. J'appréciais en fait &lt;em&gt;aMsn&lt;/em&gt; pour les nombreuses fonctionalités qu'il à toujours apporté, souvent en avance sur les autres alternatives.&lt;/p&gt;
&lt;p&gt;J'avais essayé &lt;em&gt;emesene&lt;/em&gt; à ses débuts, et je m'étais dis que je retesterais quand il aurait murit. Je n'ai pas été décu, je le trouve complet, et vais donc l'utiliser avec cette nouvelle &lt;strong&gt;Fedora&lt;/strong&gt; !&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;Fabien (eponyme)&lt;/p&gt;</description>
    
    
    
      </item>
    
  <item>
    <title>Me voilà sous Fedora 15</title>
    <link>http://blog.nicoleau-fabien.net/index.php?post/2011/05/26/Me-voil%C3%A0-sous-Fedora-15</link>
    <guid isPermaLink="false">urn:md5:8bb3de1d13cb84a53a8d5c01640144cb</guid>
    <pubDate>Thu, 26 May 2011 23:32:00 +0200</pubDate>
    <dc:creator>Fabien Nicoleau</dc:creator>
        <category>Linux</category>
        <category>fedora</category><category>gnome</category>    
    <description>    &lt;p&gt;Ces derniers temps, j'étais peu (ou moins) enthousiaste lors des sorties de nouvelles versions de &lt;strong&gt;Fedora&lt;/strong&gt;. J'installais, ça tournait, et puis voilà ... Cette fois-ci les choses sont assez différentes, car parmi les&lt;a hreflang=&quot;fr&quot; href=&quot;http://forums.fedora-fr.org/viewtopic.php?id=52522&quot;&gt; nombreuses nouveautées&lt;/a&gt; se cache une qui va changer mon quotidien : &lt;a hreflang=&quot;en&quot; href=&quot;http://gnome3.org/&quot;&gt;GNOME 3&lt;/a&gt;. Avec les pré-versions de &lt;strong&gt;F15&lt;/strong&gt;, je l'avais testé rapidement, sans vraiment m'y mettre. La, plus le choix ! Et franchement mes craintes se sont vites envolées, je m'y suis habitué en une soirée, et ce grâce à &lt;a hreflang=&quot;fr&quot; href=&quot;http://www.llaumgui.com/&quot;&gt;llaumgui&lt;/a&gt; et &lt;a hreflang=&quot;fr&quot; href=&quot;http://blog.ulysses.fr/&quot;&gt;trashy&lt;/a&gt; qui ont rédigé &lt;a hreflang=&quot;fr&quot; href=&quot;http://doc.fedora-fr.org/wiki/GNOME3&quot;&gt;cette documentation&lt;/a&gt; qui a répondu à beaucoup de mes questions.&lt;/p&gt;
&lt;p&gt;Une autre bonne surprise, pour moi, sera la disparition de &lt;a hreflang=&quot;en&quot; href=&quot;https://bugzilla.redhat.com/show_bug.cgi?id=598686&quot;&gt;ce vieu bogue de son&lt;/a&gt;. Plus besoins de remonter le volume à chaque démarrage, ca sera un petit confort. &lt;/p&gt;
&lt;p&gt;Il me reste encore trois soucis, qui trouveront peut être solution dans les commentaires :&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;De nombreuses applications (xchat, amsn, quodlibet, packagekit) n'ont plus d'icône dans le systray. C'est vraiment gênant et je suis surpris de ne pas trouver d'info la dessus sur le net&lt;/li&gt;
&lt;li&gt;Je ne trouve pas l'endroit ou indiquer les applications que je souhaite lancer au démarrage de gnome, comme conky&lt;/li&gt;
&lt;li&gt;Je n'arrive plus à cacher un utilisateur dans la fenêtre de login, le fichier custom.conf de gdm ne semble plus faire effet&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Il me restera à trouver un jeu d'icones et un nouveau thème pour les fenêtres car je ne suis pas un grand fan de celui par défaut, mais ca n'est pas le plus important pour le moment.&lt;/p&gt;
&lt;p&gt;Il faut noter que &lt;strong&gt;GNOME 3&lt;/strong&gt; n'utilise plus &lt;a hreflang=&quot;en&quot; href=&quot;http://projects.gnome.org/gconf/&quot;&gt;gconf&lt;/a&gt; mais &lt;strong&gt;gsettings&lt;/strong&gt; (avec &lt;strong&gt;dconf-editor&lt;/strong&gt;, son interface graphique). Pour, sous Nautilus, être en mode &quot;saisie de l'emplacement&quot; par défaut, j'ai donc utilisé cette commande :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;$ gsettings set org.gnome.nautilus.preferences always-use-location-entry true&lt;/p&gt;
&lt;p&gt;Et vous, sous Gnome 3, ça va ? :D&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;Fabien (eponyme)&lt;/p&gt;</description>
    
    
    
      </item>
    
  <item>
    <title>QtScript : exemple d'utilisation</title>
    <link>http://blog.nicoleau-fabien.net/index.php?post/2011/03/05/QtScript-%3A-exemple-d-utilisation</link>
    <guid isPermaLink="false">urn:md5:699fad0d263742840522e62caef427f6</guid>
    <pubDate>Sun, 20 Mar 2011 02:12:00 +0100</pubDate>
    <dc:creator>Fabien Nicoleau</dc:creator>
        <category>Développement</category>
        <category>plugins</category><category>Qt</category><category>QtScript</category>    
    <description>&lt;p&gt;J'ai essayé dans &lt;a href=&quot;http://blog.nicoleau-fabien.net/index.php?post/2011/02/23/Premiers-pas-avec-QtScript&quot;&gt;mon billet précédent&lt;/a&gt; de démystifier &lt;strong&gt;QtScript&lt;/strong&gt; et de montrer au travers de différents exemples quelques unes des possibilités offertes par ce module de la bibliothèque &lt;a hreflang=&quot;fr&quot; href=&quot;http://fr.wikipedia.org/wiki/Qt&quot;&gt;Qt&lt;/a&gt;. Après ces premiers pas, je vous propose ici d'utiliser &lt;strong&gt;QtScript&lt;/strong&gt; dans un exemple concret. Il s'agira de créer une calculatrice pour laquelle chaque type d'opération possible sera un &lt;em&gt;plugin&lt;/em&gt; développé en &lt;strong&gt;JavaScript&lt;/strong&gt;. Il sera ainsi possible &quot;d'étendre&quot; cette calculatrice comme bon vous semble en codant de nouveaux types d'opérations. Cependant je m'en tiendrai dans cet exemple aux simples addition, soustraction, multiplication et division. J'ai appelé ce petit projet &lt;strong&gt;QtExCalc&lt;/strong&gt; pour &lt;strong&gt;Qt Ex&lt;/strong&gt;tendable &lt;strong&gt;Calc&lt;/strong&gt;ulator.&lt;/p&gt;    &lt;h2&gt;Le projet&lt;/h2&gt;
&lt;p&gt;Pour commencer, assurez vous que le package &lt;em&gt;qt-devel&lt;/em&gt; est installé sur votre poste. Si ce n'est pas le cas, sous &lt;em&gt;Fedora&lt;/em&gt;, tapez :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;# yum install qt-devel&lt;/p&gt;
&lt;p&gt;Il faudra ensuite télécharger les sources du projet, dont vous trouverez l'archive jointe à ce billet. Une fois cette dernière décompressée, déplacez vous dans le dossier qtexcalc puis tapez :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;$ qmake-qt4&lt;br /&gt;$ make&lt;/p&gt;
&lt;p&gt;Le projet est alors compilé. Vous pouvez l'exécuter :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;$ ./qtexcalc&lt;/p&gt;
&lt;p&gt;L'application se lance :&lt;/p&gt;
&lt;p&gt;&lt;img title=&quot;capture1.jpg, mar. 2011&quot; style=&quot;margin: 0 auto; display: block;&quot; alt=&quot;capture1.jpg&quot; src=&quot;http://blog.nicoleau-fabien.net/public/qtexcalc/capture1.jpg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Elle est très simple. Choisissez un type d'opération proposé dans la liste, saisissez deux nombre, puis cliquez sur le bouton pour afficher le résultat. Tout l'intérêt de ce programme est donc qu'il est modulable, grâce à des scripts &lt;strong&gt;JS&lt;/strong&gt;. A son lancement, elle charge des plugins placés dans le sous-répertoire &lt;em&gt;plugins&lt;/em&gt;. Chaque &lt;em&gt;plugin&lt;/em&gt; fourni trois informations :&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;Le libellé de son opération, qui sera affiché dans la liste (&quot;Addition&quot; par exemple)&lt;/li&gt;
&lt;li&gt;Le signe de son opération, qui sera affiché sur le bouton (&quot;+&quot; par exemple)&lt;/li&gt;
&lt;li&gt;Une procédure de traitement, prenant deux chiffres en paramètre, et renvoyant un résultat. Le traitement effectué est évidemment propre à chaque &lt;em&gt;plugin&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Le code&lt;/h2&gt;
&lt;p&gt;Les sources sont composées d'une classe &lt;em&gt;Dialog&lt;/em&gt; comprennant la fenêtre principale, ainsi que les différents traitements associés aux actions de l'utilisateur, une classe &lt;em&gt;Plugin&lt;/em&gt;, dont chaque instance &quot;représentera&quot; un des &lt;em&gt;plugins&lt;/em&gt;, et qui sera chargée de dialoguer avec. Enfin, un fichier main, simplement chargé de créer la fenêtre principale et de l'afficher. Passons au code.&lt;/p&gt;
&lt;h3&gt;main.cpp&lt;/h3&gt;
&lt;p&gt;C'est le seul fichier dont je copierai intégralement le contenu ici, tant il est petit :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;#include &amp;lt;QtGui/QApplication&amp;gt;&lt;br /&gt;#include &quot;dialog.h&quot;&lt;br /&gt;&lt;br /&gt;int main(int argc, char *argv[])&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; QApplication a(argc, argv);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Dialog w;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; w.show();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return a.exec();&lt;br /&gt;}&lt;/p&gt;
&lt;p&gt;Comme expliqué plus tôt, on se contente ici d'afficher la fenêtre du projet.&lt;/p&gt;
&lt;h3&gt;Classe Plugin&lt;/h3&gt;
&lt;p&gt;Cette classe a en charge de dialoguer avec le &lt;em&gt;plugin&lt;/em&gt;. Elle contient trois méthodes dont voici l'implémentation :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;Plugin::Plugin(QScriptEngine* eng)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; this-&amp;gt;engine = eng;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; this-&amp;gt;sign =this-&amp;gt;engine-&amp;gt;globalObject().property(&quot;getOperationSign&quot;).call(QScriptValue()).toString() ;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;QString Plugin::getSign() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return this-&amp;gt;sign;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;double Plugin::compute(double num1, double num2) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return this-&amp;gt;engine-&amp;gt;globalObject().property(&quot;compute&quot;).call(QScriptValue(),QScriptValueList() &amp;lt;&amp;lt; num1&amp;lt;&amp;lt;num2).toNumber();&lt;br /&gt;}&lt;/p&gt;
&lt;p&gt;Le constructeur prend en paramètre un pointeur sur un moteur de script, qui permettra de dialoguer avec le &lt;em&gt;plugin&lt;/em&gt;, et récupère ensuite le signe de l'opération du plugin en appelant sa fonction &lt;em&gt;getOperationSign()&lt;/em&gt;.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;La méthode &lt;em&gt;getSign()&lt;/em&gt; renvoie le signe de l'opération du &lt;em&gt;plugin&lt;/em&gt; qui a été stocké dans le constructeur.&lt;/p&gt;
&lt;p&gt;Enfin, la méthode &lt;em&gt;compute()&lt;/em&gt; se charge d'effectuer l'opération. Elle attend deux paramètres qui seront passés à la fonction &lt;em&gt;compute()&lt;/em&gt; du plugin. Elle renvoie ensuite le résultat de l'opération.&lt;/p&gt;
&lt;h3&gt;Classe Dialog&lt;/h3&gt;
&lt;p&gt;Voici la principale classe du projet. Je laisse de coté ici tout ce qui concerne la &lt;a hreflang=&quot;en&quot; href=&quot;http://en.wikipedia.org/wiki/Graphical_user_interface&quot;&gt;gui&lt;/a&gt;, pour ne se concentrer que sur &lt;strong&gt;QtScript&lt;/strong&gt;. Commençons par la méthode &lt;em&gt;loadPlugins()&lt;/em&gt; qui est appelée lors de la construction de l'objet et qui permet de &quot;charger&quot; les différents plugins :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;void Dialog::loadPlugins() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; QDir dirPlugins(&quot;plugins&quot;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; QString fName;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; QScriptEngine * engine;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; QComboBox * cbPlugins = this-&amp;gt;ui-&amp;gt;cbChoosePlugin;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; cbPlugins-&amp;gt;addItem(QString::fromUtf8 (&quot;Choisissez une opération ...&quot;),&quot;&quot;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; foreach(fName,dirPlugins.entryList(QStringList() &amp;lt;&amp;lt; &quot;*.qs&quot;)) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; engine = new QScriptEngine();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; QFile file(&quot;plugins/&quot;+fName);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; file.open(QIODevice::ReadOnly);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; engine-&amp;gt;evaluate(file.readAll());&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; file.close();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; cbPlugins-&amp;gt;addItem(engine-&amp;gt;globalObject().property(&quot;getOperationName&quot;).call(QScriptValue()).toString(),fName);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this-&amp;gt;plugins[fName] = new Plugin(engine) ;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;}&lt;/p&gt;
&lt;p&gt;Tous les fichiers dont l'extension est &lt;em&gt;qs&lt;/em&gt; (pour &lt;strong&gt;QtScript&lt;/strong&gt;, mais on peut bien sûr utiliser ce qu'on veut) sont listés grâce à la méthode&lt;a hreflang=&quot;en&quot; href=&quot;http://doc.qt.nokia.com/latest/qdir.html#entryList-2&quot;&gt; entryList()&lt;/a&gt;. Pour chacun des fichiers, on créé un &lt;em&gt;moteur de script&lt;/em&gt; puis on évalue le contenu. Ensuite, on ajoute à la liste (&lt;a hreflang=&quot;en&quot; href=&quot;http://doc.qt.nokia.com/latest/qcombobox.html#addItem&quot;&gt;addItem()&lt;/a&gt;) le nom de l'opération, en appelant la fonction &lt;em&gt;getOperationName&lt;/em&gt; du &lt;em&gt;plugin&lt;/em&gt;, et on donne le nom du fichier (&lt;em&gt;fName&lt;/em&gt;) comme &lt;em&gt;data&lt;/em&gt;. Enfin, on construit un nouvel objet &lt;em&gt;Plugin&lt;/em&gt; auquel on passe en paramètre le moteur et que l'on stocke dans une &lt;a hreflang=&quot;en&quot; href=&quot;http://doc.qt.nokia.com/latest/qmap.html&quot;&gt;QMap&lt;/a&gt;, avec le nom de fichier (&lt;em&gt;fName&lt;/em&gt; toujours) comme clé. Ainsi, lorsqu'une opération sera choisie dans la liste, on récupèrera le &lt;em&gt;data&lt;/em&gt; (correspondant au nom de fichier) grâce auquel on pourra accéder à l'objet correspondant de la &lt;a hreflang=&quot;en&quot; href=&quot;http://doc.qt.nokia.com/latest/qmap.html&quot;&gt;QMap&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Passons maintenant au &lt;a hreflang=&quot;en&quot; href=&quot;http://doc.qt.nokia.com/4.7/signalsandslots.html&quot;&gt;slot&lt;/a&gt; &lt;em&gt;choosedPlugin&lt;/em&gt; appelé à chaque fois que l'on sélectionne un &lt;em&gt;item&lt;/em&gt; dans la liste des opérations :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;void Dialog::choosedPlugin(int index) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if(index&amp;gt;0) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this-&amp;gt;ui-&amp;gt;bProcess-&amp;gt;setText(this-&amp;gt;plugins[this-&amp;gt;ui-&amp;gt;cbChoosePlugin-&amp;gt;itemData(index).toString()]-&amp;gt;getSign());&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this-&amp;gt;ui-&amp;gt;bProcess-&amp;gt;setEnabled(true);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; else {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this-&amp;gt;ui-&amp;gt;bProcess-&amp;gt;setText(&quot;&quot;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this-&amp;gt;ui-&amp;gt;bProcess-&amp;gt;setEnabled(false);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;}&lt;/p&gt;
&lt;p&gt;On vérifie tout d'abord que l'on a pas sélectionné le premier élément, qui est celui demandant de choisir une opération. Si on a bien sélectionné une opération, on récupère la donnée de l'élément (&lt;a hreflang=&quot;en&quot; href=&quot;http://doc.qt.nokia.com/latest/qcombobox.html#itemData&quot;&gt;itemData()&lt;/a&gt;) sélectionné, qui nous permet d'accéder à l'objet &lt;em&gt;Plugin&lt;/em&gt; correspondant, depuis lequel on appelle la méthode &lt;em&gt;getSign()&lt;/em&gt;. Le signe de l'opération est appliqué au bouton, qui est ensuite activé.&lt;/p&gt;
&lt;p&gt;Passons au dernier slot, compute, appelé lorsque l'utilisateur clique sur le bouton :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;void Dialog::compute() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if(!this-&amp;gt;ui-&amp;gt;leNumber1-&amp;gt;text().isEmpty() &amp;amp;&amp;amp; ! this-&amp;gt;ui-&amp;gt;leNumber2-&amp;gt;text().isEmpty() ) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Plugin * selectedPlugin = this-&amp;gt;plugins[this-&amp;gt;ui-&amp;gt;cbChoosePlugin-&amp;gt;itemData(this-&amp;gt;ui-&amp;gt;cbChoosePlugin-&amp;gt;currentIndex()).toString()];&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this-&amp;gt;ui-&amp;gt;lResult-&amp;gt;setText(QString::number(selectedPlugin-&amp;gt;compute(this-&amp;gt;ui-&amp;gt;leNumber1-&amp;gt;text().toDouble(),this-&amp;gt;ui-&amp;gt;leNumber2-&amp;gt;text().toDouble())));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;}&lt;/p&gt;
&lt;p&gt;Si les deux champs de saisie ont été remplis, on récupère l'objet &lt;em&gt;Plugin&lt;/em&gt; de l'opération sélectionnée. On appelle la méthode &lt;em&gt;compute()&lt;/em&gt; du &lt;em&gt;Plugin&lt;/em&gt;, en lui passant en paramètre la valeur des champs de saisie, qui nous retourne le résultat de l'opération, résultat que l'on affiche dans le libellé correspondant.&lt;/p&gt;
&lt;p&gt;Voici pour terminer, le code du plugin &quot;addition&quot;, je ne donne pas le code des 3 autres, qui se devine facilement, et qui est dispo dans les sources :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;function getOperationName() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return &quot;Addition&quot;;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function getOperationSign() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return &quot;+&quot;;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function compute(num1,num2) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return num1+num2;&lt;br /&gt;}&lt;/p&gt;
&lt;p&gt;On y voit donc les trois fonctions nécessaires, donnant le libellé de l'opération, son signe, et enfin le résultat de l'opération.&lt;/p&gt;
&lt;p&gt;Voilà pour l'explication de ce petit projet, qui j'espère vous permettra de voir de quelle façon on peut facilement avec &lt;strong&gt;Qt&lt;/strong&gt; gérer des &lt;em&gt;plugins&lt;/em&gt; écrits en &lt;strong&gt;JavaScript&lt;/strong&gt;. Si vous avez des questions sur le code, n'hésitez pas à les poser dans les commentaires.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;Bon dev'&lt;/p&gt;
&lt;p&gt;Fabien (eponyme)&lt;/p&gt;</description>
    
          <enclosure url="http://blog.nicoleau-fabien.net/public/qtexcalc/qtexcalc.tar.gz"
      length="2465" type="application/x-gzip" />
    
    
      </item>
    
  <item>
    <title>Premiers pas avec QtScript</title>
    <link>http://blog.nicoleau-fabien.net/index.php?post/2011/02/23/Premiers-pas-avec-QtScript</link>
    <guid isPermaLink="false">urn:md5:4535a5961e9b2f81f359e29c96c71273</guid>
    <pubDate>Thu, 03 Mar 2011 15:04:00 +0100</pubDate>
    <dc:creator>Fabien Nicoleau</dc:creator>
        <category>Développement</category>
        <category>plugins</category><category>Qt</category><category>QtScript</category>    
    <description>&lt;p&gt;Dans un précédent billet, j'avais parlé de la possibilité &lt;a href=&quot;http://blog.nicoleau-fabien.net/index.php?post/2010/11/16/Java-%3A-g%C3%A9rer-facilement-des-plugins-JavaScript&quot;&gt;d'intégrer très facilement dans vos applications Java des scripts écrits en JavaScript&lt;/a&gt;, et de la facilité avec laquelle vos applications peuvent interagir avec les scripts. J'avais ensuite proposé &lt;a href=&quot;http://blog.nicoleau-fabien.net/index.php?post/2010/11/20/Scripts-JS-avec-Java-et-Rhino-%3A-mise-en-%C5%93uvre-avec-un-bot-IRC&quot;&gt;un exemple d'utilisation avec un robot IRC&lt;/a&gt; fonctionnant avec des &lt;em&gt;plugins&lt;/em&gt; écrits en &lt;a hreflang=&quot;fr&quot; href=&quot;http://fr.wikipedia.org/wiki/JavaScript&quot;&gt;&lt;strong&gt;JavaScript&lt;/strong&gt;&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;La bibliothèque &lt;a hreflang=&quot;fr&quot; href=&quot;http://fr.wikipedia.org/wiki/Qt&quot;&gt;&lt;strong&gt;Qt&lt;/strong&gt;&lt;/a&gt; permet elle aussi d'intégrer des scripts &lt;strong&gt;JavaScript&lt;/strong&gt; dans vos applications. Je propose ici de découvrir comment le faire, à travers quelques exemples simples.&lt;/p&gt;    &lt;h2&gt;Avant de commencer&lt;/h2&gt;
&lt;p&gt;Avant d'entrer dans le vif du sujet, préparons d'abord le terrain. Je proposerai pour chaque exemple le code dans ce billet, mais je vous conseille, si vous voulez tester, de télécharger l'archive jointe à ce billet contenant les sources des exemples. Une fois décompressée, déplacez vous dans le dossier &lt;em&gt;qtscripting&lt;/em&gt;, puis ouvrez une console, et tapez :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;qmake-qt4&lt;br /&gt;make&lt;/p&gt;
&lt;p&gt;Tous les exemples sont alors compilés. Bien sûr, pour que la compilation fonctionne, ils vous faut installer le paquet &lt;strong&gt;qt-devel&lt;/strong&gt;. Sous &lt;strong&gt;Fedora&lt;/strong&gt;, tapez :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;# yum install qt-devel&lt;/p&gt;
&lt;p&gt;Une fois les exemples compilés, vous pouvez vous déplacer dans les dossiers, et lancer les exécutables. &lt;/p&gt;
&lt;p&gt;Notez que pour ajouter le support des scripts au projet, il a simplement suffit d'ajouter &lt;em&gt;script&lt;/em&gt; à la directive &lt;em&gt;QT&lt;/em&gt; (voir le &lt;em&gt;QT += script&lt;/em&gt; dans le fichier &lt;em&gt;common.pri&lt;/em&gt;), et d'include &lt;strong&gt;QtScript&lt;/strong&gt; dans les sources.&lt;/p&gt;
&lt;h2&gt;Exemple 1 : 1 + 1&lt;/h2&gt;
&lt;p&gt;Pour le premier exemple, faisons simple ! Il s'agit ici simplement de voir comment exécuter un code &lt;strong&gt;JavaScript&lt;/strong&gt; depuis du code &lt;strong&gt;C++&lt;/strong&gt;, et de récupérer le résultat.&lt;/p&gt;
&lt;p&gt;On commence direct avec le code :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;#include &amp;lt;QtScript&amp;gt;&lt;br /&gt;#include &amp;lt;QApplication&amp;gt;&lt;br /&gt;int main(int argc, char **argv)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; QApplication app(argc, argv);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; QScriptEngine engine;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; QScriptValue resultat = engine.evaluate(&quot;1+1&quot;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; qDebug() &amp;lt;&amp;lt; resultat.toString() ;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return 0;&lt;br /&gt;}&lt;/p&gt;
&lt;p&gt;Rien de complexe. On créé d'abord un objet de type &lt;a hreflang=&quot;en&quot; href=&quot;http://doc.trolltech.com/4.7/qscriptengine.html&quot;&gt;QScriptEngine&lt;/a&gt;, qui sera notre &lt;em&gt;moteur de script&lt;/em&gt;, indispensable. On demande ensuite à notre moteur &lt;em&gt;d'évaluer&lt;/em&gt; le code &quot;1+1&quot;. Le résultat de l'évaluation est stocké dans un objet de type &lt;a hreflang=&quot;en&quot; href=&quot;http://doc.trolltech.com/4.7/qscriptvalue.html&quot;&gt;QScriptValue&lt;/a&gt;. Enfin on affiche le résultat. En parcourant &lt;a hreflang=&quot;en&quot; href=&quot;http://doc.trolltech.com/4.7/qscriptvalue.html&quot;&gt;la doc sur QScriptValue&lt;/a&gt;, vous pourrez vous rendre compte qu'il est possible d'effectuer de nombreuses vérifications afin de s'assurer que le résultat est exploitable, notamment en contrôlant son type.&lt;/p&gt;
&lt;p&gt;Voilà pour un début, il n'y a rien d'exceptionnel bien sûr, mais les base sont posées : notre programme a affiché le résultat d'un code externe (en l'occurrence du &lt;strong&gt;JavaScript&lt;/strong&gt;, même si ce n'est qu'une addition, et que le code est &quot;en dur&quot; dans le programme). Pour les plus sceptiques, j'affiche la sortie du programme :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;[eponyme@localhost exemple1]$ ./exemple1 &lt;br /&gt;&quot;2&quot; &lt;br /&gt;[eponyme@localhost exemple1]$&lt;/p&gt;
&lt;p&gt;Surpris ? :D&lt;/p&gt;
&lt;p&gt;Passons à la suite.&lt;/p&gt;
&lt;h2&gt;Exemple 2 : appel d'une fonction&lt;/h2&gt;
&lt;p&gt;Nous allons dans cette exemple appeler une fonction et lui passer un paramètre, puis afficher ce qu'elle nous renvoie. Le code :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;#include &amp;lt;QtScript&amp;gt;&lt;br /&gt;#include &amp;lt;QApplication&amp;gt;&lt;br /&gt;int main(int argc, char **argv)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; QApplication app(argc, argv);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; QScriptEngine engine;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; engine.evaluate(&quot;function disMoiBonjour(prenom) { return \&quot;Bonjour \&quot;+prenom; }&quot;);&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; QScriptValue disBonjour = engine.globalObject().property(&quot;disMoiBonjour&quot;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; qDebug() &amp;lt;&amp;lt; disBonjour.call(QScriptValue(),QScriptValueList() &amp;lt;&amp;lt; &quot;Fabien&quot;).toString() ;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return 0;&lt;br /&gt;}&lt;/p&gt;
&lt;p&gt;Comme dans le premier exemple, on créé un &lt;em&gt;moteur&lt;/em&gt;, mais cette fois ci au lieu de lui faire évaluer une addition, nous demandons d'évaluer la définition d'une fonction, appelée &lt;em&gt;disMoiBonjour&lt;/em&gt;. Cette fonction retourne une phrase &quot;disant bonjour&quot; à la personne dont le prénom est passé en paramètre. La ligne suivante nous permet de récupérer parmi les objets du script (&lt;a hreflang=&quot;en&quot; href=&quot;http://doc.trolltech.com/4.7/qscriptengine.html#globalObject&quot;&gt;globalObject()&lt;/a&gt;)&amp;nbsp; notre fonction &lt;em&gt;disMoiBonjour&lt;/em&gt; (&lt;a hreflang=&quot;en&quot; href=&quot;http://doc.trolltech.com/4.7/qscriptvalue.html#property&quot;&gt;property()&lt;/a&gt;), conservée dans la variable &lt;em&gt;disBonjour&lt;/em&gt;. Il ne nous reste plus qu'à l'appeler grâce à la méthode &lt;a hreflang=&quot;en&quot; href=&quot;http://doc.trolltech.com/4.7/qscriptvalue.html#call&quot;&gt;call()&lt;/a&gt;. Notez le second paramètre, qui est une liste de valeurs qui sont passées en arguments à la fonction appelée. Ici, on envoie juste la chaîne &quot;Fabien&quot;.&lt;/p&gt;
&lt;p&gt;Voici la sortie du programme :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;[eponyme@localhost exemple2]$ ./exemple2 &lt;br /&gt;&quot;Bonjour Fabien&quot; &lt;br /&gt;[eponyme@localhost exemple2]$ &lt;/p&gt;
&lt;p&gt;Cet article ayant juste pour but de découvrir des choses simples et basiques possibles avec &lt;strong&gt;QtScript&lt;/strong&gt;, je ne rentre pas plus dans les le détail concernant les différentes méthodes utilisées ici, mais la documentation vous fera découvrir que l'on peut aller beaucoup plus loin.&lt;/p&gt;
&lt;p&gt;Au passage, on voit déjà que du code &lt;strong&gt;JavaScript&lt;/strong&gt; dans une chaine de caractères, ça n'est pas très pratique. Vivement qu'on puisse le mettre dans un fichier !&lt;/p&gt;
&lt;h2&gt;Exemple 3 : code JS dans un fichier et objet global&lt;/h2&gt;
&lt;p&gt;Pour le moment, nos scripts étaient &quot;en dur&quot; dans le code &lt;strong&gt;C++&lt;/strong&gt;, ce qui n'a que très peu (aucun ?) intérêt. Voyons ici comment externaliser ce code et le placer dans un fichier. La méthode &lt;a hreflang=&quot;en&quot; href=&quot;http://doc.trolltech.com/4.7/qscriptengine.html#evaluate&quot;&gt;evaluate()&lt;/a&gt; prenant en paramètre une chaine de caractères, il sera très simple (surtout avec &lt;strong&gt;Qt&lt;/strong&gt;) de récupérer le contenu d'un fichier texte pour le faire évaluer. Je profite aussi de cet exemple pour montrer comment exporter depuis le code &lt;strong&gt;C++&lt;/strong&gt; un objet global dans le script. Comme d'habitude, on attaque directement avec le code :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;#include &amp;lt;QtScript&amp;gt;&lt;br /&gt;#include &amp;lt;QApplication&amp;gt;&lt;br /&gt;int main(int argc, char **argv)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; QApplication app(argc, argv);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; QScriptEngine engine;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; QFile file(&quot;script.qs&quot;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; file.open(QIODevice::ReadOnly);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; engine.globalObject().setProperty(&quot;name&quot;,&quot;Fabien&quot;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; engine.evaluate(file.readAll());&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; file.close();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return 0;&lt;br /&gt;}&lt;/p&gt;
&lt;p&gt;Comme on pouvait s'y attendre, la chose est très simple à réaliser grâce à l'objet &lt;a hreflang=&quot;en&quot; href=&quot;http://doc.qt.nokia.com/latest/qfile.html&quot;&gt;QFile&lt;/a&gt;. On ouvre en lecture seule un fichier nommé &lt;em&gt;script.qs&lt;/em&gt;, et on passe son contenu à la méthode &lt;a hreflang=&quot;en&quot; href=&quot;http://doc.trolltech.com/latest/qscriptengine.html#evaluate&quot;&gt;evaluate()&lt;/a&gt; via la méthode &lt;a hreflang=&quot;en&quot; href=&quot;http://doc.qt.nokia.com/latest/qiodevice.html#readAll&quot;&gt;readAll()&lt;/a&gt;. Le contenu du fichier est ainsi entièrement évalué. L'autre nouveauté ici est que l'on &quot;envoie&quot; dans le script l'objet &quot;name&quot;, dont la valeur est &quot;Fabien&quot;, avec la méthode &lt;a hreflang=&quot;en&quot; href=&quot;http://doc.trolltech.com/latest/qscriptvalue.html#setProperty&quot;&gt;setProperty()&lt;/a&gt;. Ainsi, à n'importe quel endroit du script, il sera possible d'accéder à cet objet.&lt;/p&gt;
&lt;p&gt;Voyons d'ailleurs le contenu du script (fichier &lt;em&gt;script.qs&lt;/em&gt;) :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;print('Bonjour '+name);&lt;/p&gt;
&lt;p&gt;Ce petit script se contentera donc d'afficher dans la console un bonjour à la personne dont le prénom est stocké dans l'objet &lt;em&gt;name&lt;/em&gt; (et assigné depuis le code &lt;strong&gt;C++&lt;/strong&gt;).&lt;/p&gt;
&lt;p&gt;Voyons ce que ca donne à l'exécution :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;[eponyme@localhost exemple3]$ ./exemple3 &lt;br /&gt;Bonjour Fabien&lt;br /&gt;[eponyme@localhost exemple3]$&lt;/p&gt;
&lt;p&gt;La encore, pas de grande surprise ! Mais désormais, vous pouvez stocker votre code &lt;strong&gt;JS&lt;/strong&gt; dans un fichier, ce qui ouvre un grand nombre de possibilités, notamment celui de stocker différents scripts afin de charger différentes fonctions, pour un système de &lt;em&gt;plugins&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;Exemple 4 : envoi d'un QObject dans le script&lt;/h2&gt;
&lt;p&gt;L'exemple 3 nous a montré qu'il est possible d'envoyer un objet avec une valeur dans le script, et ce depuis le code &lt;strong&gt;C++&lt;/strong&gt;. Cependant cet objet ne peut prendre qu'une valeur simple. Nous allons voir ici comment envoyer dans le script un &lt;a hreflang=&quot;en&quot; href=&quot;http://doc.qt.nokia.com/latest/qobject.html&quot;&gt;QObject&lt;/a&gt; (et donc un de ses objets hérités, ce qui en fait beaucoup).&lt;/p&gt;
&lt;p&gt;Pour illustrer cet exemple, je vais utiliser un &lt;a hreflang=&quot;en&quot; href=&quot;http://doc.qt.nokia.com/latest/qlabel.html&quot;&gt;QLabel&lt;/a&gt;, habituellement utilisé pour afficher un libellé dans une interface graphique. Voici le code :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;#include &amp;lt;QtScript&amp;gt;&lt;br /&gt;#include &amp;lt;QApplication&amp;gt;&lt;br /&gt;#include &amp;lt;QLabel&amp;gt;&lt;br /&gt;int main(int argc, char **argv)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; QApplication app(argc, argv);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; QLabel lbl;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; QScriptEngine engine;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; QFile file(&quot;script.qs&quot;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; file.open(QIODevice::ReadOnly);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; lbl.setText(&quot;UN&quot;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; QScriptValue object = engine.newQObject(&amp;amp;lbl);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; engine.globalObject().setProperty(&quot;label&quot;,object);&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; engine.evaluate(file.readAll());&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; file.close();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; qDebug() &amp;lt;&amp;lt;&quot;Dans le code : &quot; &amp;lt;&amp;lt;&amp;nbsp; lbl.text();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return 0;&lt;br /&gt;}&lt;/p&gt;
&lt;p&gt;Le &lt;a hreflang=&quot;en&quot; href=&quot;http://doc.qt.nokia.com/latest/qlabel.html&quot;&gt;QLabel&lt;/a&gt; ne sera pas utilisé ici dans une interface, mais on utilise ses méthodes pour le manipuler. Après l'habituelle création du moteur, on créé donc un objet &lt;a hreflang=&quot;en&quot; href=&quot;http://doc.qt.nokia.com/latest/qlabel.html&quot;&gt;QLabel&lt;/a&gt;, pour lequel on modifie le libellé en le passant à &quot;UN&quot;, grâce au &lt;em&gt;slot&lt;/em&gt; &lt;a hreflang=&quot;en&quot; href=&quot;http://doc.qt.nokia.com/latest/qlabel.html#text-prop&quot;&gt;setText()&lt;/a&gt;. Ensuite, la méthode &lt;a hreflang=&quot;en&quot; href=&quot;http://doc.trolltech.com/latest/qscriptengine.html#newQObject&quot;&gt;newQObject()&lt;/a&gt; du moteur est appelée, prenant en paramètre un pointeur sur notre objet de type &lt;a hreflang=&quot;en&quot; href=&quot;http://doc.qt.nokia.com/latest/qlabel.html&quot;&gt;QLabel&lt;/a&gt;. C'est la valeur renvoyée par &lt;em&gt;newQObject&lt;/em&gt; qui est utilisée pour le &lt;a hreflang=&quot;en&quot; href=&quot;http://doc.trolltech.com/latest/qscriptvalue.html#setProperty&quot;&gt;setProperty()&lt;/a&gt; de la ligne suivante, déjà utilisé dans l'exemple 3. Ainsi, dans notre script, on pourra utiliser notre objet &lt;a hreflang=&quot;en&quot; href=&quot;http://doc.qt.nokia.com/latest/qlabel.html&quot;&gt;QLabel&lt;/a&gt; n'importe quand grâce à la variable &lt;em&gt;label&lt;/em&gt;, dont le nom est passé en premier argument à &lt;a hreflang=&quot;en&quot; href=&quot;http://doc.trolltech.com/latest/qscriptvalue.html#setProperty&quot;&gt;setProperty()&lt;/a&gt;. Comme dans les autres exemples, on évalue le script, puis on ferme le fichier. Enfin, on affiche la valeur de notre &lt;a hreflang=&quot;en&quot; href=&quot;http://doc.qt.nokia.com/latest/qlabel.html&quot;&gt;QLabel&lt;/a&gt; grâce à sa méthode &lt;a hreflang=&quot;en&quot; href=&quot;http://doc.qt.nokia.com/latest/qlabel.html#text-prop&quot;&gt;text()&lt;/a&gt;. En toute logique, elle devrait renvoyer &quot;UN&quot;, à moins que la valeur ait été changée depuis le script ... Voyons justement le code de ce dernier (fichier &lt;em&gt;script.qs&lt;/em&gt;) : &lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;print(&quot;Dans le script : &quot;+label.text);&lt;br /&gt;label.setText(&quot;DEUX&quot;);&lt;/p&gt;
&lt;p&gt;Deux lignes, très simples. La première affiche la valeur du &lt;a hreflang=&quot;en&quot; href=&quot;http://doc.qt.nokia.com/latest/qlabel.html&quot;&gt;QLabel&lt;/a&gt; accessible grâce à la variable &lt;em&gt;label&lt;/em&gt;. La valeur du &lt;a hreflang=&quot;en&quot; href=&quot;http://doc.qt.nokia.com/latest/qlabel.html&quot;&gt;QLabel&lt;/a&gt; est obtenue grâce à la propriété &lt;em&gt;text&lt;/em&gt; de ce dernier. Sur la seconde ligne, on change la valeur du &lt;a hreflang=&quot;en&quot; href=&quot;http://doc.qt.nokia.com/latest/qlabel.html&quot;&gt;QLabel&lt;/a&gt; à &quot;DEUX&quot;, grâce à &lt;a hreflang=&quot;en&quot; href=&quot;http://doc.qt.nokia.com/latest/qlabel.html#text-prop&quot;&gt;setText()&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;Voyons ce que donne l'exécution :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;[eponyme@localhost exemple4]$ ./exemple4 &lt;br /&gt;Dans le script : UN&lt;br /&gt;Dans le code :&amp;nbsp; &quot;DEUX&quot; &lt;br /&gt;[eponyme@localhost exemple4]$&lt;/p&gt;
&lt;p&gt;On voit ici l'évolution de notre &lt;a hreflang=&quot;en&quot; href=&quot;http://doc.qt.nokia.com/latest/qobject.html&quot;&gt;QObject&lt;/a&gt; ! La première valeur affichée (&quot;UN&quot;) depuis le script (avec print()) est celle qui avait été fixée dans le code &lt;strong&gt;C++&lt;/strong&gt;. Après avoir affiché la valeur, le script &lt;strong&gt;JS&lt;/strong&gt; a changé la valeur du &lt;a hreflang=&quot;en&quot; href=&quot;http://doc.qt.nokia.com/latest/qlabel.html&quot;&gt;QLabel&lt;/a&gt;, et depuis le code, la valeur affichée est bien &quot;DEUX&quot;.&lt;/p&gt;
&lt;p&gt;Nous pouvons donc de façon très simple passer à notre script &lt;strong&gt;JS&lt;/strong&gt; des &lt;a hreflang=&quot;en&quot; href=&quot;http://doc.qt.nokia.com/latest/qobject.html&quot;&gt;QObject&lt;/a&gt; et lui permettre d'en modifier les propriétés.&lt;/p&gt;
&lt;h2&gt;Exemple 5 : gestion des erreurs&lt;/h2&gt;
&lt;p&gt;Lorsque l'on débute, ou lorsque l'on commence à faire des choses compliquées, il arrive souvent que l'on bloque car le code &lt;strong&gt;JS&lt;/strong&gt; n'est pas évalué. Dans la plupart des cas, il s'agit juste d'une erreur de syntaxe. Mais il est parfois difficile de savoir pourquoi est ce que notre script n'est pas évalué, et donc qu'il est impossible d'interagir avec lui ensuite. On peut aussi être parfois sûr de son code, et ne pas penser qu'il y a une erreur. Heureusement il est possible, lorsqu'une erreur est rencontrée, d'afficher un message. Voici un code d'exemple :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;#include &amp;lt;QtScript&amp;gt;&lt;br /&gt;#include &amp;lt;QApplication&amp;gt;&lt;br /&gt;int main(int argc, char **argv)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; QApplication app(argc, argv);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; QScriptEngine engine;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; QScriptValue result = engine.evaluate(&quot;print('Bonjour !'&quot;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (result.isError()) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; qDebug() &amp;lt;&amp;lt; result.property(&quot;message&quot;).toString(); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return 0;&lt;br /&gt;}&lt;/p&gt;
&lt;p&gt;Dans ce code, on demande au moteur d'évaluer du &lt;strong&gt;JavaScript&lt;/strong&gt; devant afficher &quot;Bonjour !&quot;, mais la parenthèse fermante est volontairement oubliée. On se sert de la valeur renvoyée par l'évaluation pour vérifier s'il y a eu une erreur avec &lt;a hreflang=&quot;en&quot; href=&quot;http://doc.trolltech.com/latest/qscriptvalue.html#isError&quot;&gt;isError()&lt;/a&gt;. Si c'est le cas, on peut afficher un message explicatif en récupérant la propriété &lt;em&gt;message&lt;/em&gt; du résultat d'évaluation. &lt;/p&gt;
&lt;p&gt;Voyons l'exécution du programme :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;[eponyme@localhost exemple5]$ ./exemple5 &lt;br /&gt;&quot;Parse error&quot; &lt;br /&gt;[eponyme@localhost exemple5]$&lt;/p&gt;
&lt;p&gt;Notre code n'est pas évalué, et le moteur nous indique une &lt;em&gt;Parse error&lt;/em&gt;. On sait au moins ou chercher. Cette vérification vous permettra de gagner un peu de temps si vous n'obtenez pas le résultat espéré.&lt;/p&gt;
&lt;h2&gt;Exemple 6 : signaux et slots&lt;/h2&gt;
&lt;p&gt;Les &lt;em&gt;signaux&lt;/em&gt; et &lt;em&gt;slots&lt;/em&gt; sont l'un des avantages du développement avec la bibliothèque &lt;strong&gt;Qt&lt;/strong&gt;, et n'ont pas été oubliés avec &lt;strong&gt;QtScript&lt;/strong&gt;. Dans ce dernier exemple, nous allons créer une fenêtre basique comprenant deux boutons. Le premier, appelé &quot;Bonjour&quot;, devra afficher &quot;Bonjour !&quot; dans la console lorsque l'on clique dessus, et le second, &quot;Au revoir&quot;, devra afficher ... &quot;Au revoir !&quot; (et oui !)&amp;nbsp; lorsque l'on clique dessus. La particularité est que ces affichages dans la console se feront depuis un script &lt;strong&gt;JS&lt;/strong&gt;, et non pas directement depuis des &lt;em&gt;slots&lt;/em&gt; dans le code &lt;strong&gt;C++&lt;/strong&gt;. L'intérêt ? Ici, aucun. Il s'agira simplement de montrer que l'on peut connecter un &lt;em&gt;signal&lt;/em&gt; à un &lt;em&gt;slot&lt;/em&gt; dont l'implémentation est faite dans un script &lt;strong&gt;JS&lt;/strong&gt;, ce qui permet de personnaliser facilement une application en changeant le comportement du &lt;em&gt;slot&lt;/em&gt; dans les scripts. Pour l'exemple, nous verrons deux façons différentes de connecter un &lt;em&gt;signal&lt;/em&gt; à un &lt;em&gt;slot&lt;/em&gt; implémenté dans un script, la première sera faite depuis le code &lt;strong&gt;C++&lt;/strong&gt;, pour le bouton &quot;Bonjour&quot;, et la seconde directement dans le script &lt;strong&gt;JS&lt;/strong&gt;, pour le bouton &quot;Au revoir&quot;.&lt;/p&gt;
&lt;p&gt;Passons au code :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;#include &amp;lt;QtScript&amp;gt;&lt;br /&gt;#include &amp;lt;QApplication&amp;gt;&lt;br /&gt;#include &amp;lt;QtGui&amp;gt;&lt;br /&gt;int main(int argc, char **argv)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; QApplication app(argc, argv);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; QWidget fenetre;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; QVBoxLayout vbox(&amp;amp;fenetre);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; QPushButton bBonjour(&quot;Bonjour&quot;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; QPushButton bAuRevoir(&quot;Au revoir&quot;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; vbox.addWidget(&amp;amp;bBonjour);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; vbox.addWidget(&amp;amp;bAuRevoir);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; QScriptEngine engine;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; QFile file(&quot;script.qs&quot;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; file.open(QIODevice::ReadOnly);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; QScriptValue objBonjour = engine.newQObject(&amp;amp;bBonjour);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; QScriptValue objAuRevoir = engine.newQObject(&amp;amp;bAuRevoir);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; engine.globalObject().setProperty(&quot;objAuRevoir&quot;,objAuRevoir);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; engine.evaluate(file.readAll());&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; file.close();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; QScriptValue slot = engine.globalObject().property(&quot;bonjourHandler&quot;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; qScriptConnect(&amp;amp;bBonjour, SIGNAL(clicked()), objBonjour, slot);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; fenetre.show();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return app.exec();&lt;br /&gt;}&lt;/p&gt;
&lt;p&gt;C'est un peu plus long que d'habitude, certes, mais le premier pavé ne concerne que l'interface graphique, ce qui n'est pas le sujet de ce billet. On y créé les deux boutons et on les place sur la fenêtre. &lt;/p&gt;
&lt;p&gt;Ensuite, comme d'habitude, on créé un moteur, qui évaluera du code &lt;strong&gt;JS&lt;/strong&gt; placé dans un fichier. Deux &quot;objets &lt;em&gt;QtScript&lt;/em&gt;&quot; sont créés à partir des deux boutons, grâce à &lt;a hreflang=&quot;en&quot; href=&quot;http://doc.trolltech.com/latest/qscriptengine.html#newQObject&quot;&gt;newQObject()&lt;/a&gt; : &lt;em&gt;objBonjour&lt;/em&gt; et &lt;em&gt;objAuRevoir&lt;/em&gt;. Ils nous serviront à réaliser les connexions avec les &lt;em&gt;slots&lt;/em&gt; du script. L'objet &lt;em&gt;objAuRevoir&lt;/em&gt; est exporté dans le script car nous en aurons besoin pour réaliser la connexion au &lt;em&gt;slot&lt;/em&gt;.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Une fois l'évaluation du script faite, on récupère la propriété &lt;em&gt;bonjourHander&lt;/em&gt;, qui est une fonction dans le script &lt;strong&gt;JS&lt;/strong&gt;, que l'on stocke dans la variable &lt;em&gt;slot&lt;/em&gt;. Cette variable est utilisée ensuite pour réaliser la connexion entre le &lt;em&gt;signal&lt;/em&gt; &lt;a hreflang=&quot;en&quot; href=&quot;http://doc.trolltech.com/latest/qabstractbutton.html#clicked&quot;&gt;clicked&lt;/a&gt; du bouton &quot;Bonjour&quot; et le &lt;em&gt;slot&lt;/em&gt; bonjourHandler, grâce à la fonction &lt;a hreflang=&quot;en&quot; href=&quot;http://doc.trolltech.com/latest/qscriptengine.html#qScriptConnect&quot;&gt;qScriptConnect()&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;Voyons maintenant le contenu du script (fichier &lt;em&gt;script.qs&lt;/em&gt;) :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;function bonjourHandler () {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; print('Bonjour !');&lt;br /&gt;}&lt;br /&gt;function auRevoirHandler () {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; print('Au revoir !');&lt;br /&gt;}&lt;br /&gt;objAuRevoir.clicked.connect(this.auRevoirHandler);&lt;/p&gt;
&lt;p&gt;On y trouve les deux fonctions qui seront appelées lors des clics sur les boutons. &lt;em&gt;bonjourHandler&lt;/em&gt; est déjà connectée au bouton &quot;Bonjour&quot; via l'appel à &lt;a hreflang=&quot;en&quot; href=&quot;http://doc.trolltech.com/latest/qscriptengine.html#qScriptConnect&quot;&gt;qScriptConnect()&lt;/a&gt; dans le code &lt;strong&gt;C++&lt;/strong&gt;. La fonction &lt;em&gt;auRevoirHandler&lt;/em&gt; est elle connectée au bouton &quot;Au revoir&quot; à la dernière ligne du script, qui utilise l'objet &lt;em&gt;objAuRevoir&lt;/em&gt; exporté dans le programme. Ainsi nos deux fonctions sont connectées à leur bouton respectif, l'une depuis le code &lt;strong&gt;C++&lt;/strong&gt;, l'autre depuis le script &lt;strong&gt;JS&lt;/strong&gt;. A vous de voir ce que vous préférez !&lt;/p&gt;
&lt;p&gt;Une petite image pour l'exécution du programme :&lt;/p&gt;
&lt;p&gt;&lt;img title=&quot;tuto_qtscript_exemple6.jpg, mar. 2011&quot; style=&quot;margin: 0 auto; display: block;&quot; alt=&quot;tuto_qtscript_exemple6.jpg&quot; src=&quot;http://blog.nicoleau-fabien.net/public/QtScript/tuto_qtscript_exemple6.jpg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;C'est sur cet exemple que ce termine cette initiation. Je n'ai pas la prétention avec cet article de donner une vue d'ensemble des possibilités offertes par &lt;strong&gt;QtScript&lt;/strong&gt;. J'en suis d'ailleurs encore au stade de la découverte. Mais ces exemples pourrons vous permettre de vous lancer, et de démystifier un peu les choses ! Je proposerai dans un prochain article un exemple concret d'utilisation de &lt;strong&gt;QtScript&lt;/strong&gt; pour un système de &lt;em&gt;plugins&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Hormis les liens disséminés un peu partout dans l'article, les deux sources qui m'ont le plus aidé sont :&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;&lt;a hreflang=&quot;en&quot; href=&quot;http://doc.trolltech.com/4.3/qtscript.html&quot;&gt;La doc officielle sur QtScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a hreflang=&quot;fr&quot; href=&quot;http://qt.developpez.com/evenement/2009-devdays/conferences/qt-script/&quot;&gt;Le site développez.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bon dev' !&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;Fabien (eponyme)&lt;/p&gt;</description>
    
          <enclosure url="http://blog.nicoleau-fabien.net/public/QtScript/qtscripting.tar.gz"
      length="1514" type="application/x-gzip" />
    
    
      </item>
    
  <item>
    <title>Réponse à l'article &quot;Fedora vs OpenSuse vs Ubuntu&quot; du Linux Planet #63</title>
    <link>http://blog.nicoleau-fabien.net/index.php?post/2011/01/22/R%C3%A9ponse-%C3%A0-l-article-Fedora-vs-OpenSuse-vs-Ubuntu-du-Linux-Planet-63</link>
    <guid isPermaLink="false">urn:md5:801b2061097f7f06c666969928fca3c2</guid>
    <pubDate>Sat, 22 Jan 2011 20:56:00 +0100</pubDate>
    <dc:creator>Fabien Nicoleau</dc:creator>
        <category>Lectures</category>
            
    <description>&lt;p&gt;Vieil abonné de ce magazine, j'ai reçu
le dernier numéro il y a quelques jours, qui propose un comparatif
des trois distributions mentionnées dans le titre, proposant même
en couverture de nous dire quelle est la meilleure ! Le problème est
que ce comparatif se trouve en fait être un &quot;travail&quot;
bâclé, plutôt pro-ubuntu, contre Fedora, et qui ne nous dis pas
grand chose sur OpenSuse. Si le résultat était basé sur un vrai
comparatif, on pourrait admettre la chose. Sauf que ce n'est pas le
cas, et c'est Fedora qui en pâti le plus. Selon cet article, nous
sommes une communauté mal organisée, et notre système est
difficilement configurable sans un bon niveau d'anglais. De plus
Fedora n'a volontairement inclut aucun outil de configuration afin de
ne s'adresser qu'aux experts. Ah si il y en a un, oui oui, nous avons
un &quot;centre de contrôle&quot;, ils ont même mis une capture
d'écran ! En regardant de plus près, le &quot;centre de contrôle&quot;
est l'outil de configuration de compiz-fusion. Pas étonnant qu'il
soit jugé &quot;séduisant mais incomplet&quot; pour configurer
notre Fedora, puisque qu'il n'est pas fait pour ça. Pour l'offre
logicielle de Fedora, l'auteur reproche au dépôt Livna de ne pas
être à jour ... Bref, vous voyez le niveau de l'article, et surtout
le non professionnalisme. On trouve des défauts à Fedora qui se
transforment presque en avantage chez les autres distros. Cela dit,
Ubuntu n'est pas en reste, puisque qu'un titre nous dis &quot;Ubuntu,
des assistants efficaces&quot;, et quelques lignes plus bas &quot;Les
quelques assistants présents ne sont pas d'une grande efficacité et
souvent trop incomplets&quot;. En somme, un article qui n'en ai pas
vraiment un, et qui m'a exaspéré. On regarde la distro vite fait,
on clique ici et la, et on donne un avis. &lt;a hreflang=&quot;fr&quot; href=&quot;http://blog.mrtomlinux.org/index.php?post/Plan%C3%A8te-Linux-%3A-num%C3%A9ro-de-janvier-2011-d%C3%A9cevant-%21&quot;&gt;MrTom dans son billet&lt;/a&gt;
pointe les deux erreurs principales : ne pas avoir parlé des idéaux
des distros, et ne pas avoir contacté la communauté.
&lt;/p&gt;
&lt;p&gt;J'ai donc joints le courrier des
lecteurs, et leur ai envoyé, ce courrier, en espérant qu'il y aura
au moins un petit correctif pour ce qui a été inventé de toute
pièce, et que comme je le leur propose, pour se rattraper, ils
prendront le temps de rédiger un vrai article sur Fedora dans un numéro, en prenant soin de s'intéresser vraiment à la
distribution, sa communauté, sa philosophie, bref, leur job.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Edit : Honte à moi, je retire ce que j'ai dis sur le panneau de contrôle qui existe bel et bien. L'erreur vient donc de moi, et non pas du magazine, qui pour le coup me l'a fait découvrir. Merci à eux :)&lt;/strong&gt;&lt;/p&gt;    &lt;q&gt;&lt;p&gt;Bonjour,&lt;/p&gt;
&lt;p&gt;Je suis utilisateur de Fedora depuis la
&quot;core 3&quot;. J'aimerais vous faire part de mon mécontentement
au sujet de l'article &quot;Fedora vs OpenSuse vs Ubuntu&quot; du
numéro 63 de votre magazine, pour lequel j'ai trouvé qu'il y a eu
de la part des auteurs un réel manque de professionnalisme. Je doute
même que la distribution ai été réellement testée, tant
certaines erreurs sont flagrantes.
&lt;/p&gt;
&lt;p&gt;Je me permets donc ici de vous faire
part de ce que j'ai relevé :
&lt;/p&gt;
&lt;p&gt;Dans la partie &quot;Configuration&quot;, vous mettez un sous titre pour Fedora &quot;Le minimum syndical&quot;.
Vous ajoutez ensuite que c'est un choix délibéré afin de ne pas
attirer trop de débutants. J'aimerais avoir une référence la
dessus, car je pense que c'est totalement faux. D'ailleurs les outils
de configuration graphique sont très nombreux, et se trouvent dans
les menus Système=&amp;gt;Préférences et Système=&amp;gt;Administration.
Je ne suis pas débutant, et j'utilise systématiquement des outils
graphiques de configuration lorsque j'ai des paramétrages à faire.
Les outils graphiques de configuration sous Fedora se nomment tous
system-config-... (network, printer, keyboard). Non seulement les
outils sont donc présents, mais en plus la plupart (tous ?) ont été
développé par RedHat / Fedora, et certains ont été repris dans
d'autres distributions... Vous parlez ensuite d'un &quot;centre de
contrôle plutôt séduisant&quot; mais &quot;très incomplet et très
sommaire&quot;. J'ai été très surpris, car utilisant Fedora depuis
très longtemps, je n'avais jamais entendu parler d'un &quot;centre
de contrôle&quot; propre à ma distribution préférée. C'est en
regardant la capture d'écran que vous avez associée à ce
paragraphe que j'ai compris l'erreur : vous avez utilisé l'outil de
configuration de compiz-fusion... Il est donc normal que vous le
trouviez incomplet pour configurer une distribution. En revanche pour
configurer compiz (ce pourquoi il a été fait), je le trouve plutôt
pratique. J’espère que vous admettrez ici que vous n'avez
absolument pas cherché à savoir comment configurer Fedora, que vous
avez pris le premier outil de configuration trouvé et que vous vous
êtes basé la dessus pour vous faire un avis. Sauf que l'outil
n'était pas le bon, et donc l'avis n'a aucun crédit. Vous trompez
d'ailleurs vos lecteur. C'est difficilement acceptable. Vous parlez
pour terminer de l'installation des pilotes et logiciels
propriétaires, tels que flash. Je ne vois pas ce que ça vient faire
dans la partie configuration... Vous dites qu'il faudra lire les
documentation, mais vous oubliez de préciser qu'une fois la doc lue,
l'installation se fait en tapant au maximum deux lignes dans un
terminal... Vous oubliez d'ailleurs de parler de la philosophie de
Fedora, et de son attachement au libre. Vous dites avoir eu des
soucis pour installer flash et la lecture de mp3. Je suis depuis de
nombreuses versions la documentation lors d'une nouvelle version de
Fedora pour installer (entre autres choses) ces outils, et tout
marche à chaque fois. Il serait intéressant que vous indiquiez les
problèmes que vous avez rencontré, pour pouvoir modifier la doc si
nécessaire, mais étant donné le manque d’honnêteté avec lequel
vous avez entamé ce paragraphe, j'ai quelques doutes quand au fait
que vous auriez essayé d'installer des pilotes.
&lt;/p&gt;
&lt;p&gt;Il est aussi intéressant de noter que
dans la colonne d’à coté, vous donnez un avis très positif
d'OpenSuse en raison de la richesse de ses DVD, alors que votre test
est fait depuis un live CD. J'y reviendrais plus tard ... Il est
aussi intéressant de noter que pour Ubuntu, vous dites &quot;Pour la
partie périphérique, soit ça fonctionne directement, soit il
faudra passer par la console pour régler le problème&quot;. En
gros, soit ça marche, soit non, et la on utilise la console. Bref,
quelle différence avec les autres distribution ? D'un seul coup
utiliser sa console n'est pas un problème, alors que l'utiliser pour
installer un driver propriétaire sous Fedora en est un, curieux.
D'ailleurs, toujours pour la colonne &quot;Ubuntu&quot;, le titre est
&quot;des assistants efficaces&quot;, puis plus loin : &quot;Les
quelques assistants présents ne sont pas d'une grande efficacité et
souvent trop incomplets&quot;. J'espère que le stagiaire qui a écrit
cette partie n'a pas eu les tickets resto que vous lui aurez promis
!
&lt;/p&gt;
&lt;p&gt;Je passe au point suivant : &quot;Offre
logicielle&quot;. Vous parlez des nouveautés, du fait qu'il ne faut
pas &quot;avoir peur&quot; d'essayer les dernière innovations. C'est
assez vrai. Auriez vous donc vraiment testé cette distribution ?
Vous parlez ensuite du fait que les dépôts RPM Fusion et Livna,
sont parfois &quot;très incomplets&quot; selon vous. Je vous invite
à lire la documentation francophone du site que vous critiquez à
plusieurs reprises pour vous rendre compte qu'en ce qui concerne
Livna, vous risquez d'attendre longtemps de nouveaux logiciels :
http://doc.fedora-fr.org/wiki/D%C3%A9p%C3%B4t_livna. Je n'ai pas
compris ce que sont les &quot;décalages entre versions&quot; non
comblés. Il est intéressant de voir que vous parlez du dépôt
ccrma, très spécifique, mais que vous omettez de parler d'un dépôt
comme celui de &quot;Remi&quot; (et dont la configuration est
extrêmement simple et expliquée dans la documentation francophone
...) pourtant très réputé dans la communauté (et pas que
francophone).
&lt;/p&gt;
&lt;p&gt;Vous trouvez l'offre pas aussi complète
que pour Ubuntu. Pour ma part, outre les dépôts standards déjà
installés, j'utilise simplement le dépôt rpmfusion, et j'ai toute
l'offre logicielle dont j'ai besoins. La fusion des dépôts Fedora a
non seulement permis de donner une grande importance à la
communauté, mais permet aussi de faire en sorte que l'offre
logicielle réponde à des règles communes, et assure une cohérence
du système. Oui, Ubuntu est extrêmement complet. Je package des
logiciels pour Fedora et j'ai pu m'apercevoir que si un de mes paquets
à mis 1 mois de plus que sous Ubuntu à arriver dans les dépôts
officiels (et donc ne nécessitant aucune installation de dépôt
tiers pour l'utilisateur), le packageur Ubuntu passait lui par un
dépôt tiers qui se souciait peu des conventions pour
l'emplacement de certains fichiers. Oui, le package ubuntu était
prêt avant, mais il n'avait pas été vérifié, et nécessitait un
dépôt tiers. Mon insistance auprès du développeur du logiciel
pour permettre plus facilement de placer les fichiers du programme au
bon endroit sur le système lui ont permit de fournir un système
d'installation plus propre, et a facilité l'acceptation du paquet
dans d'autres distributions. Chacun sa politique, mais il est
important de préciser les choses ...
&lt;/p&gt;
&lt;p&gt;Le point suivant : &quot;Communauté -
Aide&quot;. Vous continuez sur votre exemple d'installation du dépôt
ccrma (sans préciser à vos lecteurs qu'ils s'agit d'un dépôt très
spécifique, concernant surtout les musiciens, et que certains des
logiciels qu'il propose nécessitent aussi certainement, pour les
autres distributions, l'utilisation de dépôts tiers). Vous dites ne
pas être &quot;convaincus&quot; de l'aide donnée sur le site d'aide
francophone, sauf qu'elle fonctionne, et que les urls utilisées sont
celles des miroirs français données sur le site officiel du projet.
Vous vous doutez bien qu'elles n'auraient pas été utilisées si
elles avaient été du type &quot;http://jesuisunpirate.com/ccrm.repo&quot;
... L'outil proposé pour installer le rpm est &quot;yum&quot;, et
l'option --nogpgcheck est utilisée car effectivement le paquet n'est
pas signé. C'est une erreur du dépôt (tiers !), et pas une erreur
de Fedora. Vous dites que le site officiel donne une solution
(utiliser rpm directement, plutôt que yum), et qu'elle ne marche
pas. Je viens de faire l'essai, et ça fonctionne chez moi. La encore
vous ne donnez aucune précision... En revanche, même en passant par
&quot;rpm&quot;, on a un avertissement au sujet de la non signature
du paquet. Au final vous ne dites pas ce qui a fonctionné. Vous
dites ensuite que la communauté française n'est pas &quot;trop
organisée&quot; pour la documentation. Je suis curieux de savoir le
temps que vous avez pris pour savoir quelle est notre organisation
... autant que pour trouver le panneau de contrôle qui n'existe pas
?
&lt;/p&gt;
&lt;p&gt;Ce paragraphe sur la communauté montre
parfaitement votre partialité, et de quelle façon vous cherchez à
dénigrer Fedora. Vous prenez un exemple très précis sur Fedora, un
dépôt dont la plupart de vos lecteur n'aurons pas besoins. Vous
dites avoir des problèmes avec ... vous ne donnez pas de solution
... Vous nous servez ensuite une petite remontrance en nous disant
que la documentation joue un rôle important dans le choix d'une
distribution ... En revanche pour OpenSuse, c'est magique ! Il faut
d'abord chercher quels sont les sites d'aide, pour ensuite pouvoir
rechercher dessus. Mais ça ne vous pose pas de souci. Vous dites
qu'ils répondent au &quot;maximum des attentes&quot;, mais vos
attentes pour OpenSuse semblent moins pointilleuses que pour Fedora.
J'espère ne pas blesser les utilisateurs francophones d'OpenSuse
(j'en fais aussi partie !), mais ce n'est pas un secret que de dire
que la communauté est &quot;plutôt petite&quot;. Vous finissez en
disant que la communauté francophone est quasi inexistante (c'est
pire que mal organisée (selon vous) non ?). Ne mettre qu'un point
d'écart entre Fedora et OpenSuse ne reflète absolument pas la
réalité. De plus vos comparaisons sont totalement inégales. C'est
bien de mettre des notes, mais il serait bien de mettre un barème,
cela rendrait peut être les choses moins aléatoires, et vous aurait
peut être forcé à faire une réelle comparaison ...
&lt;/p&gt;
&lt;p&gt;Votre bilan est plutôt fidèle au
reste. Dans l'introduction de l'article, vous dites qu'il ne s'agit pas d'un
comparatif de bureau. Heureusement que vous n’êtes pas allés
jusque la ! A quoi aurions nous eu droit. Vous arrivez quand même à
dire que Fedora et Ubuntu sont diffusées avec Gnome, laissant penser
que pour avoir kde avec Fedora, il faudrait, à l'image de Ubuntu,
télécharger une &quot;Kedora&quot;. Vous avez simplement utilisé
le liveCD gnome, comme vous auriez pu prendre le liveCD KDE de
Fedora. Sinon, le DVD propose les deux bureaux (puisque vous parlez
des dvd comme un point positif pour OpenSuse ...).
&lt;/p&gt;
&lt;p&gt;Bref, j'espère vous avoir montré que
votre &quot;article&quot; n'a rien de professionnel, et n'a pas fait
l'objet d'un réel travail (la bourde sur le panneau de contrôle de
compiz est franchement énorme, et a du mal à passer !). Voir que
l'un des auteurs est rédacteur en chef du magazine me fait peur.
Utilisant Fedora et m'investissant un peu dans la communauté, j'ai
pu relever vos erreurs. Mais je me dis aujourd'hui qu'il est probable
que vous aillez fait le même genre d'article sur des sujets auxquels
je ne connais rien, et que je me sois fait &quot;avoir&quot; comme
vous aurez bien eu les gens qui ne connaissent pas Fedora et a qui
vous aurez fourni un tas de fausses informations.
&lt;/p&gt;
&lt;p&gt;Je ne sais pas comment vous réagirez à
ce message, vous n'hésitez pas de temps en temps à publier des
courriers négatifs de vos lecteurs, ce qui est plutôt une bonne
chose. Le mien est bien long et nécessiterait quelque pages.
Cependant les erreurs ayant été grosses, je trouve normal que des
utilisateurs de Fedora puissent avoir un droit de réponse, et
surtout rectifier les choses. J'ai donc rédigé un article sur mon
blog (http://blog.nicoleau-fabien.net/index.php?post/2011/01/22/R%C3%A9ponse-%C3%A0-l-article-Fedora-vs-OpenSuse-vs-Ubuntu-du-Linux-Planet-63), diffusé aussi sur le planet
fedora francophone. Thomas Canniot en a aussi rédigé un, diffusé
sur plusieurs planet, et reprends de façon constructive les points
qui ont manqué pour que votre article puisse avoir un réel sens
(http://blog.mrtomlinux.org/index.php?post/Plan%C3%A8te-Linux-%3A-num%C3%A9ro-de-janvier-2011-d%C3%A9cevant-!).
Il pose d'ailleurs une bonne question : pourquoi ne pas être venus
nous voir ? Je pense que vous vous devez au moins de rectifier les
choses dans votre prochain numéro, notamment à propos du centre de
contrôle. Une réaction plus positive, et constructive, serait de
proposer dans un futur numéro une réelle présentation de Fedora,
avec un réel investissement, un rapprochement avec la communauté,
et de mettre en évidence sa philosophie, qui fait d'elle une
distribution à part. D'ailleurs, toutes les distributions
mériteraient cela, pas seulement Fedora.
&lt;/p&gt;
&lt;p&gt;C'est la première fois que je vous
écris, je me permets donc d'enchainer sur un avis à propos de votre
magazine :
&lt;/p&gt;
&lt;p&gt;contrairement à ce que vous aurez peut
être pu penser, je ne suis pas un &quot;anti ubuntu&quot;, ou &quot;anti
OpenSuse&quot;, qui sont deux distribution que j'ai utilisées et
appréciées. Cependant je regrette que tous vos articles tournent
autour de ubuntu, ça en est exaspérant. Bien sur vous présentez
d'autres distributions, mais lorsqu'il s'agit de parler d'un
logiciel, de son installation, c'est toujours sous ubuntu (à une
époque c'était mandrake). Moi, comme beaucoup d'autres personnes,
je ne suis pas utilisateur de ubuntu. Est ce une tare au point de ne
pas avoir le droit de temps en temps d'avoir UN article qui ne se
base pas sur Ubuntu. Bien sur en parlant de ubuntu, vous touchez le
plus de monde, mais les autres ? Toutes les distributions ont des
choses à proposer, et je trouve dommage que vous tombiez dans la
facilité de toujours rester sur la même distro. Vous dites parfois
que c'est &quot;plus simple&quot;, mais ça en devient lassant. Vous
rencontrez aussi des problèmes sous ubuntu, et vous fournissez des
solutions. Pourquoi ne pas en fournir pour les autres
distributions&amp;nbsp;? Linux est considéré comme un système
alternatif, mais bientôt, les gens, à force de lire vos articles,
penseront que mandriva, opensuse, fedora, et bien d'autres, sont des
distributions secondaires par rapport à ubuntu. Ce serait des
alternatives à Ubuntu, dans un système alternatif à Windows.
&lt;/p&gt;
&lt;p&gt;Il est évidemment difficile de
connaitre toutes les distributions, et de pouvoir changer chaque
semaine. Cela doit prendre beaucoup de temps. Mais je regrette que
vous ne sembliez pas essayer. Si les choses sont moins faciles
ailleurs, alors ça ne vaut pas le coup de chercher et fournir une
solution ? Vous pourriez vous aussi être une source de documentation
et un fournisseur francophone d'aide, comme vous semblez y tenir. Il
est bien loin le temps ou j'avais sur mon bureau quelques numéros de
linux planet avec des marques pages partout parce qu'il y avait la
petite astuce qui résolvait mon souci. J'ai de plus en plus
l'impression de lire &quot;Ubuntu planet&quot;. C'est très bien
ubuntu, et c'est très bien que les utilisateurs puissent lire vos
articles et utiliser facilement les commandes que vous fournissez.
Mais moi je n'utilise pas Ubuntu, et j'aimerai avoir un magazine
comme il l'était avant, quand il mettait en avant la diversité de
Linux, et de tout ce que ce système offre.
&lt;/p&gt;
&lt;p&gt;J'ai tous vos numéros depuis le #23,
mais suite à cet article, et la sensation de ne pas être &quot;le
bon lecteur puisque je n'ai pas la bonne distro&quot;, je ne pense
pas que je renouvellerai mon abonnement.
&lt;/p&gt;
&lt;p&gt;Fabien Nicoleau
&lt;/p&gt;
&lt;p&gt;Un très fidèle lecteur, très déçu&lt;/p&gt;
&lt;/q&gt;</description>
    
    
    
      </item>
    
  <item>
    <title>Scripts JS avec Java et Rhino : mise en œuvre avec un bot IRC</title>
    <link>http://blog.nicoleau-fabien.net/index.php?post/2010/11/20/Scripts-JS-avec-Java-et-Rhino-%3A-mise-en-%C5%93uvre-avec-un-bot-IRC</link>
    <guid isPermaLink="false">urn:md5:6a96efb476727dfc853c4dcac2f4caa3</guid>
    <pubDate>Sat, 20 Nov 2010 14:18:00 +0100</pubDate>
    <dc:creator>Fabien Nicoleau</dc:creator>
        <category>Développement</category>
        <category>java</category><category>javascript</category><category>plugins</category><category>rhino</category>    
    <description>&lt;p&gt;Je montrais dans &lt;a href=&quot;http://blog.nicoleau-fabien.net/index.php?post/2010/11/16/Java-%3A-g%C3%A9rer-facilement-des-plugins-JavaScript&quot;&gt;mon billet précédent&lt;/a&gt; que grâce à &lt;a hreflang=&quot;en&quot; href=&quot;http://www.mozilla.org/rhino/&quot;&gt;Rhino&lt;/a&gt; il est possible d'exécuter du code &lt;strong&gt;JavaScript&lt;/strong&gt; depuis un programme &lt;strong&gt;Java&lt;/strong&gt;, et comment il possible de se servir de ce système pour gérer des &lt;strong&gt;plugins&lt;/strong&gt;. Je propose dans ce billet de mettre en œuvre ces fonctionnalités et de les appliquer à un projet simple : un robot &lt;em&gt;IRC&lt;/em&gt; modulaire. Le principe est d'avoir un robot écrit en &lt;strong&gt;Java&lt;/strong&gt; et capable de se connecter à un serveur &lt;em&gt;IRC&lt;/em&gt;, puis de communiquer avec lui (envoi et réception de messages). Nous n'ajouterons rien à ce programme &lt;strong&gt;Java&lt;/strong&gt;, aucun savoir faire pour ce robot, à une exception prêt : la possibilité de stocker des &lt;strong&gt;plugins&lt;/strong&gt; qui lui permettront d'avoir de nouvelles fonctionnalités. Attention, le sujet de ce billet n'étant pas le codage d'un robot &lt;em&gt;IRC&lt;/em&gt; (il y en a &lt;a hreflang=&quot;en&quot; href=&quot;http://blog.nicoleau-fabien.net/index.php?pages/trustyRC&quot;&gt;de meilleurs&lt;/a&gt; pour ca ^^), celui présenté ici est ultra simple, et se contente du minimum.&lt;/p&gt;
&lt;p&gt;Pour comprendre ce programme, il faut avoir quelques &lt;a href=&quot;http://blog.nicoleau-fabien.net/index.php?post/2010/11/16/Java-%3A-g%C3%A9rer-facilement-des-plugins-JavaScript&quot;&gt;notions sur Rhino/Java&lt;/a&gt;, des notions sur les &lt;a hreflang=&quot;en&quot; href=&quot;http://download.oracle.com/javase/tutorial/essential/regex/&quot;&gt;expressions régulières&lt;/a&gt;, et notamment les &lt;a hreflang=&quot;en&quot; href=&quot;http://download.oracle.com/javase/6/docs/api/java/util/regex/Matcher.html#group%28%29&quot;&gt;groups&lt;/a&gt; qui seront bien utiles ici, et savoir en gros ce qu'est un &lt;a hreflang=&quot;fr&quot; href=&quot;http://fr.wikipedia.org/wiki/Client_IRC&quot;&gt;client IRC&lt;/a&gt;.&lt;/p&gt;    &lt;h2&gt;Le décor&lt;/h2&gt;
&lt;p&gt;Le programme sera donc codé en &lt;strong&gt;Java&lt;/strong&gt;. Une classe &lt;em&gt;JIrcRobot&lt;/em&gt; se chargera de se connecter au serveur &lt;em&gt;IRC&lt;/em&gt;, et de communiquer avec lui. Une &lt;a hreflang=&quot;en&quot; href=&quot;http://en.wikipedia.org/wiki/Interface_%28Java%29&quot;&gt;interface&lt;/a&gt; permettra de définir les méthodes à implémenter par les &lt;em&gt;plugins&lt;/em&gt;. Elle sera originalement nommée &lt;strong&gt;Plugin&lt;/strong&gt;. La classe &lt;em&gt;JIrcRobot &lt;/em&gt;chargera les &lt;em&gt;plugins &lt;/em&gt;disponibles, c'est à dire ceux contenus dans le dossier originalement nommé &lt;strong&gt;plugins &lt;/strong&gt;et dont l'extension est &lt;em&gt;.js&lt;/em&gt;, puisqu'ils contiennent du code &lt;strong&gt;JavaScript&lt;/strong&gt;. Cela permettra aussi de pouvoir désactiver le chargement d'un plugin en modifiant simplement son extension. Une fois les plugins chargés, le programme attendra des messages du serveur. A chaque message reçu, il interrogera tout ses &lt;em&gt;plugins &lt;/em&gt;pour savoir si l'un d'eux est concerné par le message. Si c'est le cas, le &lt;em&gt;plugin &lt;/em&gt;sera alors exécuté et pourra alors réagir en envoyant des messages au serveur &lt;em&gt;IRC&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;Le test&lt;/h2&gt;
&lt;p&gt;Pour ceux qui préfèrent voir les choses fonctionner tout de suite, et voir comment ca marche, je vous propose de tester tout de suite le programme. Il vous faut récupérer tous les fichiers en annexe de ce programme : le fichier &lt;strong&gt;JIrcRobot.java&lt;/strong&gt; ainsi que tous les fichiers en &lt;em&gt;.js&lt;/em&gt;, qui seront à mettre dans un dossier nommé &lt;strong&gt;plugins&lt;/strong&gt;. &lt;strong&gt;JIrcRobot.java&lt;/strong&gt; sera à mettre au même niveau d'arborescence que le dossier &lt;strong&gt;plugins&lt;/strong&gt;. Vous pouvez sinon juste prendre le fichier &lt;strong&gt;jircrobot.tar.gz&lt;/strong&gt; et le décompresser. &lt;/p&gt;
&lt;p&gt;Ouvrez ensuite le fichier &lt;strong&gt;JIrcRobot.java&lt;/strong&gt; et éditez les paramètres de connexion, situés sous le commentaire &quot;&lt;strong&gt;CONFIGURATION DE LA CONNEXION AU SERVEUR&lt;/strong&gt;&quot; pour donner un pseudonyme au robot, lui indiquer sur quel serveur il doit se connecter, et quels canaux il doit rejoindre. Sauvegardez les modifications et compilez le programme :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;javac JIrcRobot.java&lt;/p&gt;
&lt;p&gt;Vous pouvez maintenant l'exécuter :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;java JIrcRobot&lt;/p&gt;
&lt;p&gt;Le robot charge les &lt;em&gt;plugins &lt;/em&gt;puis se connecte au serveur. En l'état actuel, le robot est capable de répondre aux &lt;em&gt;PING &lt;/em&gt;du serveur, afin qu'il ne coupe pas la connexion, de rejoindre des canaux de discussion, de se présenter quand il rejoint un canal et souhaiter la bienvenue à ceux qui arrivent ensuite, de se couper si quelqu'un tape &quot;!QUIT&quot; et enfin de crier &quot;COCORICO&quot; si une phrase contient &quot;france&quot;. Ces fonctionnalités sont toutes apportées par les &lt;em&gt;plugins&lt;/em&gt;. Le programme &lt;strong&gt;Java &lt;/strong&gt;en lui même ne sait rien faire de tout ca.&lt;/p&gt;
&lt;h2&gt;La classe JIrcRobot&lt;/h2&gt;
&lt;p&gt;Il est maintenant temps de comprendre comment tout cela fonctionne. Je passe rapidement sur les fonctionnalités liées au protocole &lt;em&gt;IRC&lt;/em&gt;. Sans entrer dans le code, il faut juste savoir que la classe propose ces méthodes :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;&lt;strong&gt;connect&lt;/strong&gt;() : se connecte au serveur IRC&lt;br /&gt;&lt;strong&gt;getNickName&lt;/strong&gt;() : renvoie le pseudonyme du robot&lt;br /&gt;&lt;strong&gt;joinChannels&lt;/strong&gt;() : envoie les commandes au serveur IRC pour rejoindre des canaux de discussion&lt;br /&gt;&lt;strong&gt;loadPlugins&lt;/strong&gt;() : charge tous les plugins disponibles dans un dossier&lt;br /&gt;&lt;strong&gt;readLine&lt;/strong&gt;() : lis un message provenant du serveur, s'il y en a un d'arrivé&lt;br /&gt;&lt;strong&gt;run&lt;/strong&gt;() : boucle conservant la connexion avec le serveur, et exécutant les plugins si besoin&lt;br /&gt;&lt;strong&gt;setStayConnected&lt;/strong&gt;() : permet d'indiquer si l'on souhaite rester connecté au serveur ou non&lt;br /&gt;&lt;strong&gt;write&lt;/strong&gt;() : envoi un message au serveur IRC&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;Les méthodes importantes seront détaillées ensuite : &lt;strong&gt;loadPlugins &lt;/strong&gt;et &lt;strong&gt;run&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Enfin la classe contient une interface privée, &lt;strong&gt;Plugin&lt;/strong&gt;, qui permet de définir les méthodes que devront implémenter les &lt;em&gt;plugins &lt;/em&gt;:&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;&lt;strong&gt;getPattern&lt;/strong&gt;() : retournera l'&lt;em&gt;expression régulière&lt;/em&gt; qui si elle est validée, indiquera que le &lt;em&gt;plugin &lt;/em&gt;doit réagir au message arrivé&lt;br /&gt;&lt;strong&gt;patternMatch&lt;/strong&gt;() : cette méthode sera appelée si l'expression régulière du plugin &lt;em&gt;match &lt;/em&gt;avec le message arrivé&lt;/p&gt;
&lt;p&gt;Nos &lt;em&gt;plugins &lt;/em&gt;devront donc implémenter ces deux méthodes. &lt;/p&gt;
&lt;h2&gt;Le programme Java&lt;/h2&gt;
&lt;p&gt;Après avoir vu les méthodes permettant de dialoguer avec le serveur, intéressons nous, dans le détail cette fois-ci, au code des deux principales. Avant cela, un rapide coup d'œil à la méthode &lt;em&gt;main&lt;/em&gt; du programme :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;public static void main(String[] args) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; JIrcRobot jir = new JIrcRobot();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; jir.loadPlugins(&quot;plugins&quot;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (jir.connect()) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; jir.run();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;}&lt;/p&gt;
&lt;p&gt;Rien de complexe : on créé un objet &lt;strong&gt;JIrcRobot&lt;/strong&gt;, on charge les &lt;em&gt;plugins&lt;/em&gt;, on connecte le robot au serveur &lt;em&gt;IRC&lt;/em&gt;, et enfin on se met en attente de réception des messages avec la méthode &lt;em&gt;run&lt;/em&gt;(). Il est maintenant temps de voir comment sont chargés les &lt;em&gt;plugins&lt;/em&gt;, avec la méthode &lt;strong&gt;loadPlugins &lt;/strong&gt;;&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;public void loadPlugins(String folder) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ScriptEngine engine;&lt;br /&gt;&amp;nbsp; &amp;nbsp; Invocable inv;&lt;br /&gt;&amp;nbsp; &amp;nbsp; File dir = new File(folder);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; for (File file : dir.listFiles()) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (file.isFile() &amp;amp;&amp;amp; file.getName().toLowerCase().endsWith(&quot;.js&quot;)) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; try {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; engine = new ScriptEngineManager().getEngineByName(&quot;JavaScript&quot;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; engine.put(&quot;robot&quot;, this);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; engine.eval(new FileReader(file.getAbsolutePath()));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; inv = (Invocable) engine;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.plugins.add(inv.getInterface(Plugin.class));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; System.out.println(file.getAbsolutePath() + &quot; loaded.&quot;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } catch (Exception e) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; e.printStackTrace();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;}&lt;/p&gt;
&lt;p&gt;Cette méthode va lister (&lt;a hreflang=&quot;en&quot; href=&quot;http://download.oracle.com/javase/6/docs/api/java/io/File.html#listFiles%28%29&quot;&gt;listFiles&lt;/a&gt;) le dossier dont le nom lui est passé en paramètre (&lt;em&gt;folder&lt;/em&gt;). Pour chaque fichier dont l'extension est &lt;em&gt;.js&lt;/em&gt; (&lt;a hreflang=&quot;en&quot; href=&quot;http://download.oracle.com/javase/6/docs/api/java/lang/String.html&quot;&gt;endsWith&lt;/a&gt;), elle créé un moteur de &lt;strong&gt;JavaScript &lt;/strong&gt;(&lt;a hreflang=&quot;en&quot; href=&quot;http://download.oracle.com/javase/6/docs/api/javax/script/ScriptEngineManager.html#getEngineByName%28java.lang.String%29&quot;&gt;getEngineByName&lt;/a&gt;) et place dans l'environnement du script une variable nommée &lt;strong&gt;robot &lt;/strong&gt;pointant sur l'objet &lt;strong&gt;JIrcRobot &lt;/strong&gt;(&lt;a hreflang=&quot;en&quot; href=&quot;http://download.oracle.com/javase/6/docs/api/javax/script/ScriptEngine.html#put%28java.lang.String,%20java.lang.Object%29&quot;&gt;put&lt;/a&gt;). Ensuite elle lit le contenu du fichier et stocke dans le tableau &lt;strong&gt;plugins &lt;/strong&gt;une instanciation de l'interface &lt;strong&gt;Plugin &lt;/strong&gt;provenant du fichier (&lt;a hreflang=&quot;en&quot; href=&quot;http://download.oracle.com/javase/6/docs/api/javax/script/Invocable.html#getInterface%28java.lang.Class%29&quot;&gt;getInterface&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Le chargement des &lt;strong&gt;plugins &lt;/strong&gt;consiste donc à stocker des objets implémentant l'interface &lt;strong&gt;Plugin &lt;/strong&gt;et dont le contenu provient des fichiers &lt;strong&gt;JavaScript&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Maintenant, la méthode &lt;strong&gt;run &lt;/strong&gt;:&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;public void run() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; String buffer;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Matcher matcher;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; while (this.stayConnected) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; buffer = this.readLine();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (!buffer.equals(&quot;&quot;)) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; System.out.println(buffer);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; for (Plugin p : this.plugins) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; matcher = Pattern.compile(p.getPattern()).matcher(buffer);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (matcher.find()) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; p.patternMatch(matcher);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;}&lt;/p&gt;
&lt;p&gt;Cette méthode contient une boucle qui attend un message du serveur &lt;em&gt;IRC &lt;/em&gt;(&lt;a hreflang=&quot;en&quot; href=&quot;http://download.oracle.com/javase/6/docs/api/java/io/BufferedReader.html#readLine%28%29&quot;&gt;readLine&lt;/a&gt;). Une fois qu'un message est reçu, elle boucle sur tous les &lt;strong&gt;plugins&lt;/strong&gt; chargés. Pour chacun d'eux, elle teste si le &lt;em&gt;pattern &lt;/em&gt;du &lt;em&gt;plugin &lt;/em&gt;(&lt;em&gt;p.getPattern()&lt;/em&gt;) &lt;em&gt;match &lt;/em&gt;avec le message reçu (&lt;em&gt;buffer&lt;/em&gt;). Si c'est le cas (&lt;a hreflang=&quot;en&quot; href=&quot;http://download.oracle.com/javase/6/docs/api/java/util/regex/Matcher.html#find%28%29&quot;&gt;find&lt;/a&gt;), la méthode &lt;em&gt;patterMatch&lt;/em&gt;() du &lt;em&gt;plugin &lt;/em&gt;est appellée et on lui passe en paramètre le &lt;em&gt;matcher&lt;/em&gt;, ce qui permettra au &lt;em&gt;plugin &lt;/em&gt;d'analyser les groupes capturés grâce à &lt;em&gt;l'expression régulière&lt;/em&gt;. C'est assez pratique car le &lt;em&gt;plugin &lt;/em&gt;reçoit ainsi seulement ce qui l'intéresse, et qu'il a lui-même spécifié dans la &lt;em&gt;regex&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;C'est ici que s'arrête le détail ! Nous avons un système qui stocke des &lt;em&gt;plugins &lt;/em&gt;et un autre qui communique avec eux pour savoir s'il faut les solliciter (grâce à un système de &lt;em&gt;regex &lt;/em&gt;ici, mais ca pourrait être autrement) et qui qui les exécute si besoin. Ce robot &lt;em&gt;IRC &lt;/em&gt;est donc ainsi fait d'un noyau, disposant de peu de fonctionnalités, mais extensible à volonté.&lt;/p&gt;
&lt;h2&gt;Les plugins&lt;/h2&gt;
&lt;p&gt;Notre programme étant prêt, concentrons nous maintenant sur les &lt;em&gt;plugins&lt;/em&gt;. Nous créerons un fichier par &lt;em&gt;plugin&lt;/em&gt;.&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;ping.js&lt;/h3&gt;
&lt;p&gt;Le serveur &lt;em&gt;IRC &lt;/em&gt;envoie régulièrement un message &lt;strong&gt;PING &lt;/strong&gt;auquel le client doit répondre. Si la réponse n'est pas envoyée dans un certain laps de temps, le serveur rompt la connexion. Ce &lt;em&gt;plugin &lt;/em&gt;est donc vital. Le message est du type &quot;&lt;em&gt;PING :msg&lt;/em&gt;&quot;. Le client doit répondre &quot;&lt;em&gt;PONG :msg&lt;/em&gt;&quot;. &lt;strong&gt;msg &lt;/strong&gt;est parfois le nom du serveur, ou parfois un numéro aléatoire. Pour un &lt;strong&gt;PING &lt;/strong&gt;reçu, on récupèrera donc la partie droite, et on s'en servira pour envoyer le &lt;strong&gt;PONG&lt;/strong&gt;. Voici le contenu de &lt;em&gt;ping.js&lt;/em&gt; :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;importClass(java.util.regex.Matcher);&lt;br /&gt;&lt;br /&gt;function getPattern() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return 'PING\\s:(.*)';&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function patternMatch(matcher) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; robot.write(&quot;PONG :&quot; + matcher.group(1));&lt;br /&gt;}&lt;/p&gt;
&lt;p&gt;On commence par importer la classe Java &lt;a hreflang=&quot;en&quot; href=&quot;http://download.oracle.com/javase/6/docs/api/java/util/regex/Matcher.html&quot;&gt;Matcher&lt;/a&gt;. On implémente ensuite les deux méthodes nécessaires de l'interface &lt;strong&gt;Plugin&lt;/strong&gt;. Le regex renvoyé par &lt;strong&gt;getPattern &lt;/strong&gt;contient un groupe qui capturera la partie à renvoyer par le &lt;strong&gt;PONG&lt;/strong&gt;. La fonction &lt;strong&gt;patternMatch &lt;/strong&gt;qui est appelée si le regex a &lt;em&gt;matché &lt;/em&gt;envoie le &lt;strong&gt;PONG &lt;/strong&gt;suivi du groupe capturé dans le &lt;strong&gt;PING&lt;/strong&gt;. Pour cela elle utilise la variable &lt;strong&gt;robot &lt;/strong&gt;représentant l'objet &lt;strong&gt;JIrcRobot&lt;/strong&gt; pour envoyer un message au serveur.&lt;/p&gt;
&lt;h3&gt;endOfMOTD.js&lt;/h3&gt;
&lt;p&gt;Le &lt;strong&gt;Message Of The Day&lt;/strong&gt; (&lt;em&gt;MOTD&lt;/em&gt;) est un texte envoyé par le serveur au client lorsqu'il se connecte. Il contient souvent des informations sur le serveur. Une fois le &lt;em&gt;MOTD &lt;/em&gt;envoyé, le serveur envoie un message indiquant la fin du &lt;em&gt;MOTD &lt;/em&gt;du type : &quot;:calvino.freenode.net 376 jircrobot :End of /MOTD command.&quot;. Il est important de réagir à ce message car certains serveurs n'autorisent pas le client à rejoindre des canaux tant que le &lt;em&gt;MOTD &lt;/em&gt;n'a pas été envoyé. En attendant la réception de ce message pour rejoindre des canaux, on est sûr qu'on ne sera pas bloqué. Ce &lt;em&gt;plugin &lt;/em&gt;réagira donc à ce message, et une fois reçu, appellera la méthode &lt;strong&gt;joinChannels &lt;/strong&gt;de la classe &lt;strong&gt;JIrcRobot&lt;/strong&gt; :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;importClass(java.util.regex.Matcher);&lt;br /&gt;&lt;br /&gt;function getPattern() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return ':.*\\s376\\s.*';&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function patternMatch(matcher) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; robot.joinChannels();&lt;br /&gt;}&lt;/p&gt;
&lt;p&gt;C'est assez simple ici encore. On donne la &lt;em&gt;regex &lt;/em&gt;pour capturer la fin du &lt;em&gt;MOTD &lt;/em&gt;et lorsque que le message est arrivé, on utilise la variable &lt;strong&gt;robot &lt;/strong&gt;pour se connecter aux canaux.&lt;/p&gt;
&lt;h3&gt;quit.js&lt;/h3&gt;
&lt;p&gt;Ce &lt;em&gt;plugin &lt;/em&gt;permettra de stopper le bot. Lorsqu'une personne tapera &lt;strong&gt;!QUIT&lt;/strong&gt; sur un canal, le robot se stoppera. Biensûr dans le cadre d'un &quot;vrai&quot; bot, il faudrait s'assurer que la personne voulant couper le robot en a le droit, en se basant sur son nom d'hôte ou son pseudonyme. Le message envoyé par le serveur sera du type &quot;:someone!~someident@some-host.com PRIVMSG #channel1 :!QUIT&quot;. Voici le contenu du plugin :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;importClass(java.util.regex.Matcher);&lt;br /&gt;&lt;br /&gt;function getPattern() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return ':.*\\sPRIVMSG\\s[^ ]+\\s:!QUIT';&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function patternMatch(matcher) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; robot.setStayConnected(false);&lt;br /&gt;}&lt;/p&gt;
&lt;p&gt;La &lt;em&gt;regex &lt;/em&gt;ne capture rien ici car on ne gère pas de droits. Pour quelque chose de plus sécurisé, il faudrait capturer au moins le pseudonyme de la personne. La fonction appelée utilisera la méthode &lt;strong&gt;setStayConnected &lt;/strong&gt;avec &lt;strong&gt;false &lt;/strong&gt;en paramètre, ce qui aura pour effet de stopper la méthode &lt;strong&gt;run &lt;/strong&gt;du robot.&lt;/p&gt;
&lt;h3&gt;join.js&lt;/h3&gt;
&lt;p&gt;Afin de rendre notre robot un minimum sociable, ce &lt;em&gt;plugin &lt;/em&gt;aura pour tâche de le faire se présenter lorsqu'il rejoint un canal et de souhaiter la bienvenue aux nouveaux arrivants. Pour cela, il suffira de capturer les messages de type &lt;strong&gt;JOIN &lt;/strong&gt;provenant du serveur, qui sont envoyés quand une personne rejoint un canal, ou quand le bot lui même le fait. Le message est du type &quot;:nick!~ident@hostname.fr JOIN :#channel&quot;. Il suffit alors de comparer &quot;nick&quot; avec le propre pseudonyme du robot. S'il sont équivalents, c'est que c'est lui qui entre sur un canal, il doit donc se présenter. Si ce n'est pas le sien, alors il souhaite la bienvenue au nouvel arrivant. Il faudra donc capturer le pseudonyme et le nom du canal afin de s'en servir pour envoyer le message :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;importClass(java.util.regex.Matcher);&lt;br /&gt;&lt;br /&gt;function getPattern() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return ':([^!]+).*\\sJOIN\\s:([^ ]+)';&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function patternMatch(matcher) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Si c'est le robot qui JOIN&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if(matcher.group(1) == robot.getNickname()) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; robot.write(&quot;PRIVMSG &quot;+matcher.group(2)+&quot; :Salut tout le monde, je suis &quot;+matcher.group(1));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; else { // si c'est un nouvel arrivant&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; robot.write(&quot;PRIVMSG &quot;+matcher.group(2)+&quot; :Salut &quot;+matcher.group(1));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;}&lt;/p&gt;
&lt;p&gt;On voit donc la &lt;em&gt;regex &lt;/em&gt;avec les deux captures (nick + canal). Ces informations sont ensuite utilisées pour le message envoyé.&lt;/p&gt;
&lt;h3&gt;patriote.js&lt;/h3&gt;
&lt;p&gt;Un &lt;em&gt;plugin &lt;/em&gt;beaucoup moins utile, qui permettra simplement de montrer comment réagir à un texte particulier. Nous souhaitons ici que le bot montre qu'il est fier d'être français. A chaque fois que le mot France (peu importe la casse) sera écrit, il réagira. Le message reçu sera du type &quot;:someone!~someident@some-host.com PRIVMSG #channel :Vive la France&quot;. Voyons le code du &lt;em&gt;plugin &lt;/em&gt;: &lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;importClass(java.util.regex.Matcher);&lt;br /&gt;&lt;br /&gt;function getPattern() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return '(?i):[^!]+.*\\sPRIVMSG\\s([^ ]+)\\s:.*france.*';&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function patternMatch(matcher) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; robot.write(&quot;PRIVMSG &quot;+matcher.group(1)+&quot; :COCORICO !!!&quot;);&lt;br /&gt;}&lt;/p&gt;
&lt;p&gt;La &lt;em&gt;regex &lt;/em&gt;indique que la recherche sera insensible à la casse. On capture simplement le nom du canal d'où le texte est envoyé pour pouvoir répondre.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;Voilà pour quelques exemples de &lt;em&gt;plugins&lt;/em&gt;. Le but ici est de montrer que presque tout est possible, mais que surtout ce genre de programme, modulable, auquel on peut ajouter des fonctionnalités, est facilement réalisable. Pour les plus courageux qui auront lu jusque ici (j'espère que number80 en fait partie !), n'hésitez pas à poser des questions dans les commentaires. Il n'est pas facile de synthétiser tout cela en un seul billet, il y a donc probablement des passages obscurs !&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;Fabien (eponyme)&lt;/p&gt;</description>
    
          <enclosure url="http://blog.nicoleau-fabien.net/public/jircrobot/jircrobot.tar.gz"
      length="1873" type="application/x-gzip" />
          <enclosure url="http://blog.nicoleau-fabien.net/public/jircrobot/JIrcRobot.java"
      length="4200" type="text/plain" />
          <enclosure url="http://blog.nicoleau-fabien.net/public/jircrobot/endOfMOTD.js"
      length="163" type="text/javascript" />
          <enclosure url="http://blog.nicoleau-fabien.net/public/jircrobot/join.js"
      length="474" type="text/javascript" />
          <enclosure url="http://blog.nicoleau-fabien.net/public/jircrobot/patriote.js"
      length="232" type="text/javascript" />
          <enclosure url="http://blog.nicoleau-fabien.net/public/jircrobot/ping.js"
      length="181" type="text/javascript" />
          <enclosure url="http://blog.nicoleau-fabien.net/public/jircrobot/quit.js"
      length="188" type="text/javascript" />
    
    
      </item>
    
  <item>
    <title>Java : gérer facilement des plugins JavaScript</title>
    <link>http://blog.nicoleau-fabien.net/index.php?post/2010/11/16/Java-%3A-g%C3%A9rer-facilement-des-plugins-JavaScript</link>
    <guid isPermaLink="false">urn:md5:2bc10c1225d20d941fd581c986c85b11</guid>
    <pubDate>Wed, 17 Nov 2010 00:11:00 +0100</pubDate>
    <dc:creator>Fabien Nicoleau</dc:creator>
        <category>Développement</category>
        <category>java</category><category>javascript</category><category>plugins</category><category>rhino</category>    
    <description>&lt;p&gt;Dans une application, il peut être parfois intéressant d'extraire une partie de l'intelligence afin de répondre à un besoins sépcifique. Un exemple courant est une application fournie à différents clients. Elle comporte un socle commun, puis les spécificités sont développées dans des &lt;em&gt;plugins&lt;/em&gt; afin de ne pas avoir à toucher au code de l'application pour une demande particulière. L'autre intérêt est de pouvoir charger dans une application des fonctionnalités supplémentaires, permettant de réduire le poids de l'application en retirant des fonctionnalités inutilisées. Le fait d'avoir du code externe permet aussi d'en facilité les mises à jour.&lt;/p&gt;
&lt;p&gt;En &lt;a hreflang=&quot;fr&quot; href=&quot;http://fr.wikipedia.org/wiki/Java_%28langage%29&quot;&gt;Java&lt;/a&gt;, il est possible de créer des &lt;em&gt;plugins&lt;/em&gt; de différentes façons : avec des classes externes, chargées grâce à un &lt;a hreflang=&quot;en&quot; href=&quot;http://download.oracle.com/javase/6/docs/api/java/lang/ClassLoader.html&quot;&gt;ClassLoader&lt;/a&gt;, grâce à &lt;a hreflang=&quot;fr&quot; href=&quot;http://fr.wikipedia.org/wiki/Groovy_%28langage%29&quot;&gt;groovy&lt;/a&gt;, très populaire, ou encore &lt;a hreflang=&quot;fr&quot; href=&quot;http://fr.wikipedia.org/wiki/Jython&quot;&gt;jython&lt;/a&gt;, permettant d'exécuter du code &lt;a hreflang=&quot;fr&quot; href=&quot;http://fr.wikipedia.org/wiki/Python_%28langage%29&quot;&gt;Python&lt;/a&gt; depuis un programme &lt;strong&gt;Java&lt;/strong&gt;. Il existe de nombreuses autres solutions, comme celle d'utiliser le moteur &lt;a hreflang=&quot;fr&quot; href=&quot;http://fr.wikipedia.org/wiki/JavaScript&quot;&gt;JavaScript&lt;/a&gt; de la fondation &lt;a hreflang=&quot;fr&quot; href=&quot;http://www.mozilla-europe.org/fr/&quot;&gt;Mozilla&lt;/a&gt; : &lt;a hreflang=&quot;en&quot; href=&quot;http://www.mozilla.org/rhino/&quot;&gt;Rhino&lt;/a&gt;. Sa particularité est qu'il est fourni par défaut avec &lt;strong&gt;Java&lt;/strong&gt; depuis la &lt;em&gt;version 6&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;En ayant eu besoin pour un projet, et ayant trouvé peu d'aide en français, je propose ici quelques exemples très basiques afin de mettre en place un système de &lt;em&gt;plugins JavaScript&lt;/em&gt; avec &lt;strong&gt;Java&lt;/strong&gt;. 90% de l'aide dont j'ai eu besoin a été trouvée sur cette &lt;a hreflang=&quot;en&quot; href=&quot;http://download.oracle.com/javase/6/docs/technotes/guides/scripting/programmer_guide/index.html&quot;&gt;page de documentation&lt;/a&gt;. Je reprends donc ici quelques exemples, commentés, afin de comprendre le principe et d'imaginer les possibilités qu'offre &lt;strong&gt;Rhino&lt;/strong&gt;. N'hésitez pas à poser des questions dans les commentaires si vous avez besoins de précisions.&lt;/p&gt;    &lt;p&gt;Tout d'abord, je vous indique ici les &lt;em&gt;import &lt;/em&gt;dont vous aurez besoin et qui seront à utiliser tout au long des exemples (mais pas utiles pour tous). Il ne seront pas réécris ensuite, pour plus de lisibilité :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;import javax.script.Invocable;&lt;br /&gt;import javax.script.ScriptEngine;&lt;br /&gt;import javax.script.ScriptEngineManager;&lt;br /&gt;import java.io.FileReader;&lt;/p&gt;
&lt;p&gt;Toujours pour simplifier le code affiché, les &lt;em&gt;exceptions&lt;/em&gt; ne seront pas gérées, mais renvoyées par le &lt;em&gt;main&lt;/em&gt;. Il vous faut évidemment avoir quelques bases de &lt;strong&gt;Java&lt;/strong&gt; et de &lt;strong&gt;JavaScript&lt;/strong&gt; pour pouvoir suivre ces exemples. Dans chacun d'eux, j'utiliserai des fonctions &lt;em&gt;JavaScript&lt;/em&gt;. Si vous préférez utiliser du code orienté objet, il vous sera facile de l'adapter grâce aux exemples de la page &lt;em&gt;Oracle&lt;/em&gt; citée en préambule.&lt;/p&gt;
&lt;p&gt;Enfin, pour chaque exemple, je n'afficherai que la fonction &lt;em&gt;main&lt;/em&gt;, qu'il faudra évidemment que vous incluiez dans une classe pour que le tout fonctionne, cependant les sources de chaque exemples sont disponibles en annexe de ce billet.&lt;/p&gt;
&lt;h2&gt;Exemple 1 : un simple affichage &lt;/h2&gt;
&lt;p&gt;Pour le premier essai, nous allons exécuter une simple ligne de code &lt;strong&gt;JavaScript&lt;/strong&gt; dans du code &lt;strong&gt;Java&lt;/strong&gt; :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;public static void main(String[] args) throws Exception {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ScriptEngineManager manager = new ScriptEngineManager();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ScriptEngine engine = manager.getEngineByName(&quot;JavaScript&quot;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; engine.eval(&quot;println('Mon premier script !');&quot;);&lt;br /&gt;}&lt;/p&gt;
&lt;p&gt;Rien de plus ! C'est en fait assez simple. Nous commençons par instancier un &lt;a hreflang=&quot;en&quot; href=&quot;http://download.oracle.com/javase/6/docs/api/javax/script/ScriptEngineManager.html&quot;&gt;ScriptEngineManager&lt;/a&gt; qui nous permettra de charger le moteur de script souhaité. Nous l'utilisons sur la deuxième ligne : nous chargeons le moteur &lt;strong&gt;JavaScript&lt;/strong&gt;. Aucune installation de bibliothèque nécessaire, car ce moteur est fourni avec &lt;strong&gt;&lt;em&gt;Java 6&lt;/em&gt;&lt;/strong&gt; ! Ces deux premières lignes seront utilisées dans tous nos exemples. Nous terminons en demandant à notre moteur d'évaluer une ligne de code, ici l'affichage du texte &quot;Mon premier script !&quot;.&lt;/p&gt;
&lt;p&gt;Après compilation et exécution, la ligne s'affiche bien. Rien de transcendant ici, mais nous voyons que nous allons facilement pouvoir exécuter du code &lt;strong&gt;JavaScript&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;Exemple 2 : interagir avec un script externe&lt;/h2&gt;
&lt;p&gt;Dans l'optique d'utiliser un système de &lt;em&gt;plugins&lt;/em&gt;, il nous faut d'abord pouvoir sortir le code &lt;strong&gt;JavaScript&lt;/strong&gt; du code &lt;strong&gt;Java&lt;/strong&gt;, et le placer dans un fichier externe. De plus il nous faut pouvoir appeler une fonction en lui passant des paramètres, puis pouvoir récupérer le résultat obtenu.&lt;/p&gt;
&lt;p&gt;Pour illustrer l'exemple, nous allons imaginer un programme &lt;strong&gt;Java&lt;/strong&gt; qui passe à une fonction nommée &lt;em&gt;compute()&lt;/em&gt; deux chiffres qu'elle traitera. Le code &lt;strong&gt;Java&lt;/strong&gt; récupèrera le résultat du traitement effectué par &lt;em&gt;compute()&lt;/em&gt; et l'affichera. Enfin, nous allons créer deux plugins &lt;strong&gt;JavaScript&lt;/strong&gt; qui implémenteront tous les deux la fonction &lt;em&gt;compute()&lt;/em&gt;. L'un fera une addition (plus.js) des deux chiffres donnés, l'autre une soustraction (moins.js). On commence par le code &lt;strong&gt;Java&lt;/strong&gt; :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;public static void main(String[] args) throws Exception {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ScriptEngineManager manager = new ScriptEngineManager();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ScriptEngine engine = manager.getEngineByName(&quot;JavaScript&quot;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; engine.eval(new FileReader(&quot;plus.js&quot;));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Invocable inv = (Invocable) engine;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; System.out.println(inv.invokeFunction(&quot;compute&quot;,3,2));&lt;br /&gt;}&lt;/p&gt;
&lt;p&gt;Comme dans le premier exemple, nous récupérons le moteur &lt;strong&gt;JavaScript&lt;/strong&gt;. Ensuite plutôt que directement évaluer du code, nous passons un fichier à la fonction &lt;a hreflang=&quot;en&quot; href=&quot;http://download.oracle.com/javase/6/docs/api/javax/script/ScriptEngine.html#eval%28java.io.Reader%29&quot;&gt;eval()&lt;/a&gt;, qui contiendra notre code &lt;strong&gt;JavaScript&lt;/strong&gt;. Nous commençons ici par &lt;em&gt;plus.js&lt;/em&gt;, qui fera une addition. Vous pourrez ensuite utiliser &lt;em&gt;moins.js&lt;/em&gt;. Enfin, nous invoquons la fonction &lt;em&gt;compute()&lt;/em&gt; et lui passons deux arguments (3 et 2). Nous récupérons le résultat du traitement, qui est un &lt;a hreflang=&quot;en&quot; href=&quot;http://download.oracle.com/javase/6/docs/api/java/lang/Object.html&quot;&gt;Object&lt;/a&gt;, et qui contiendra ici un chiffre (un &lt;a hreflang=&quot;en&quot; href=&quot;http://download.oracle.com/javase/6/docs/api/java/lang/Double.html&quot;&gt;Double&lt;/a&gt; à vrai dire), nous l'affichons directement.&lt;/p&gt;
&lt;p&gt;Voici le contenu de plus.js :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;function compute(a,b) {&lt;br /&gt;&amp;nbsp;&amp;nbsp; return a+b;&lt;br /&gt;}&lt;/p&gt;
&lt;p&gt;Celui de moin.js :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;function compute(a,b) {&lt;br /&gt;&amp;nbsp;&amp;nbsp; return a-b;&lt;br /&gt;}&lt;/p&gt;
&lt;p&gt;Aucun commentaire nécessaire ! Exécutez le programme avec plus.js, puis moins.js, les résultats seront 5.0 puis 1.0. &lt;/p&gt;
&lt;p&gt;Nous voyons ici que nous pouvons très facilement avoir du code &lt;strong&gt;Java&lt;/strong&gt; qui exécute une fonction dont il ne connait pas le contenu. Il en récupère le résultat sous forme d'un objet et peut le traiter. D'un autre coté, nous avons des fichiers contenant du code &lt;strong&gt;JavaScript&lt;/strong&gt; qui traitent de façon différente deux arguments identiques, et renvoient le résultat. Dans une application gérant des &lt;em&gt;plugins&lt;/em&gt;, il suffit alors que le nom du fichier &lt;strong&gt;JavaScript&lt;/strong&gt; soit une variable, ou provienne d'un choix de l'utilisateur, et le tour est joué ! Attention tout de même, pour un système robuste, il est important de gérer les exceptions afin de réagir aux problèmes qui pourraient survenir.&lt;/p&gt;
&lt;h2&gt;Exemple 3 : Exporter des variables dans le script externe&lt;/h2&gt;
&lt;p&gt;Lorsque l'on mets en place un système de &lt;em&gt;plugins&lt;/em&gt;, on souhaite que ces derniers puissent avoir accès aux informations de l'application, souvent par l'intermédiaire d'un noyau depuis lequel on accède à des variables. De cette manière le &lt;em&gt;plugin&lt;/em&gt; agit de façon directe avec l'application, en consultant des informations, et en les mettant à jour. Nous allons dans cet exemple voir qu'il est tout à fait possible de faire cela avec &lt;strong&gt;Java&lt;/strong&gt; et &lt;strong&gt;Rhino&lt;/strong&gt;. Nous allons créer une classe &lt;em&gt;Afficheur&lt;/em&gt; contenant la méthode &lt;em&gt;affiche()&lt;/em&gt; qui se contente d'afficher dans la console une ligne de texte. Ensuite, nous allons instancier un objet de cette classe et l'exporter dans notre script &lt;strong&gt;JavaScript&lt;/strong&gt;. Ce dernier utilisera dans son code l'objet exporté et appellera la méthode &lt;em&gt;affiche()&lt;/em&gt; :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;private static class Afficheur {&lt;br /&gt;&amp;nbsp;&amp;nbsp; public void affiche() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; System.out.println(&quot;J'affiche !&quot;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;}&lt;br /&gt;public static void main(String[] args) throws Exception {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ScriptEngineManager manager = new ScriptEngineManager();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ScriptEngine engine = manager.getEngineByName(&quot;JavaScript&quot;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; engine.eval(new FileReader(&quot;afficheur.js&quot;));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Afficheur aff = new Afficheur();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; engine.put(&quot;monAfficheur&quot;,aff);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Invocable inv = (Invocable) engine;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; inv.invokeFunction(&quot;affiche&quot;);&lt;br /&gt;}&lt;/p&gt;
&lt;p&gt;On voit ici qu'une fois l'objet &lt;em&gt;Afficheur&lt;/em&gt; instancié, on l'exporte dans le script grace à la méthode &lt;a hreflang=&quot;en&quot; href=&quot;http://download.oracle.com/javase/6/docs/api/javax/script/ScriptEngine.html#put%28java.lang.String,%20java.lang.Object%29&quot;&gt;put()&lt;/a&gt;. On indique que le nom de variable par laquelle l'objet sera accessible dans le script sera &quot;monAfficheur&quot;. Enfin on appelle la fonction &lt;em&gt;affiche()&lt;/em&gt; implémentée dans le script &lt;em&gt;afficheur.js&lt;/em&gt; dont voici le contenu :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;function affiche() {&lt;br /&gt;&amp;nbsp;&amp;nbsp; monAfficheur.affiche();&lt;br /&gt;}&lt;/p&gt;
&lt;p&gt;La fonction &lt;em&gt;affiche()&lt;/em&gt; utilise donc la variable &lt;em&gt;monAfficheur&lt;/em&gt; disponnible grace à l'export fait depuis le code &lt;strong&gt;Java&lt;/strong&gt;, et appelle la méthode &lt;em&gt;affiche()&lt;/em&gt;. Voilà notre liaison réalisée ! Depuis notre code &lt;strong&gt;JavaScript&lt;/strong&gt;, nous accédons à un objet de notre application &lt;strong&gt;Java&lt;/strong&gt; et pouvons l'utiliser. Ici nous ne réalisons qu'un simple affichage, mais tout est possible. Notez qu'il est possible de définir différent &lt;em&gt;scope&lt;/em&gt; lors de l'export des variables permettant ainsi de leur donner des valeurs différentes selon le contexte utilisé lors de l'évaluation. Plus de renseignement dans &lt;a hreflang=&quot;en&quot; href=&quot;http://download.oracle.com/javase/6/docs/technotes/guides/scripting/programmer_guide/index.html#scopes&quot;&gt;la documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Exemple 4 : Implémenter une interface&lt;/h2&gt;
&lt;p&gt;Nous progressons dans les fonctionnalités proposées pour réaliser une gestion de &lt;em&gt;plugins&lt;/em&gt;. Mais il est possible d'aller plus loin, et de définir plus précisément les fonctionnalités offertes par les &lt;em&gt;plugins&lt;/em&gt;. Pour cela, nous pouvons définir en &lt;strong&gt;Java&lt;/strong&gt; une &lt;a hreflang=&quot;en&quot; href=&quot;http://en.wikipedia.org/wiki/Interface_%28Java%29&quot;&gt;interface&lt;/a&gt;, et l'implémenter depuis un &lt;em&gt;plugin&lt;/em&gt;. Une fois le code du &lt;em&gt;plugin&lt;/em&gt; évalué, nous appelons une méthode depuis le code &lt;strong&gt;Java&lt;/strong&gt;, dont l'implémentation a été réalisée depuis le code &lt;strong&gt;JavaScript&lt;/strong&gt; ! Il devient alors possible de définir proprement en &lt;strong&gt;Java&lt;/strong&gt; les méthodes qui seront à implémenter par les &lt;em&gt;plugins&lt;/em&gt;, sans en connaitre le traitement évidemment, et d'utiliser ensuite dans le code des objets instanciant cette interface. Mieux que du blabla, le code :&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;private interface Afficheur2 {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; void affiche2();&lt;br /&gt;}&lt;br /&gt;public static void main(String[] args) throws Exception {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ScriptEngineManager manager = new ScriptEngineManager();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ScriptEngine engine = manager.getEngineByName(&quot;JavaScript&quot;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; engine.eval(&quot;function affiche2() { println('affiche (2)'); }&quot;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Invocable inv = (Invocable) engine;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Afficheur2 aff = inv.getInterface(Afficheur2.class);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; aff.affiche2();&lt;br /&gt;}&lt;/p&gt;
&lt;p&gt;Pour l'exemple, je n'utilise pas de fichier externe, mais directement une ligne de code &lt;strong&gt;JavaScript&lt;/strong&gt;. Ce code implémente la méthode &lt;em&gt;affiche2()&lt;/em&gt; de l'interface &lt;em&gt;Afficheur2&lt;/em&gt; en faisant un simple affichage de ligne. Nous créons un objet de type &lt;em&gt;Afficheur2&lt;/em&gt; puis récupérons l'instanciation de l'interface grâce à la méthode &lt;a hreflang=&quot;en&quot; href=&quot;http://download.oracle.com/javase/6/docs/api/javax/script/Invocable.html#getInterface%28java.lang.Class%29&quot;&gt;getInterface()&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Enfin, nous utilisons ce nouvel objet et appelons la méthode &lt;em&gt;affiche2()&lt;/em&gt; qui effectuera ce qui a été défini dans le code &lt;strong&gt;JavaScript&lt;/strong&gt;, c'est à dire afficher une ligne de texte. &lt;/p&gt;
&lt;p&gt;Nous voyons ici qu'il nous est donc possible d'écrire du code générique et de l'utiliser. C'est grâce aux &lt;em&gt;plugins&lt;/em&gt; utilisés que instanciation est faite et nous pouvons ainsi pour un même code &lt;strong&gt;Java&lt;/strong&gt; obtenir des comportement totalement différents.&lt;/p&gt;
&lt;h2&gt;Exemple 5 : Utilisation des classes Java depuis le code JavaScript&lt;/h2&gt;
&lt;p&gt;Comme dernier exemple et pour montrer toute la puissance de &lt;strong&gt;Rhino&lt;/strong&gt;, nous créons un code Java qui se contentera d'évaluer un script :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;public static void main(String[] args) throws Exception {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ScriptEngineManager manager = new ScriptEngineManager();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ScriptEngine engine = manager.getEngineByName(&quot;JavaScript&quot;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; engine.eval(new FileReader(&quot;frame.js&quot;));&lt;br /&gt;}&lt;/p&gt;
&lt;p&gt; Le script en revanche est particulier, car il importe directement des classes &lt;strong&gt;Java&lt;/strong&gt; et utilise les objets instanciés. Le script &lt;em&gt;frame.js&lt;/em&gt; va créer une &lt;a hreflang=&quot;en&quot; href=&quot;http://download.oracle.com/javase/6/docs/api/javax/swing/JFrame.html&quot;&gt;JFrame&lt;/a&gt; et l'afficher. Il affichera aussi le titre de la fenêtre, qu'il récupère directement depuis la propriété de la &lt;em&gt;JFrame&lt;/em&gt; :&lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;importClass(javax.swing.JFrame);&lt;br /&gt;importClass(java.awt.Dimension);&lt;br /&gt;&lt;br /&gt;var frame = new JFrame(&quot;hello&quot;);&lt;br /&gt;frame.setSize(new Dimension(250,250));&lt;br /&gt;frame.setVisible(true);&lt;br /&gt;println(frame.title);&lt;/p&gt;
&lt;p&gt;Exécutez le programme, une fenêtre apparait !&lt;/p&gt;
&lt;p&gt;&lt;img title=&quot;JFrame depuis un JavaScript, nov. 2010&quot; style=&quot;margin: 0 auto; display: block;&quot; alt=&quot;JFrame depuis un JavaScript&quot; src=&quot;http://blog.nicoleau-fabien.net/public/ScriptingJava/jframe.JPG&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;Voilà pour cette petite initiation au &lt;em&gt;scripting&lt;/em&gt; avec &lt;strong&gt;Java&lt;/strong&gt; et son application avec l'utilisation de &lt;em&gt;plugins&lt;/em&gt;. Il y aurait surement beaucoup plus à dire, mais vous disposez maintenant d'une base pour débuter, et de l'alliance du &lt;strong&gt;Java&lt;/strong&gt; et du &lt;strong&gt;JavaScript&lt;/strong&gt; pour vos applications ! Ce sujet aura aussi été pour moi l'occasion de reprendre la plume sur ce blog, chose qui n'avait pas été faite depuis trop longtemps !&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;Fabien (eponyme)&lt;/p&gt;</description>
    
          <enclosure url="http://blog.nicoleau-fabien.net/public/ScriptingJava/afficheur.js"
      length="53" type="text/javascript" />
          <enclosure url="http://blog.nicoleau-fabien.net/public/ScriptingJava/frame.js"
      length="194" type="text/javascript" />
          <enclosure url="http://blog.nicoleau-fabien.net/public/ScriptingJava/moins.js"
      length="42" type="text/javascript" />
          <enclosure url="http://blog.nicoleau-fabien.net/public/ScriptingJava/plus.js"
      length="42" type="text/javascript" />
          <enclosure url="http://blog.nicoleau-fabien.net/public/ScriptingJava/Exemple1.java"
      length="364" type="text/plain" />
          <enclosure url="http://blog.nicoleau-fabien.net/public/ScriptingJava/Exemple2.java"
      length="521" type="text/plain" />
          <enclosure url="http://blog.nicoleau-fabien.net/public/ScriptingJava/Exemple3.java"
      length="717" type="text/plain" />
          <enclosure url="http://blog.nicoleau-fabien.net/public/ScriptingJava/Exemple4.java"
      length="607" type="text/plain" />
          <enclosure url="http://blog.nicoleau-fabien.net/public/ScriptingJava/Exemple5.java"
      length="383" type="text/plain" />
    
    
      </item>
    
  <item>
    <title>5 ans (et quelques mois) de fedora-fr.org !</title>
    <link>http://blog.nicoleau-fabien.net/index.php?post/2010/09/06/5-ans-%28et-quelques-mois%29-de-fedora-fr.org-%21</link>
    <guid isPermaLink="false">urn:md5:6c2655bfb9fe4eb526cc87c22c846c8e</guid>
    <pubDate>Mon, 06 Sep 2010 23:54:00 +0200</pubDate>
    <dc:creator>Fabien Nicoleau</dc:creator>
        <category>Linux</category>
            
    <description>    &lt;p&gt;Comme tous les ans depuis quelques années maintenant, je profite de mon &quot;anniversaire&quot; d'inscription sur le site &lt;a hreflang=&quot;fr&quot; href=&quot;http://www.fedora-fr.org/&quot;&gt;fedora-fr.org&lt;/a&gt; (datant du 07/07/2005) pour faire un petit bilan de mon activité autour de fedora. En relisant les billets précédents, je m'inquiete un peu de voir que ça diminue de plus en plus, mais maintenant que j'ai de nouveau ma connexion, et la motivation après une longue pause, plus d'excuses ! Voilà donc un petit tour d'horizon, à aujourd'hui :&lt;/p&gt;
&lt;h2&gt;Le forum&lt;/h2&gt;
&lt;p&gt;Je suis un lecteur assidu (et modérateur aussi parfois!), un peu moins contributeur. Je reste fidèle et continue la lecture quotidienne des sujets. J'ai aujourd'hui 2185 messages au compteur.&lt;/p&gt;
&lt;h2&gt;Le wiki&lt;/h2&gt;
&lt;p&gt;Comme l'an dernier, honte à moi ... Je n'ai toujours que deux articles à mon actif :&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://doc.fedora-fr.org/wiki/Vsftpd_:_Installation_et_configuration&quot; hreflang=&quot;fr&quot;&gt;Installation et configuration de vsftpd&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://doc.fedora-fr.org/wiki/VirtualBox_:_installation%2C_configuration%2C_utilisation&quot; hreflang=&quot;fr&quot;&gt;Installation et configuration de virtualbox&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Les cannaux IRC&lt;/h2&gt;
&lt;p&gt;J'y suis présent tous les jours, c'est d'ailleurs le meilleur moyen de me contacter. Présent pour causer .. aider.. C'est par ce biais que je reste le plus au sein de la communauté. &lt;/p&gt;
&lt;h2&gt;Packaging&lt;/h2&gt;
&lt;p&gt;J'ai au cours de cette année ajouté trois paquets à &lt;a hreflang=&quot;en&quot; href=&quot;https://admin.fedoraproject.org/pkgdb/users/packages/eponyme&quot;&gt;ma liste&lt;/a&gt; pour les dépôts de fedora :&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;&lt;a hreflang=&quot;en&quot; href=&quot;http://www.monkeystudio.org/&quot;&gt;monkeystudio&lt;/a&gt; : un EDI multi-plateformes dédié à Qt4&lt;/li&gt;
&lt;li&gt;&lt;a hreflang=&quot;en&quot; href=&quot;http://code.google.com/p/quvi/&quot;&gt;quvi&lt;/a&gt; : une bibliothèque permettant de récupérer les informations des vidéos disponnibles sur de nombreux sites de partages de vidéos (youtube &amp;amp; co) utilisée par &lt;a hreflang=&quot;en&quot; href=&quot;http://code.google.com/p/cclive/&quot;&gt;cclive&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a hreflang=&quot;en&quot; href=&quot;http://henning.makholm.net/&quot;&gt;xcftools&lt;/a&gt; : paquet fournissant quelques utilitaires permettant de récupérer des informations sur les fichiers au format .xcf&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Comme l'an dernier, c'est de ce coté que je contribue le plus, et les choses devraient continuer dans ce sens, car j'ai quelques paquets sur le feu que je proposerai certainement cette année. &lt;/p&gt;
&lt;p&gt;Même s'il n'y a pas de rapport direct, &lt;a hreflang=&quot;fr&quot; href=&quot;http://blog.nicoleau-fabien.net/index.php?post/2010/06/06/XChat-2.8.8-est-sorti%2C-la-hache-de-guerre-avec-les-balloons-est-enterr%C3%A9e-%21&quot;&gt;ma minuscule contribution à xchat a été prise en compte&lt;/a&gt; dans la dernière release, permettant enfin de rendre le temps des notifications configurable.&lt;/p&gt;
&lt;h2&gt;Mon blog&lt;/h2&gt;
&lt;p&gt;Principal reflet de mon activité, il a logiquement été peu mis à jour. J'ai cependant cette année &lt;a hreflang=&quot;fr&quot; href=&quot;http://blog.nicoleau-fabien.net/index.php?post/2010/06/06/Back-dans-les-blogs-%21-100%C3%A8me-billet&quot;&gt;passé la barre des 100 billets&lt;/a&gt;. C'est à cette occasion que j'ai mis en place un nouveau thème, sur lequel je devrais encore travailler. En tout cas dans l'état actuel il me convient bien. Le blog à donc aujourd'hui 103 billets, et 271 commentaires.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;Voila pour cette année, peu de choses à dire, mais je suis aujourd'hui de nouveau disponnible pour faire en sorte d'avoir de nouveaux chapitres à ajouter l'an prochain ;)&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;Fabien (eponyme)&lt;/p&gt;</description>
    
    
    
      </item>
    
  <item>
    <title>Petite absence ...</title>
    <link>http://blog.nicoleau-fabien.net/index.php?post/2010/07/01/Petite-absence-...</link>
    <guid isPermaLink="false">urn:md5:fc22f1fbb8f2d4b911b1908bfae6d2d5</guid>
    <pubDate>Thu, 01 Jul 2010 15:15:00 +0200</pubDate>
    <dc:creator>Fabien Nicoleau</dc:creator>
        <category>Général</category>
            
    <description>    &lt;p&gt;C'est l'été, et les vacances arrivent (enfin!). Je profite de ces quelques semaines pour déménager, et donc déplacer mon abonnement ADSL. La mauvaise nouvelle est qu'avec quelques difficultés rencontrées, je vais avoir plus d'un mois d'interruption, la bonne en revanche est que je reviendrais avec un abonnement totalement dégroupé (merci SFR!).&lt;/p&gt;
&lt;p&gt;Du coup plus de billets, plus de forums, et plus de packages pendants quelques semaines.&lt;/p&gt;
&lt;p&gt;A bientôt !&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;Fabien (eponyme)&lt;/p&gt;</description>
    
    
    
      </item>
    
  <item>
    <title>XChat 2.8.8 est sorti, la hache de guerre avec les balloons est enterrée !</title>
    <link>http://blog.nicoleau-fabien.net/index.php?post/2010/06/06/XChat-2.8.8-est-sorti%2C-la-hache-de-guerre-avec-les-balloons-est-enterr%C3%A9e-%21</link>
    <guid isPermaLink="false">urn:md5:c83612f221d46174f7d829566de2a933</guid>
    <pubDate>Sun, 06 Jun 2010 22:19:00 +0200</pubDate>
    <dc:creator>Fabien Nicoleau</dc:creator>
        <category>Linux</category>
        <category>fedora</category><category>IRC</category><category>patch</category><category>RPM</category><category>xchat</category>    
    <description>    &lt;p&gt;Il y a quelques jours, une nouvelle version du &lt;a hreflang=&quot;en&quot; href=&quot;http://forum.xchat.org/viewtopic.php?t=5515&quot;&gt;client IRC XChat est sortie&lt;/a&gt;. Cette version intègre &lt;a hreflang=&quot;fr&quot; href=&quot;http://blog.nicoleau-fabien.net/index.php?post/2008/07/20/xchat-286-et-les-balloons-l-histoire-continue&quot;&gt;le patch&lt;/a&gt; que j'avais soumis il y a quelques temps, afin de régler le problème de temps d'apparition bien trop long des notifications. C'est donc une petite satisfaction personnelle de voir dans cette release quelques lignes de codes que j'avais proposées, même si le mérite en revient plutôt à &lt;a hreflang=&quot;fr&quot; href=&quot;http://blog.famillecollet.com/&quot;&gt;Remi&lt;/a&gt; car je m'étais inspiré de &lt;a hreflang=&quot;en&quot; href=&quot;http://sourceforge.net/tracker/index.php?func=detail&amp;amp;aid=1910389&amp;amp;group_id=239&amp;amp;atid=100239&quot;&gt;son patch&lt;/a&gt; plutôt que de &lt;a hreflang=&quot;fr&quot; href=&quot;http://blog.nicoleau-fabien.net/index.php?post/2008/03/08/xchat-284-12f8eponyme&quot;&gt;mon original&lt;/a&gt; pour en proposer un nouveau.&lt;/p&gt;
&lt;p&gt;Avec la version 2.8.8, il est donc maintenant possible de régler le temps d'apparition des notifications par la commande &lt;/p&gt;
&lt;p class=&quot;tty&quot;&gt;/set input_balloon_time&lt;/p&gt;
&lt;p&gt;ou bien sûr directement dans le fichier de configuration. C'est un soulagement pour moi car je n'aurais plus à reconstruire une version du paquet avec le patch pour ne plus avoir à hurler lorsque je joue à un jeu et que des notifications viennent manger une partie de l'écran pendant 20 secondes !&lt;/p&gt;
&lt;p&gt;La version est déjà &lt;em&gt;packagée&lt;/em&gt; pour fedora, et une &lt;a hreflang=&quot;en&quot; href=&quot;https://admin.fedoraproject.org/updates/xchat-2.8.8-2.fc13&quot;&gt;demande d'envoi vers le dépôt stable&lt;/a&gt; a déjà été faite, elle apparaitra donc bientôt dans les mises à jour !&lt;/p&gt;
&lt;br /&gt;&lt;p&gt;Fabien (eponyme)&lt;/p&gt;</description>
    
    
    
      </item>
    
</channel>
</rss>