<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>Lab &amp; stacks</title>
    <link rel="alternate" type="text/html" href="http://blog.bjornoya.be/lab_stacks/" />
    <link rel="self" type="application/atom+xml" href="http://blog.bjornoya.be/lab_stacks/atom.xml" />
    <id>tag:blog.bjornoya.be,2009-07-15:/lab_stacks//1</id>
    <updated>2010-03-17T22:46:31Z</updated>
    
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type 4.261</generator>

<entry>
    <title>Sauver les images d&apos;un fichier HTML</title>
    <link rel="alternate" type="text/html" href="http://blog.bjornoya.be/lab_stacks/2010/03/sauver-les-images-dun-fichier-html.html" />
    <id>tag:blog.bjornoya.be,2010:/lab_stacks//1.26</id>

    <published>2010-03-17T22:36:32Z</published>
    <updated>2010-03-17T22:46:31Z</updated>

    <summary><![CDATA[
Il y a quelques temps maintenant, quand j'ai commencé à lire quotidiennement
sur mon ebook, j'ai rapidement souhaité être en mesure de lire des articles
provenant de web sur ma liseuse. Après un rapide tour d'horizon, je n'avais
rien trouvé à l'époque (cela remonte quand même à un petit bout de temps
maintenant), et je m'étais donc lancé dans le développement d'une solution
personnelle.


Après quelques réflexions, j'ai développé les outils suivants : 


HTML::Excerpt::FromXPath ; cet outil permet d'extraire une partie d'une page
web sur base d'une expression XPath, à cette époque, je n'avais pas encore
entendu parlé du merveilleux outil développé par Arc90, j'ai nommé
Readability 1


Mobigen::Command ; cet outil était juste un wrapper du programme
mobigen_linux qui permettait de convertir un fichier HTML en fichier
Mobibook ; il est bon de noter que mobigen_linux a été remplacé par
kindlegen (disponible gratuitement même si ce n'est pas libre) ;


HTML::Image::Save ; cet outil permet de sauvegarder les images d'un fichier
HTML, et de modifier ce dernier de manière à faire correspondre les liens
des images vers les versions locales ; 


App::uri2mobi ; est l'outil exploitant ces trois outils précédents dans une
interface en ligne de commande. 




Par (mauvaise) paresse, je n'ai jamais pris le temps de mettre ces modules sur
CPAN 2, mais cela ne m'empêche pas d'en parler quand même. 


Donc, dans le cas qui nous occupe aujourd'hui, nous allons voir
HTML::Image::Save. L'utilisation de ce dernier est aussi simple que possible : 



my $img_saver = HTML::Image::Save-&gt;new(
   output_dir =&gt; './',
   img_dir =&gt; 'images',
);
$img_saver-&gt;html( $html );
$img_saver-&gt;output_html( 'web_scraping.html' );
$img_saver-&gt;save();



Comme le HTML pouvait venir de différents sources (fichiers en local ou
récupéré directement sur le web), j'ai préféré la solution la plus simple, à
savoir prévoir une méthode pour obtenir le code HTML. 


En ce qui concerne le code lui-même, il n'y a pour ainsi que la méthode
save() qui est intéressante : 



sub save {
    my $self = shift;

    croak &quot;No base URL&quot; unless $self-&gt;base_url;
    croak &quot;No HTML&quot; unless $self-&gt;html;
    
    my $resolver = HTML::ResolveLink-&gt;new(
        base =&gt; $self-&gt;base_url
    );
    
    my $html = $resolver-&gt;resolve($self-&gt;html);

    my $tree = HTML::TreeBuilder-&gt;new_from_content( $html );
    my @img = $tree-&gt;find('img');

    $self-&gt;_build_directories();
    
    foreach my $image (@img) {
        my $remote_link = $image-&gt;attr('src');
        my $local_link = $self-&gt;_get_local_link($remote_link);
        getstore($remote_link, $local_link);
        $image-&gt;attr('src', $local_link);
        if ($self-&gt;callback) {
            $self-&gt;callback-&gt;($self, $image, $local_link);
        }
    }

    $self-&gt;html($tree-&gt;as_HTML());

    if ($self-&gt;output_html()) {
        open my $fh, '&gt;', $self-&gt;output_html;
        print $fh $self-&gt;html();
        close $fh;
    }

    return $self-&gt;html();   
}



Cette dernière s'appuie sur HTML::ResolveLink pour modifier le HTML de manière
à transformer tout les liens en liens absolus, sur HTML::TreeBuilder pour
parcourir les images du code HTML, et enfin sur LWP::Simple pour récupérer les
images. 


Bref, rien de bien compliqué, et une chouette exploitation du CPAN me
permettant d'avoir l'outil qu'il faut, rapidement, et sans trop de prises de
tête. 


Notes de bas de page:

1 il existe maintenant deux modules permettant de reproduire le
comportement de Readability : HTML::ExtractMain et HTML::ExtractContent, donc,
dans mes futurs outils, il est plus que probable que j'utiliserai ces
derniers.

2 mais je vais le faire, promis !


]]></summary>
    <author>
        <name>manu</name>
        
    </author>
    
        <category term="Français" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="cpan" label="cpan" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="ebook" label="ebook" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl" label="perl" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="fr" xml:base="http://blog.bjornoya.be/lab_stacks/">
        <![CDATA[
<p>Il y a quelques temps maintenant, quand j'ai commencé à lire quotidiennement
sur mon <a href="http://www.bookeen.com/specs/ebook-CybookGen3.aspx">ebook</a>, j'ai rapidement souhaité être en mesure de lire des articles
provenant de web sur ma <a href="http://www.bookeen.com/specs/ebook-CybookGen3.aspx">liseuse</a>. Après un rapide tour d'horizon, je n'avais
rien trouvé à l'époque (cela remonte quand même à un petit bout de temps
maintenant), et je m'étais donc lancé dans le développement d'une solution
personnelle.
</p>
<p>
Après quelques réflexions, j'ai développé les outils suivants : 
</p><ul>
<li>
<a href="http://github.com/edipretoro/html-excerpt-fromxpath">HTML::Excerpt::FromXPath</a> ; cet outil permet d'extraire une partie d'une page
web sur base d'une expression <a href="http://fr.wikipedia.org/wiki/XPath">XPath</a>, à cette époque, je n'avais pas encore
entendu parlé du merveilleux outil développé par <a href="http://www.arc90.com/">Arc90</a>, j'ai nommé
<a href="http://lab.arc90.com/experiments/readability/">Readability</a> <sup><a class="footref" name="fnr.1" href="#fn.1">1</a></sup>
</li>
<li>
<a href="http://github.com/edipretoro/mobigen-command">Mobigen::Command</a> ; cet outil était juste un <i>wrapper</i> du programme
<code>mobigen_linux</code> qui permettait de convertir un fichier HTML en fichier
Mobibook ; il est bon de noter que <code>mobigen_linux</code> a été remplacé par
<code>kindlegen</code> (<a href="http://www.amazon.com/gp/feature.html?docId=1000234621">disponible gratuitement même si ce n'est pas libre</a>) ;
</li>
<li>
<a href="http://github.com/edipretoro/html-image-save">HTML::Image::Save</a> ; cet outil permet de sauvegarder les images d'un fichier
HTML, et de modifier ce dernier de manière à faire correspondre les liens
des images vers les versions locales ; 
</li>
<li>
<a href="http://github.com/edipretoro/app-uri2mobi">App::uri2mobi</a> ; est l'outil exploitant ces trois outils précédents dans une
interface en ligne de commande. 

</li>
</ul>

<p>Par (mauvaise) paresse, je n'ai jamais pris le temps de mettre ces modules sur
<a href="http://www.cpan.org">CPAN</a> <sup><a class="footref" name="fnr.2" href="#fn.2">2</a></sup>, mais cela ne m'empêche pas d'en parler quand même. 
</p>
<p>
Donc, dans le cas qui nous occupe aujourd'hui, nous allons voir
<a href="http://github.com/edipretoro/html-image-save">HTML::Image::Save</a>. L'utilisation de ce dernier est aussi simple que possible : 
</p>
<p>
<pre class='brush: perl'>
my $img_saver = HTML::Image::Save-&gt;new(
   output_dir =&gt; './',
   img_dir =&gt; 'images',
);
$img_saver-&gt;html( $html );
$img_saver-&gt;output_html( 'web_scraping.html' );
$img_saver-&gt;save();
</pre>
</p>
<p>
Comme le HTML pouvait venir de différents sources (fichiers en local ou
récupéré directement sur le web), j'ai préféré la solution la plus simple, à
savoir prévoir une méthode pour obtenir le code HTML. 
</p>
<p>
En ce qui concerne le code lui-même, il n'y a pour ainsi que la méthode
<i>save()</i> qui est intéressante : 
</p>
<p>
<pre class='brush: perl'>
sub save {
    my $self = shift;

    croak &quot;No base URL&quot; unless $self-&gt;base_url;
    croak &quot;No HTML&quot; unless $self-&gt;html;
    
    my $resolver = HTML::ResolveLink-&gt;new(
        base =&gt; $self-&gt;base_url
    );
    
    my $html = $resolver-&gt;resolve($self-&gt;html);

    my $tree = HTML::TreeBuilder-&gt;new_from_content( $html );
    my @img = $tree-&gt;find('img');

    $self-&gt;_build_directories();
    
    foreach my $image (@img) {
        my $remote_link = $image-&gt;attr('src');
        my $local_link = $self-&gt;_get_local_link($remote_link);
        getstore($remote_link, $local_link);
        $image-&gt;attr('src', $local_link);
        if ($self-&gt;callback) {
            $self-&gt;callback-&gt;($self, $image, $local_link);
        }
    }

    $self-&gt;html($tree-&gt;as_HTML());

    if ($self-&gt;output_html()) {
        open my $fh, '&gt;', $self-&gt;output_html;
        print $fh $self-&gt;html();
        close $fh;
    }

    return $self-&gt;html();   
}
</pre>
</p>
<p>
Cette dernière s'appuie sur <a href="http://search.cpan.org/dist/HTML-ResolveLink">HTML::ResolveLink</a> pour modifier le HTML de manière
à transformer tout les liens en <a href="http://fr.wikibooks.org/wiki/Le_langage_HTML/Liens#Liens_absolus">liens absolus</a>, sur <a href="http://search.cpan.org/dist/HTML-Tree/">HTML::TreeBuilder</a> pour
parcourir les images du code HTML, et enfin sur <a href="http://search.cpan.org/dist/libwww-perl/lib/LWP/Simple.pm">LWP::Simple</a> pour récupérer les
images. 
</p>
<p>
Bref, rien de bien compliqué, et une chouette exploitation du <a href="http://www.cpan.org">CPAN</a> me
permettant d'avoir l'outil qu'il faut, rapidement, et sans trop de prises de
tête. 
</p>
<div id="footnotes">
<h2 class="footnotes"><strong>Notes de bas de page:</strong></h2>
<div id="text-footnotes">
<p class="footnote"><sup><a class="footnum" name="fn.1" href="#fnr.1">1</a></sup> il existe maintenant deux modules permettant de reproduire le
comportement de <a href="http://lab.arc90.com/experiments/readability/">Readability</a> : <a href="http://search.cpan.org/dist/HTML-ExtractMain">HTML::ExtractMain</a> et <a href="http://search.cpan.org/dist/HTML-ExtractContent">HTML::ExtractContent</a>, donc,
dans mes futurs outils, il est plus que probable que j'utiliserai ces
derniers.
</p>
<p class="footnote"><sup><a class="footnum" name="fn.2" href="#fnr.2">2</a></sup> mais je vais le faire, promis !
</p>
</div>
</div>]]>
    </content>
</entry>

<entry>
    <title>Perl est une planète</title>
    <link rel="alternate" type="text/html" href="http://blog.bjornoya.be/lab_stacks/2010/03/perl-est-une-planete.html" />
    <id>tag:blog.bjornoya.be,2010:/lab_stacks//1.25</id>

    <published>2010-03-15T22:32:48Z</published>
    <updated>2010-03-15T22:34:12Z</updated>

    <summary> Avec un temps de retard, je viens de lire le billet de Jean Véronis intitulé «
Ontologies: Perl est une planète du système solaire », (une version anglaise de l&apos;article est disponible). 


Et donc, mis-à-part l&apos;intérêt intrinsèque du billet, vive Perl ;-)
</summary>
    <author>
        <name>manu</name>
        
    </author>
    
        <category term="Français" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="perl" label="perl" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="tal" label="tal" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="fr" xml:base="http://blog.bjornoya.be/lab_stacks/">
        <![CDATA[ <p>Avec un temps de retard, je viens de lire le billet de <a href="http://blog.veronis.fr/">Jean Véronis</a> intitulé «
<a href="http://blog.veronis.fr/2010/02/ontologies-perl-est-une-planete-du.html">Ontologies: Perl est une planète du système solaire</a> », (<a href="http://blog.veronis.fr/2010/03/ontologies-perl-is-planet-in-solar.html">une version anglaise de l'article est disponible</a>). 
</p>
<p>
Et donc, mis-à-part l'intérêt intrinsèque du billet, vive <a href="http://perl.org">Perl</a> ;-)
</p>]]>
    </content>
</entry>

<entry>
    <title>L&apos;importance de l&apos;écosystème d&apos;un langage</title>
    <link rel="alternate" type="text/html" href="http://blog.bjornoya.be/lab_stacks/2010/03/limportance-de-lecosysteme-dun-langage.html" />
    <id>tag:blog.bjornoya.be,2010:/lab_stacks//1.24</id>

    <published>2010-03-08T20:13:23Z</published>
    <updated>2010-03-08T20:16:07Z</updated>

    <summary>En lisant le dernier « PragPub: The First Iteration » (le n°9, disponible sur le site de PragProg), dans l&apos;article « JavaScript: It&apos;s Not Just for Browsers Any More » de Jason Huggins, je suis tombé sur une réflexion
intéressante : 


When we choose a technology to write an application, we don&apos;t just choose the
language, we also choose the list of available libraries. If a language has
many useful libraries with a vibrant community around them, it&apos;s going to be
easier to write your application in less time.



Bon, dans mon cas, cela m&apos;a fait pensé au Perl et au CPAN, mais je suis sûr
que d&apos;autres liront autres choses :)
</summary>
    <author>
        <name>manu</name>
        
    </author>
    
        <category term="Français" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="cpan" label="cpan" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl" label="perl" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="fr" xml:base="http://blog.bjornoya.be/lab_stacks/">
        <![CDATA[<p>En lisant le dernier « <i>PragPub: The First Iteration</i> » (<a href="http://www.pragprog.com/magazines">le n°9, disponible sur le site de PragProg</a>), dans l'article « <i>JavaScript: It's Not Just for Browsers Any More</i> » de <b>Jason Huggins</b>, je suis tombé sur une réflexion
intéressante : 
</p>
<blockquote>
<p>When we choose a technology to write an application, we don't just choose the
language, we also choose the list of available libraries. If a language has
many useful libraries with a vibrant community around them, it's going to be
easier to write your application in less time.
</p>
</blockquote>
<p>
Bon, dans mon cas, cela m'a fait pensé au <a href="http://www.perl.org">Perl</a> et au <a href="http://search.cpan.org">CPAN</a>, mais je suis sûr
que d'autres liront autres choses :)
</p>]]>
    </content>
</entry>

<entry>
    <title>Pearltrees, RDF &amp; Perl</title>
    <link rel="alternate" type="text/html" href="http://blog.bjornoya.be/lab_stacks/2010/03/pearltrees-rdf-perl.html" />
    <id>tag:blog.bjornoya.be,2010:/lab_stacks//1.23</id>

    <published>2010-03-07T14:54:26Z</published>
    <updated>2010-03-07T15:00:25Z</updated>

    <summary><![CDATA[Suite à quelques discussions récentes, je me suis replonger dans les arcanes
du RDF. En effet, Pearltrees offrant une possibilité d'exportation des favoris
en RDF, ma curiosité naturelle m'a poussée à investiguer de manière à savoir
ce que je pouvais faire concrètement avec ce fichier. En plus, @SebDeclercq a
été assez gentil que pour me transmettre sa propre sauvegarde, m'épargnant
ainsi la tâche fastidieuse d'enrichir mes propres Pearltrees. 


Donc, j'ai un fichier contenant plein de liens, et maintenant, je veux
exploiter ces informations. Comment faire ? Comme indiqué dans le billet du
blog de Nicolas Cynober, nous pouvons utiliser un outil comme SPARQLer pour
manipuler les informations. Dans SPARQLer, vous pourrez soumettre votre
requête écrite en SPARQL, et obtenir une réponse sous différent format :


en XML, avec la possibilité de renseigner un script XSLT permettant de
transformer le document (par exemple en XHTML) ;


en JSON ; 


ou encore simplement en texte.




Donc, c'est un outil très intéressant, mais il faut être en ligne, et
personnellement, j'aime bien avoir mes outils directement disponibles, quelque
soit mes accès au web. Et donc, se pose la question de savoir ce que je peux
avoir directement sur ma machine. Un petit tour par le CPAN, et hop, voici
quelques modules prometteurs : 


RDF::Redland ;


RDF::Trine ;


et celui qu'il me faut pour interroger le fichier via la SPARQL :
RDF::Query. 




Un petit cpan RDF::Query plus tard, je me retrouve donc avec un module
permettant d'interroger en SPARQL un store RDF. 


Mais comment faire passer mon fichier pearltrees_export.rdf dans un store
RDF ? Relativement simplement, RDF::Trine propose dans son répertoire bin
quelques exemples de scripts qui vont nous aider : 


rdf_init_store.pl qui, comme son nom l'indique, permet d'initialiser un
magasin RDF ; j'ai donc lancé la commande suivante pour initialiser ma
base de données : ./rdf_init_store.pl sqlite ./pearltrees.db '' '' pearltrees
ce qui signifie donc :


initialise une base de données en utilisant SQLite ;


le nom de cette base de données est ./pearltrees.db 1;


le premier '' permet de spécifier le nom d'utilisateur pour la base de
données, et il n'y en a pas dans le cas présent ;


le second '' permet de spécifier le mot de passe, idem que
précédemment2


et finalement, pearltrees est le nom du modèle de données RDF, ici j'ai
arbitrairement donné le nom de pearltrees ;


la commande une fois lancée me donne un message d'avertissement :
Log4perl: Seems like no initialization happened. Forgot to call      init()?, mais quand je vérifie via un sqlite3 pearltrees.db, je
constate que les tables (Bnodes, Literals, Models, Resources et
Statement2742456113224982524) ont bien été créées, donc, pas de soucis !     




rdf_store_add_file.pl qui permet d'ajouter un fichier dans la base de
données de triplets ; ce script s'utilise de la manière suivante
./rdf_store_add_file.pl sqlite ./pearltrees.db '' '' pearltrees   sebdeclercq.rdf, ce qui suit la logique du script précédent (utilisation de
SQLite, le nom de la base de données, le nom d'utilisateur, le mot de passe
et le nom du modèle de données RDF.




Sur mon EeePC 1005HA, voici quelques statistiques : 


pour un fichier RDF de 421515 octets, j'obtiens une base de données de
1872896 octets ;


le traitement du fichier prend un peu de temps, voici le résultat de
time :





real    16m52.234s
user    3m33.573s
sys     0m17.757s





Après l'exécution de rdf_store_add_file.pl, nous nous retrouvons donc avec une
base de données qui pourra servir de base à RDF::Query. 


Voici un petit script illustrant l'utilisation de RDF::Query : 

#!/usr/bin/env perl

use strict;
use warnings;

use RDF::Trine;
use RDF::Trine::Store::DBI;
use RDF::Query;
use Data::Dump;

my $sparql = &lt;&lt;'SPARQL';
PREFIX pt: &lt;http://www.pearltrees.com/rdf/0.1/&gt;
PREFIX owl: &lt;http://www.w3.org/2002/07/owl#&gt;
PREFIX rdf: &lt;http://www.w3.org/1999/02/22-rdf-syntax-ns#&gt;
PREFIX dc: &lt;http://purl.org/dc/elements/1.1/&gt;

SELECT ?title ?url
WHERE {
   ?pearl rdf:type pt:pearl;
          dc:title ?title;
          owl:sameAs ?url;
          pt:parentTree ?tree
}
ORDER BY DESC (?tree)
SPARQL

my $store =
  RDF::Trine::Store::DBI-&gt;new( 'pearltrees', 'DBI:SQLite:dbname=./pearltrees.db', '', '' );
my $model = RDF::Trine::Model-&gt;new($store);

my $querier = RDF::Query-&gt;new($sparql);

my $iterator = $querier-&gt;execute($model);
while ( my $row = $iterator-&gt;next ) {
    print $row-&gt;{title} . ' ' . $row-&gt;{url} . &quot;\n&quot;;
}



Voilà pour aujourd'hui. Je suis en train de travailler sur un script
s'appuyant sur HTTP::Server::Simple et Template::Declare afin d'avoir une
interface plus agréable pour tester mes requêtes SPARQL.


Keep in touch&hellip;






Notes de bas de page:

1 puisque nous utilisons SQLite, la base de données est en fait un
fichier

2 dans le cas d'une base de données MySQL, cela aurait été nécessaire
évidemment


]]></summary>
    <author>
        <name>manu</name>
        
    </author>
    
        <category term="Français" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="cpan" label="cpan" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="pearltrees" label="pearltrees" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl" label="perl" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="rdf" label="rdf" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="fr" xml:base="http://blog.bjornoya.be/lab_stacks/">
        <![CDATA[<p>Suite à <a href="http://sebdeclercq.wordpress.com/2010/02/03/rex-twitter-comme-outil-de-presence-en-ligne/#comments">quelques</a> <a href="http://sebdeclercq.wordpress.com/2010/02/22/rex-pourquoi-jutilise-pearltrees/">discussions</a> <a href="http://blog.bjornoya.be/lab_stacks/2010/02/pearltrees.html">récentes</a>, je me suis replonger dans les arcanes
du <a href="http://fr.wikipedia.org/wiki/Resource_Description_Framework">RDF</a>. En effet, <a href="http://pearltrees.com">Pearltrees</a> offrant une possibilité d'exportation des favoris
en <a href="http://fr.wikipedia.org/wiki/Resource_Description_Framework">RDF</a>, ma curiosité naturelle m'a poussée à investiguer de manière à savoir
ce que je pouvais faire concrètement avec ce fichier. En plus, <a href="http://twitter.com/SebDeclercq">@SebDeclercq</a> a
été assez gentil que pour me transmettre sa propre sauvegarde, m'épargnant
ainsi la tâche fastidieuse d'enrichir <a href="http://www.pearltrees.com/edipretoro/">mes propres Pearltrees</a>. 
</p>
<p>
Donc, j'ai un fichier contenant plein de liens, et maintenant, je veux
exploiter ces informations. Comment faire ? Comme indiqué dans le <a href="http://nicolas.cynober.fr/blog/496,comment-recuperer-plus-dinfo-sur-son-compte-pearltrees.html">billet</a> du
blog de <a href="http://nicolas.cynober.fr/blog">Nicolas Cynober</a>, nous pouvons utiliser un outil comme <a href="http://www.sparql.org/sparql.html">SPARQLer</a> pour
manipuler les informations. Dans <a href="http://www.sparql.org/sparql.html">SPARQLer</a>, vous pourrez soumettre votre
requête écrite en <a href="http://fr.wikipedia.org/wiki/SPARQL">SPARQL</a>, et obtenir une réponse sous différent format :
</p><ul>
<li>
en XML, avec la possibilité de renseigner un script <a href="http://fr.wikipedia.org/wiki/XSLT">XSLT</a> permettant de
transformer le document (par exemple en XHTML) ;
</li>
<li>
en JSON ; 
</li>
<li>
ou encore simplement en texte.

</li>
</ul>

<p>Donc, c'est un outil très intéressant, mais il faut être en ligne, et
personnellement, j'aime bien avoir mes outils directement disponibles, quelque
soit mes accès au web. Et donc, se pose la question de savoir ce que je peux
avoir directement sur ma machine. Un petit tour par le <a href="http://search.cpan.org/">CPAN</a>, et hop, voici
quelques modules prometteurs : 
</p><ul>
<li>
<i>RDF::Redland</i> ;
</li>
<li>
<i>RDF::Trine</i> ;
</li>
<li>
et celui qu'il me faut pour interroger le fichier via la SPARQL :
<i>RDF::Query</i>. 

</li>
</ul>

<p>Un petit <code>cpan RDF::Query</code> plus tard, je me retrouve donc avec un module
permettant d'interroger en SPARQL un <i>store</i> RDF. 
</p>
<p>
Mais comment faire passer mon fichier <code>pearltrees_export.rdf</code> dans un store
RDF ? Relativement simplement, RDF::Trine propose dans son répertoire <a href="http://cpansearch.perl.org/src/GWILLIAMS/RDF-Trine-0.117/bin/">bin</a>
quelques exemples de scripts qui vont nous aider : 
</p><ul>
<li>
<a href="http://cpansearch.perl.org/src/GWILLIAMS/RDF-Trine-0.117/bin/rdf_init_store.pl">rdf_init_store.pl</a> qui, comme son nom l'indique, permet d'initialiser un
<i>magasin</i> RDF ; j'ai donc lancé la commande suivante pour initialiser ma
base de données : <code>./rdf_init_store.pl sqlite ./pearltrees.db '' '' pearltrees</code>
ce qui signifie donc :
<ol>
<li>
initialise une base de données en utilisant SQLite ;
</li>
<li>
le nom de cette base de données est <code>./pearltrees.db</code> <sup><a class="footref" name="fnr.1" href="#fn.1">1</a></sup>;
</li>
<li>
le premier '' permet de spécifier le nom d'utilisateur pour la base de
données, et il n'y en a pas dans le cas présent ;
</li>
<li>
le second '' permet de spécifier le mot de passe, idem que
précédemment<sup><a class="footref" name="fnr.2" href="#fn.2">2</a></sup>
</li>
<li>
et finalement, <code>pearltrees</code> est le nom du modèle de données RDF, ici j'ai
arbitrairement donné le nom de <code>pearltrees</code> ;
</li>
<li>
la commande une fois lancée me donne un message d'avertissement :
<i>Log4perl: Seems like no initialization happened. Forgot to call      init()?</i>, mais quand je vérifie via un <code>sqlite3 pearltrees.db</code>, je
constate que les tables (<i>Bnodes</i>, <i>Literals</i>, <i>Models</i>, <i>Resources</i> et
<i>Statement2742456113224982524</i>) ont bien été créées, donc, pas de soucis !     
</li>
</ol>
</li>
<li>
<a href="http://cpansearch.perl.org/src/GWILLIAMS/RDF-Trine-0.117/bin/rdf_store_add_file.pl">rdf_store_add_file.pl</a> qui permet d'ajouter un fichier dans la base de
données de triplets ; ce script s'utilise de la manière suivante
<code>./rdf_store_add_file.pl sqlite ./pearltrees.db '' '' pearltrees   sebdeclercq.rdf</code>, ce qui suit la logique du script précédent (utilisation de
SQLite, le nom de la base de données, le nom d'utilisateur, le mot de passe
et le nom du modèle de données RDF.

</li>
</ul>

<p>Sur mon EeePC 1005HA, voici quelques statistiques : 
</p><ul>
<li>
pour un fichier RDF de 421515 octets, j'obtiens une base de données de
1872896 octets ;
</li>
<li>
le traitement du fichier prend un peu de temps, voici le résultat de
<code>time</code> :

</li>
</ul>


<pre class="example">real    16m52.234s
user    3m33.573s
sys     0m17.757s
</pre>



<p>
Après l'exécution de <a href="http://cpansearch.perl.org/src/GWILLIAMS/RDF-Trine-0.117/bin/rdf_store_add_file.pl">rdf_store_add_file.pl</a>, nous nous retrouvons donc avec une
base de données qui pourra servir de base à <a href="http://search.cpan.org/dist/RDF-Query/">RDF::Query</a>. 
</p>
<p>
Voici un petit script illustrant l'utilisation de <a href="http://search.cpan.org/dist/RDF-Query/">RDF::Query</a> : 
<pre class='brush: perl'>
#!/usr/bin/env perl

use strict;
use warnings;

use RDF::Trine;
use RDF::Trine::Store::DBI;
use RDF::Query;
use Data::Dump;

my $sparql = &lt;&lt;'SPARQL';
PREFIX pt: &lt;http://www.pearltrees.com/rdf/0.1/&gt;
PREFIX owl: &lt;http://www.w3.org/2002/07/owl#&gt;
PREFIX rdf: &lt;http://www.w3.org/1999/02/22-rdf-syntax-ns#&gt;
PREFIX dc: &lt;http://purl.org/dc/elements/1.1/&gt;

SELECT ?title ?url
WHERE {
   ?pearl rdf:type pt:pearl;
          dc:title ?title;
          owl:sameAs ?url;
          pt:parentTree ?tree
}
ORDER BY DESC (?tree)
SPARQL

my $store =
  RDF::Trine::Store::DBI-&gt;new( 'pearltrees', 'DBI:SQLite:dbname=./pearltrees.db', '', '' );
my $model = RDF::Trine::Model-&gt;new($store);

my $querier = RDF::Query-&gt;new($sparql);

my $iterator = $querier-&gt;execute($model);
while ( my $row = $iterator-&gt;next ) {
    print $row-&gt;{title} . ' ' . $row-&gt;{url} . &quot;\n&quot;;
}
</pre>
</p>
<p>
Voilà pour aujourd'hui. Je suis en train de travailler sur un script
s'appuyant sur <a href="http://search.cpan.org/dist/HTTP-Server-Simple/">HTTP::Server::Simple</a> et <a href="http://search.cpan.org/dist/Template-Declare/">Template::Declare</a> afin d'avoir une
interface plus agréable pour tester mes requêtes SPARQL.
</p>
<p>
<i>Keep in touch&hellip;</i>
</p>




<div id="footnotes">
<h2 class="footnotes"><strong>Notes de bas de page:</strong></h2>
<div id="text-footnotes">
<p class="footnote"><sup><a class="footnum" name="fn.1" href="#fnr.1">1</a></sup> puisque nous utilisons <a href="http://www.sqlite.org">SQLite</a>, la base de données est en fait un
fichier
</p>
<p class="footnote"><sup><a class="footnum" name="fn.2" href="#fnr.2">2</a></sup> dans le cas d'une base de données <a href="http://www.mysql.com">MySQL</a>, cela aurait été nécessaire
évidemment
</p>
</div>
</div>]]>
    </content>
</entry>

<entry>
    <title>« On se tient au courant ! »</title>
    <link rel="alternate" type="text/html" href="http://blog.bjornoya.be/lab_stacks/2010/02/-on-se-tient-au-courant.html" />
    <id>tag:blog.bjornoya.be,2010:/lab_stacks//1.22</id>

    <published>2010-02-26T22:16:47Z</published>
    <updated>2010-02-26T22:21:43Z</updated>

    <summary><![CDATA[Récemment, au détour de GitHub, j'ai vu un projet intéressant : growlme. Pour
ceux qui ne connaissent pas Growl, il s'agit d'un système de notification non
intrusif. Imaginez que vous lancez la gravure d'un DVD, et pendant ce temps-là
vous en profitez pour travailler sur un article ou un billet de
blog. Traditionnellement, les logiciels de gravure vous afficheront une petite
fenêtre à la fin de la grave, interrompant ainsi ce que vous étiez en train de
faire. Avec les systèmes de notification comme Growl, une fenêtre volante
apparaîtra en haut à droite de l'écran signalant la fin de la gravure. Growl
est uniquement disponible sur Mac1, mais il existe des systèmes équivalent sur
Linux (libnotify entre autres). 


growlme permet de lancer un programme en ligne de commande et d'être tenu au
courant du résultat de son exécution via Growl. Comme il m'arrive souvent de
lancer un processus assez long via la ligne de commande, et de m'atteler à
d'autres tâches entre-temps, j'aimerais bien avoir l'équivalent sur mon
Linux. 


Le résultat n'est pas bien long et exploite Desktop::Notify, c'est-à-dire
l'interface Perl à libnotify, IPC::Run pour lancer la commande,
Getopt::Long pour traiter les paramètres en ligne de commande (notez l'usage
de Getopt::Long::Configure('pass_through') pour conserver un @ARGV, ainsi
que Sys::Hostname pour avoir le titre de la notification. Pour le reste,
j'ai singé le programme originel. 

#!/usr/bin/env perl

use strict;
use warnings;

use Desktop::Notify;
use IPC::Run qw( run );
use Getopt::Long;
use Sys::Hostname;

my $config = {
    message =&gt; 'Succeed!',
    fail    =&gt; 'FAILED',
    title   =&gt; hostname(),
};

Getopt::Long::Configure('pass_through');
GetOptions( $config, 'message=s', 'fail=s', 'title=s' );

if ( scalar(@ARGV) == 0 ) {
    die &quot;$0: must provide a command to execute\n&quot;;
}
else {
    my $notify = Desktop::Notify-&gt;new();
    my $notification;

    eval { run \@ARGV };
    my $exitcode = $? &gt;&gt; 8;
    if ( $exitcode == 0 ) {
        $notification = $notify-&gt;create(
            summary =&gt; $config-&gt;{title},
            body    =&gt; $config-&gt;{message},
            timeout =&gt; 5000,
        );
    }
    else {
        $notification = $notify-&gt;create(
            summary =&gt; $config-&gt;{title},
            body    =&gt; $config-&gt;{fail},
            timeout =&gt; 5000,
        );
    }

    $notification-&gt;show();
    $notification-&gt;close();
}



J'ai créé un gist sur GitHub de cet outil. 


Notes de bas de page:

1 et une version pour Windows également


]]></summary>
    <author>
        <name>manu</name>
        
    </author>
    
        <category term="Français" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="cpan" label="cpan" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="growl" label="growl" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="libnotify" label="libnotify" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl" label="perl" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="fr" xml:base="http://blog.bjornoya.be/lab_stacks/">
        <![CDATA[<p>Récemment, au détour de <a href="http://github.com">GitHub</a>, j'ai vu un projet intéressant : <a href="http://github.com/robey/growlme">growlme</a>. Pour
ceux qui ne connaissent pas <a href="http://growl.info/">Growl</a>, il s'agit d'un système de notification non
intrusif. Imaginez que vous lancez la gravure d'un DVD, et pendant ce temps-là
vous en profitez pour travailler sur un article ou un billet de
blog. Traditionnellement, les logiciels de gravure vous afficheront une petite
fenêtre à la fin de la grave, interrompant ainsi ce que vous étiez en train de
faire. Avec les systèmes de notification comme <a href="http://growl.info/">Growl</a>, une fenêtre volante
apparaîtra en haut à droite de l'écran signalant la fin de la gravure. <a href="http://growl.info/">Growl</a>
est uniquement disponible sur Mac<sup><a class="footref" name="fnr.1" href="#fn.1">1</a></sup>, mais il existe des systèmes équivalent sur
Linux (<a href="http://www.galago-project.org/news/">libnotify</a> entre autres). 
</p>
<p>
<a href="http://github.com/robey/growlme">growlme</a> permet de lancer un programme en ligne de commande et d'être tenu au
courant du résultat de son exécution via <a href="http://growl.info/">Growl</a>. Comme il m'arrive souvent de
lancer un processus assez long via la ligne de commande, et de m'atteler à
d'autres tâches entre-temps, j'aimerais bien avoir l'équivalent sur mon
Linux. 
</p>
<p>
Le résultat n'est pas bien long et exploite <code>Desktop::Notify</code>, c'est-à-dire
l'interface Perl à <a href="http://www.galago-project.org/news/">libnotify</a>, <code>IPC::Run</code> pour lancer la commande,
<code>Getopt::Long</code> pour traiter les paramètres en ligne de commande (notez l'usage
de <code>Getopt::Long::Configure('pass_through')</code> pour conserver un <code>@ARGV</code>, ainsi
que <code>Sys::Hostname</code> pour avoir le titre de la notification. Pour le reste,
j'ai singé le <a href="http://github.com/robey/growlme/blob/master/growlme">programme originel</a>. 
<pre class='brush: perl'>
#!/usr/bin/env perl

use strict;
use warnings;

use Desktop::Notify;
use IPC::Run qw( run );
use Getopt::Long;
use Sys::Hostname;

my $config = {
    message =&gt; 'Succeed!',
    fail    =&gt; 'FAILED',
    title   =&gt; hostname(),
};

Getopt::Long::Configure('pass_through');
GetOptions( $config, 'message=s', 'fail=s', 'title=s' );

if ( scalar(@ARGV) == 0 ) {
    die &quot;$0: must provide a command to execute\n&quot;;
}
else {
    my $notify = Desktop::Notify-&gt;new();
    my $notification;

    eval { run \@ARGV };
    my $exitcode = $? &gt;&gt; 8;
    if ( $exitcode == 0 ) {
        $notification = $notify-&gt;create(
            summary =&gt; $config-&gt;{title},
            body    =&gt; $config-&gt;{message},
            timeout =&gt; 5000,
        );
    }
    else {
        $notification = $notify-&gt;create(
            summary =&gt; $config-&gt;{title},
            body    =&gt; $config-&gt;{fail},
            timeout =&gt; 5000,
        );
    }

    $notification-&gt;show();
    $notification-&gt;close();
}
</pre>
</p>
<p>
J'ai créé un <a href="http://gist.github.com/316238">gist sur GitHub</a> de cet outil. 
</p>
<div id="footnotes">
<h2 class="footnotes"><strong>Notes de bas de page:</strong></h2>
<div id="text-footnotes">
<p class="footnote"><sup><a class="footnum" name="fn.1" href="#fnr.1">1</a></sup> <a href="http://www.growlforwindows.com/gfw/">et une version pour Windows également</a>
</p>
</div>
</div>]]>
    </content>
</entry>

<entry>
    <title>Pearltrees</title>
    <link rel="alternate" type="text/html" href="http://blog.bjornoya.be/lab_stacks/2010/02/pearltrees.html" />
    <id>tag:blog.bjornoya.be,2010:/lab_stacks//1.21</id>

    <published>2010-02-24T21:23:59Z</published>
    <updated>2010-02-24T21:41:10Z</updated>

    <summary><![CDATA[
Pearltrees


Suite à un commentaire sur son blog, @SebDeclercq a expliqué les raisons de
son choix concernant Pearltrees. En résumé (et il me corrigera si j'ai mal
compris) :


besoin d'un outil permettant d'effectuer des sauvegardes de ces favoris ;


cet outil devait être en ligne pour pouvoir être utilisé depuis plusieurs
machines ;


le système de classement proposé doit être efficace, et le classement
visuel sous forme d'arbre rencontrait ses attentes.


De mon côté, je partage le besoin d'un système permettant de gérer mes
favoris. J'ai utilisé pendant un temps Delicious, mais à un moment, j'ai
abandonné l'habitude d'y déposer les ressources jugées intéressantes au profit
d'un petit outil développé par mes soins. Dans sa réponse @SebDeclercq signale
que son utilisation de Pearltrees passe essentiellement par l'extension
Firefox. Je n'avais pas pris le temps de tester ce dernier. D'abord parce que
mon navigateur principal est maintenant Chromium, et aussi par manque de
temps. J'avais donc testé l'outil offert par Pearltrees, à savoir le
bookmarklet, mais je n'en étais pas nécessairement content. Ce dernier
déposait les perles (comprendre les URL que vous souhaitez conserver) dans un
panier, et il vous restait encore à « ranger » ces perles. Et donc, devoir
utiliser cette interface en Flash que je trouve particulièrement
rebuttante1. Bref, dans ces conditions, il m'était difficile d'adopter
Pearltrees dans ma boîte à outils.


Mais l'article de @SebDeclercq m'a obligé à revisiter l'outil, et donc, cette
fois-ci j'ai pris le temps de lancer un Mozilla Firefox, et d'installer
l'extension. Et j'ai donc pu comprendre pourquoi c'était un outil intéressant
pour gérer ses favoris :


l'évidente intégration dans le navigateur ;


la mise à disposition d'un bouton vous permettant de choisir où placer votre
perle, et donc, cela vous dispense de passer par le site, et donc d'éviter
l'interface Flash ;


un bouton permettant de lancer votre Pearltrees.


Néanmoins, malgré tout, je ne pense pas inclure Pearltrees dans ma boîte à
outil pour les raisons suivantes :


absence d'API à ce jour : de mon point de vue, c'est vraiment le plus gros
point noir de cet outil. En effet, dans le web 2.0 qui est le nôtre, et dans
le web 3.0 ou le web des données qui pointe le bout de son nez, la présence
d'un API est essentielle2 !  Ainsi, si j'ai du mal avec l'interface
Flash, la présence d'une API m'aurait permis de développer un interface en
ligne de commande comme je les aime. Mais là, ce n'est pas avec l'export RDF
que je vais aller bien loin3 puisque je dois me connecter pour réaliser
cet exportation ; 


les fonctionnalités de l'outil ne dépasse pas de beaucoup celle d'un
Delicious. Bon, la structure arborescente est vraiment chouette, l'aspect
visualisation est intéressante4, le fait de pouvoir « capturer » un
pearltree est vraiment très sympathique, mais pour le reste, je crains de
reproduire le même schéma qu'avec Delicious ;


à côté de cela, j'ai découvert dernièrement via un tweet de @MarioAsselin un
outil plus en accord avec mes besoins : Diigo, je l'utilise depuis
maintenant une semaine, et même si je dois encore améliorer mon workflow
personnel de PKM afin de faire un peu de place à Diigo, j'ai peut-être
trouvé une réponse adéquate à mes besoins.





Diigo


Alors, voici en bref les fonctionnalités qui m'ont séduit :
présence d'une API ; bon, OK, elle n'est pas complète, mais elle permet déjà
de récupérer les informations sur les favoris, et donc, à moi de jouer pour
l'intégrer dans mes workflows personnels ; j'ai déjà jeté les premières pierres pour réaliser cette opération, mais je dois encore continuer
(vivement le week-end !) ;
existence d'une extension pour Chromium (et évidemment, une extension est
également disponible pour Firefox, mais je n'ai pas encore pris le temps de
la tester) ;
possibilité d'annoter les pages lues ; ces annotations peuvent être
récupérées via l'API et dans les fonctions d'export de l'outil ;
plusieurs formats d'exportation (IE Bookmark, Netscape Bookmark, RSS, CSV et
Delicious) ;
Diigo crée un snapshot du lien sauvegardé, cela signifie donc que même si
le lien n'est plus disponible, vous avez une version disponible dans votre
bibliothèque Diigo ;&nbsp;
possibilité de créer des liens privés ;
possibilité de créer des listes, et ces dernières peuvent également être
privées ;
possibilité de créer des groupes, c'est un aspect communautaire
supplémentaire par rapport à Delicious, utilisé entre autres par le groupe UQ de partage sur la techno pédagogie et sur les technologies ou les environnements numériques d'apprentissage.


Bref, intéressant, non ?






Conclusion


Bon, j'ai été long, mais je pense que le sujet en vaux la peine : comment&nbsp;garder une trace de ses lectures sur le web. Une réflexion de base pour des spécialistes de l'information, mais aussi, et de plus en plus pour M. Tout-le-monde qui doit faire preuve d'une littératie de plus en plus&nbsp;importante. Quant au choix de l'outil, il importe finalement peu pour autant&nbsp;que ce dernier réponde aux besoins de l'utilisateur.&nbsp;
Et comme je suis pour une diversité maximale de l'écologie des outils et des
logiciels : longue vie à Pearltrees et à Diigo !!!&nbsp;
Notes de bas de page:1 les raisons en sont relativement simples :
je travaille sur des machines différentes, et une de ces machine est un Asus EeePC 1005HA, donc, un écran 10", ce qui rend l'interface Flash particulièrement irritante ;même sur des écrans plus grands, je trouve cette interface terriblement lente ; je suis particulièrement peu patient avec les interfaces de logiciels, et j'aime que la limite soit ma capacité à exploiter le logiciel, dans le cas présent, je dois&nbsp;attendre&nbsp;l'interface, et cela m'irrite au plus au point, cette philosophie explique probablement mon addiction à la ligne de commande.
2 Il me reste évidemment la possibilité d'analyser le fonctionnement du&nbsp;bookmarklet et de l'extension pour savoir comment construire les requêtes,&nbsp;etc. Bref, du reverse engineering qui me prendra du temps, et me distraira&nbsp;d'autres projets ;
3 cet export RDF peut difficilement être qualifié de bonne nouvelle, je&nbsp;vous met au défi de faire quoi que ce soit avec ce fichier RDF. Cela signifie&nbsp;donc que vous pouvez exporter vos données ... mais aucun logiciel actuel n'est&nbsp;capable de manipuler le format en question. Cool. Un export CSV ou, mieux&nbsp;encore, tout autre format habituellement géré par les navigateurs aurait été&nbsp;le bienvenu !
4 cela me rappelle l'histoire de KartOO, qui a commencé par l'interface « carte » (une innovation pour un métamoteur) puis qui a fini par proposer le&nbsp;choix entre une interface « carte » et une interface plus classique. En&nbsp;espérant que l'histoire se termine mieux pour Pearltrees puisque&nbsp;qu'apparemment, KartOO, c'est fini !!
]]></summary>
    <author>
        <name>manu</name>
        
    </author>
    
        <category term="Français" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="diigo" label="diigo" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="pearltrees" label="pearltrees" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="fr" xml:base="http://blog.bjornoya.be/lab_stacks/">
        <![CDATA[<div id="outline-container-1" class="outline-3">
<h2 id="sec-1"><strong>Pearltrees</strong></h2>
<div class="outline-text-3" id="text-1">
<p>
Suite à un <a href="http://sebdeclercq.wordpress.com/2010/02/03/rex-twitter-comme-outil-de-presence-en-ligne/#comments">commentaire</a> sur son <a href="http://sebdeclercq.wordpress.com/">blog</a>, <a href="http://twitter.com/SebDeclercq">@SebDeclercq</a> a expliqué les raisons de
son choix concernant <a href="http://www.pearltrees.com">Pearltrees</a>. En résumé (et il me corrigera si j'ai mal
compris) :
</p><ol>
<li>
besoin d'un outil permettant d'effectuer des sauvegardes de ces favoris ;
</li>
<li>
cet outil devait être en ligne pour pouvoir être utilisé depuis plusieurs
machines ;
</li>
<li>
le système de classement proposé doit être efficace, et le classement
visuel sous forme d'arbre rencontrait ses attentes.</li>
</ol><p></p>

<p>De mon côté, je partage le besoin d'un système permettant de gérer mes
favoris. J'ai utilisé pendant un temps <a href="http://delicious.com">Delicious</a>, mais à un moment, j'ai
abandonné l'habitude d'y déposer les ressources jugées intéressantes au profit
d'un petit outil développé par mes soins. Dans sa réponse <a href="http://twitter.com/SebDeclercq">@SebDeclercq</a> signale
que son utilisation de <a href="http://www.pearltrees.com">Pearltrees</a> passe essentiellement par l'extension
Firefox. Je n'avais pas pris le temps de tester ce dernier. D'abord parce que
mon navigateur principal est maintenant <a href="http://www.chromium.org/Home">Chromium</a>, et aussi par manque de
temps. J'avais donc testé l'outil offert par <a href="http://www.pearltress.com">Pearltrees</a>, à savoir le
<i>bookmarklet</i>, mais je n'en étais pas nécessairement content. Ce dernier
déposait les perles (comprendre les URL que vous souhaitez conserver) dans un
panier, et il vous restait encore à « ranger » ces perles. Et donc, devoir
utiliser cette interface en Flash que je trouve particulièrement
rebuttante<sup><a class="footref" name="fnr.1" href="#fn.1">1</a></sup>. Bref, dans ces conditions, il m'était difficile d'adopter
<a href="http://www.pearltrees.com">Pearltrees</a> dans ma boîte à outils.
</p>
<p>
Mais l'article de <a href="http://twitter.com/SebDeclercq">@SebDeclercq</a> m'a obligé à revisiter l'outil, et donc, cette
fois-ci j'ai pris le temps de lancer un Mozilla Firefox, et d'installer
l'extension. Et j'ai donc pu comprendre pourquoi c'était un outil intéressant
pour gérer ses favoris :
</p><ul>
<li>
l'évidente intégration dans le navigateur ;
</li>
<li>
la mise à disposition d'un bouton vous permettant de choisir où placer votre
perle, et donc, cela vous dispense de passer par le site, et donc d'éviter
l'interface Flash ;
</li>
<li>
un bouton permettant de lancer votre Pearltrees.</li>
</ul><p></p>

<p>Néanmoins, malgré tout, je ne pense pas inclure <a href="#Pearltrees">Pearltrees</a> dans ma boîte à
outil pour les raisons suivantes :
</p><ul>
<li>
absence d'API à ce jour : de mon point de vue, c'est vraiment le plus gros
point noir de cet outil. En effet, dans le web 2.0 qui est le nôtre, et dans
le web 3.0 ou le web des données qui pointe le bout de son nez, la présence
d'un API est essentielle<sup><a class="footref" name="fnr.2" href="#fn.2">2</a></sup> !  Ainsi, si j'ai du mal avec l'interface
Flash, la présence d'une API m'aurait permis de développer un interface en
ligne de commande comme je les aime. Mais là, ce n'est pas avec l'export RDF
que je vais aller bien loin<sup><a class="footref" name="fnr.3" href="#fn.3">3</a></sup> puisque je dois me connecter pour réaliser
cet exportation ; 
</li>
<li>
les fonctionnalités de l'outil ne dépasse pas de beaucoup celle d'un
<a href="http://delicious.com">Delicious</a>. Bon, la structure arborescente est vraiment chouette, l'aspect
visualisation est intéressante<sup><a class="footref" name="fnr.4" href="#fn.4">4</a></sup>, le fait de pouvoir « capturer » un
<i>pearltree</i> est vraiment très sympathique, mais pour le reste, je crains de
reproduire le même schéma qu'avec <a href="http://delicious.com">Delicious</a> ;
</li>
<li>
à côté de cela, j'ai découvert dernièrement via un tweet de <a href="http://twitter.com/MarioAsselin/">@MarioAsselin</a> un
outil plus en accord avec mes besoins : <a href="http://www.diigo.com">Diigo</a>, je l'utilise depuis
maintenant une semaine, et même si je dois encore améliorer mon <i>workflow</i>
personnel de <a href="http://en.wikipedia.org/wiki/Personal_knowledge_management">PKM</a> afin de faire un peu de place à <a href="http://www.diigo.com">Diigo</a>, j'ai peut-être
trouvé une réponse adéquate à mes besoins.</li></ul>
</div><p></p>

</div>

<div id="outline-container-2" class="outline-3">
<h2 id="sec-2"><strong>Diigo</strong></h2>
<div class="outline-text-3" id="text-2">

<p>Alors, voici en bref les fonctionnalités qui m'ont séduit :</p><ol>
<li>présence d'une API ; bon, OK, <a href="http://www.diigo.com/tools/api">elle n'est pas complète</a>, mais elle permet déjà<br />
de récupérer les informations sur les favoris, et donc, à moi de jouer pour<br />
l'intégrer dans mes <i>workflows</i> personnels ; j'ai déjà jeté les <a href="http://github.com/edipretoro/Net-Diigo">premières pierres pour réaliser cette opération</a>, mais je dois encore continuer<br />
(vivement le week-end !) ;</li>
<li>existence d'une extension pour <a href="http://www.chromium.org/Home">Chromium</a> (et évidemment, une extension est<br />
également disponible pour Firefox, mais je n'ai pas encore pris le temps de<br />
la tester) ;</li>
<li>possibilité d'annoter les pages lues ; ces annotations peuvent être<br />
récupérées via l'API et dans les fonctions d'export de l'outil ;</li>
<li>plusieurs formats d'exportation (IE Bookmark, Netscape Bookmark, RSS, CSV et<br />
Delicious) ;</li>
<li><a href="http://www.diigo.com/">Diigo</a> crée un <i>snapshot</i> du lien sauvegardé, cela signifie donc que même si<br />
le lien n'est plus disponible, vous avez une version disponible dans votre<br />
bibliothèque <a href="http://www.diigo.com">Diigo</a> ;&nbsp;</li>
<li>possibilité de créer des liens privés ;</li>
<li>possibilité de créer des listes, et ces dernières peuvent également être<br />
privées ;</li>
<li>possibilité de créer des groupes, c'est un aspect communautaire<br />
supplémentaire par rapport à <a href="http://delicious.com">Delicious</a>, utilisé entre autres par le <a href="http://groups.diigo.com/group/uq-numerique">groupe UQ de partage sur la techno pédagogie et sur les technologies ou les environnements numériques d'apprentissage</a>.</li>
</ol><p></p>

<p>Bref, intéressant, non ?
</p>
</div>

</div>

<div id="outline-container-3" class="outline-3">
<h3 id="sec-3"><b>Conclusion</b></h3>
<div class="outline-text-3" id="text-3">

<p>Bon, j'ai été long, mais je pense que le sujet en vaux la peine : comment&nbsp;garder une trace de ses lectures sur le web. Une réflexion de base pour des spécialistes de l'information, mais aussi, et de plus en plus pour M. Tout-le-monde qui doit faire preuve d'une <a href="http://fr.wikipedia.org/wiki/Littératie">littératie</a> de plus en plus&nbsp;importante. Quant au choix de l'outil, il importe finalement peu pour autant&nbsp;que ce dernier réponde aux besoins de l'utilisateur.&nbsp;</p>
<p>Et comme je suis pour une diversité maximale de l'écologie des outils et des<br />
logiciels : longue vie à <a href="http://www.pearltrees.com">Pearltrees</a> et à <a href="http://www.diigo.com/">Diigo</a> !!!&nbsp;</p></div></div><div id="footnotes">
<h2 class="footnotes"><strong>Notes de bas de page:</strong></h2><div id="text-footnotes"><p class="footnote"><sup><a class="footnum" name="fn.1" href="#fnr.1">1</a></sup> les raisons en sont relativement simples :<br />
</p><ul style="margin-top: 0px; margin-right: 0px; margin-bottom: 0,75em; margin-left: 20px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; font-size: 1em; font-weight: normal; list-style-type: disc; list-style-position: outside; list-style-image: initial; background-repeat: no-repeat repeat; "><li style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; font-size: 1em; font-weight: normal; ">je travaille sur des machines différentes, et une de ces machine est un Asus EeePC 1005HA, donc, un écran 10", ce qui rend l'interface Flash particulièrement irritante ;</li><li style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; font-size: 1em; font-weight: normal; ">même sur des écrans plus grands, je trouve cette interface terriblement lente ; je suis particulièrement peu patient avec les interfaces de logiciels, et j'aime que la limite soit ma capacité à exploiter le logiciel, dans le cas présent, je dois&nbsp;<b>attendre</b>&nbsp;l'interface, et cela m'irrite au plus au point, cette philosophie explique probablement mon addiction à la ligne de commande.</li></ul>
<p class="footnote"><sup><a class="footnum" name="fn.2" href="#fnr.2">2</a></sup> Il me reste évidemment la possibilité d'analyser le fonctionnement du&nbsp;<i>bookmarklet</i> et de l'extension pour savoir comment construire les requêtes,&nbsp;etc. Bref, du <i>reverse engineering</i> qui me prendra du temps, et me distraira&nbsp;d'autres projets ;</p>
<p class="footnote"><sup><a class="footnum" name="fn.3" href="#fnr.3">3</a></sup> cet export RDF peut difficilement être qualifié de bonne nouvelle, je&nbsp;vous met au défi de faire quoi que ce soit avec ce fichier RDF. Cela signifie&nbsp;donc que vous pouvez exporter vos données ... mais aucun logiciel actuel n'est&nbsp;capable de manipuler le format en question. Cool. Un export CSV ou, mieux&nbsp;encore, tout autre format habituellement géré par les navigateurs aurait été&nbsp;le bienvenu !</p>
<p class="footnote"><sup><a class="footnum" name="fn.4" href="#fnr.4">4</a></sup> cela me rappelle l'histoire de KartOO, qui a commencé par l'interface « carte » (une innovation pour un métamoteur) puis qui a fini par proposer le&nbsp;choix entre une interface « carte » et une interface plus classique. En&nbsp;espérant que l'histoire se termine mieux pour <a href="http://www.pearltrees.com/">Pearltrees</a> puisque&nbsp;qu'apparemment, <a href="http://rogerschmitz.blogspot.com/2010/01/kartoo-site-ferme.html">KartOO, c'est fini !!</a></p></div>
</div><p></p>]]>
    </content>
</entry>

<entry>
    <title>Information retrieval - Exemple de création d&apos;un index</title>
    <link rel="alternate" type="text/html" href="http://blog.bjornoya.be/lab_stacks/2010/02/information-retrieval---exemple-de-creation-dun-index.html" />
    <id>tag:blog.bjornoya.be,2010:/lab_stacks//1.20</id>

    <published>2010-02-21T22:49:33Z</published>
    <updated>2010-02-21T23:12:03Z</updated>

    <summary><![CDATA[Dans le cadre d'un cours d'un cours de Gestion numérique des connaissances, je
parle un peu d'information retrieval. Juste les bases, mais bon, cela me
paraît important de savoir comment fonctionne un moteur de recherche, surtout
pour de futurs spécialistes de l'information et de la documentation. Parmi ces
bases, nous avons la manière dont un moteur de recherche perçoit le texte
qu'il doit indexer. Si la théorie est facile à appréhender, cela ne m'empêche
pas de rajouter une couche visuelle, et c'est pour cette raison que j'ai
écrit un petit permettant d'illustrer cette phase de l'indexation. 


Le script a été développé sur un temps de midi, un peu avant de donner le
cours, et donc, je n'ai pas travaillé l'ergonomie et la mise en page de
l'outil. Pour réaliser rapidement l'outil, j'ai utilisé les outils suivants : 


HTTP::Server::Simple + Template::Declare pour créer un petit site web à
partir duquel l'utilisateur pourra copier/coller un texte ;


Text::ExtractWords permettant d'extraire les mots. 




Pour le reste, le code est assez simple : 

#!/usr/bin/env perl

use strict;
use warnings;

package MyView::Templates;
use Template::Declare::Tags;
use base 'Template::Declare';

private template form =&gt; sub {
    my $self  = shift;
    my $title = shift;

    div {
        attr { style =&gt; 'margin: auto; size: 15%;', };
        form {
            attr {
                action =&gt; '/submit',
                method =&gt; 'POST',
            };
            textarea {
                attr {
                    cols  =&gt; '100',
                    rows  =&gt; '25',
                    name  =&gt; 'title',
                    style =&gt; 'float: left;',
                };
                $title;
            };
            input {
                attr {
                    name  =&gt; 'submit',
                    type  =&gt; 'submit',
                    value =&gt; 'Soumettre',
                    style =&gt; 'float: left;',
                };
            };
            input {
                attr {
                    name  =&gt; 'reset',
                    type  =&gt; 'reset',
                    value =&gt; 'Réinitialiser',
                    style =&gt; 'float: left;',
                };
            };
            div { attr { style =&gt; 'clear: both;' } };
        };
    };

};

template main =&gt; sub {
    my $self  = shift;
    my $title = shift;

    html {
        head {};
        body {
            show( 'form', $title );
        };
    };
};

private template data =&gt; sub {
    my $self   = shift;
    my $result = shift;

    div {
        attr { style =&gt; 'margin: auto; width: 40%' };
        h1 {
            &quot;Résultat de l'analyse&quot;;
        };
    }
    div {
        ol {
            foreach my $word ( sort keys %$result ) {
                li { $word . &quot; : &quot; . $result-&gt;{$word} };
            }
        };
    };
};

template result =&gt; sub {
    my $self   = shift;
    my $title  = shift;
    my $result = shift;

    html {
        head {};
        body {
            show( 'form', $title );
            hr {};
            show( 'data', $result );
        };
    }
};

package MyWebServer;

use HTTP::Server::Simple::CGI;
use base qw(HTTP::Server::Simple::CGI);
use Text::ExtractWords qw(words_count);

use Template::Declare;
Template::Declare-&gt;init( dispatch_to =&gt; ['MyView::Templates'] );

my %dispatch = (
    '/'       =&gt; \&amp;resp_homepage,
    '/submit' =&gt; \&amp;resp_submit,
);

sub handle_request {
    my $self = shift;
    my $cgi  = shift;

    my $path    = $cgi-&gt;path_info();
    my $handler = $dispatch{$path};

    if ( ref($handler) eq &quot;CODE&quot; ) {
        print &quot;HTTP/1.0 200 OK\r\n&quot;;
        $handler-&gt;($cgi);

    }
    else {
        print &quot;HTTP/1.0 404 Not found\r\n&quot;;
        print $cgi-&gt;header( -charset =&gt; 'UTF-8' ),
          $cgi-&gt;start_html('Not found'),
          $cgi-&gt;h1('Not found'),
          $cgi-&gt;end_html;
    }
}

sub resp_homepage {
    my $cgi = shift;
    return if !ref $cgi;

    print $cgi-&gt;header( -charset =&gt; 'UTF-8' ), Template::Declare-&gt;show('main');
}

sub resp_submit {
    my $cgi = shift;
    return if !ref $cgi;

    my $title  = $cgi-&gt;param('title');
    my $result = {};
    words_count( $result, $title, {} );

    print $cgi-&gt;header( -charset =&gt; 'UTF-8' ),
      Template::Declare-&gt;show( 'result', $title, $result );
}

package main;

my $server = MyWebServer-&gt;new(9999);
$server-&gt;run();



J'ai créé un gist de cet outil sur Github, et je compte l'améliorer quand
j'aurai un peu de temps. 
]]></summary>
    <author>
        <name>manu</name>
        
    </author>
    
        <category term="Français" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="cpan" label="cpan" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="iessid" label="iessid" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="illustration" label="illustration" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="informationretrieval" label="information retrieval" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl" label="perl" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="fr" xml:base="http://blog.bjornoya.be/lab_stacks/">
        <![CDATA[<p>Dans le cadre d'un cours d'un cours de <a href="http://www.iessid-cours.be/moodle/course/category.php?id=6">Gestion numérique des connaissances</a>, je
parle un peu d'<i>information retrieval</i>. Juste les bases, mais bon, cela me
paraît important de savoir comment fonctionne un moteur de recherche, surtout
pour de futurs spécialistes de l'information et de la documentation. Parmi ces
bases, nous avons la manière dont un moteur de recherche perçoit le texte
qu'il doit indexer. Si la théorie est facile à appréhender, cela ne m'empêche
pas de rajouter une couche <i>visuelle</i>, et c'est pour cette raison que j'ai
écrit un petit permettant d'illustrer cette phase de l'indexation. 
</p>
<p>
Le script a été développé sur un temps de midi, un peu avant de donner le
cours, et donc, je n'ai pas travaillé l'ergonomie et la mise en page de
l'outil. Pour réaliser rapidement l'outil, j'ai utilisé les outils suivants : 
</p><ul>
<li>
<a href="http://search.cpan.org/dist/HTTP-Server-Simple/">HTTP::Server::Simple</a> + <a href="http://search.cpan.org/dist/Template-Declare">Template::Declare</a> pour créer un petit site web à
partir duquel l'utilisateur pourra copier/coller un texte ;
</li>
<li>
<a href="http://search.cpan.org/dist/Text-ExtractWords">Text::ExtractWords</a> permettant d'extraire les mots. 

</li>
</ul>

<p>Pour le reste, le code est assez simple : 
<pre class='brush: perl'>
#!/usr/bin/env perl

use strict;
use warnings;

package MyView::Templates;
use Template::Declare::Tags;
use base 'Template::Declare';

private template form =&gt; sub {
    my $self  = shift;
    my $title = shift;

    div {
        attr { style =&gt; 'margin: auto; size: 15%;', };
        form {
            attr {
                action =&gt; '/submit',
                method =&gt; 'POST',
            };
            textarea {
                attr {
                    cols  =&gt; '100',
                    rows  =&gt; '25',
                    name  =&gt; 'title',
                    style =&gt; 'float: left;',
                };
                $title;
            };
            input {
                attr {
                    name  =&gt; 'submit',
                    type  =&gt; 'submit',
                    value =&gt; 'Soumettre',
                    style =&gt; 'float: left;',
                };
            };
            input {
                attr {
                    name  =&gt; 'reset',
                    type  =&gt; 'reset',
                    value =&gt; 'Réinitialiser',
                    style =&gt; 'float: left;',
                };
            };
            div { attr { style =&gt; 'clear: both;' } };
        };
    };

};

template main =&gt; sub {
    my $self  = shift;
    my $title = shift;

    html {
        head {};
        body {
            show( 'form', $title );
        };
    };
};

private template data =&gt; sub {
    my $self   = shift;
    my $result = shift;

    div {
        attr { style =&gt; 'margin: auto; width: 40%' };
        h1 {
            &quot;Résultat de l'analyse&quot;;
        };
    }
    div {
        ol {
            foreach my $word ( sort keys %$result ) {
                li { $word . &quot; : &quot; . $result-&gt;{$word} };
            }
        };
    };
};

template result =&gt; sub {
    my $self   = shift;
    my $title  = shift;
    my $result = shift;

    html {
        head {};
        body {
            show( 'form', $title );
            hr {};
            show( 'data', $result );
        };
    }
};

package MyWebServer;

use HTTP::Server::Simple::CGI;
use base qw(HTTP::Server::Simple::CGI);
use Text::ExtractWords qw(words_count);

use Template::Declare;
Template::Declare-&gt;init( dispatch_to =&gt; ['MyView::Templates'] );

my %dispatch = (
    '/'       =&gt; \&amp;resp_homepage,
    '/submit' =&gt; \&amp;resp_submit,
);

sub handle_request {
    my $self = shift;
    my $cgi  = shift;

    my $path    = $cgi-&gt;path_info();
    my $handler = $dispatch{$path};

    if ( ref($handler) eq &quot;CODE&quot; ) {
        print &quot;HTTP/1.0 200 OK\r\n&quot;;
        $handler-&gt;($cgi);

    }
    else {
        print &quot;HTTP/1.0 404 Not found\r\n&quot;;
        print $cgi-&gt;header( -charset =&gt; 'UTF-8' ),
          $cgi-&gt;start_html('Not found'),
          $cgi-&gt;h1('Not found'),
          $cgi-&gt;end_html;
    }
}

sub resp_homepage {
    my $cgi = shift;
    return if !ref $cgi;

    print $cgi-&gt;header( -charset =&gt; 'UTF-8' ), Template::Declare-&gt;show('main');
}

sub resp_submit {
    my $cgi = shift;
    return if !ref $cgi;

    my $title  = $cgi-&gt;param('title');
    my $result = {};
    words_count( $result, $title, {} );

    print $cgi-&gt;header( -charset =&gt; 'UTF-8' ),
      Template::Declare-&gt;show( 'result', $title, $result );
}

package main;

my $server = MyWebServer-&gt;new(9999);
$server-&gt;run();
</pre>
</p>
<p>
J'ai créé un <a href="http://gist.github.com/310598">gist de cet outil sur Github</a>, et je compte l'améliorer quand
j'aurai un peu de temps. 
</p>]]>
    </content>
</entry>

<entry>
    <title>La réinvention de la roue grâce à MARC::Record</title>
    <link rel="alternate" type="text/html" href="http://blog.bjornoya.be/lab_stacks/2010/02/la-reinvention-de-la-roue-grace-a-marcrecord.html" />
    <id>tag:blog.bjornoya.be,2010:/lab_stacks//1.19</id>

    <published>2010-02-09T21:20:57Z</published>
    <updated>2010-02-09T22:12:18Z</updated>

    <summary><![CDATA[Dernièrement sur la liste de diffusion perl4lib, une question a été posée concernant l'existence d'une solution permettant de diviser un fichier MARC trop gros en plusieurs fichiers plus petits. 


Comme beaucoup d'utilisateurs de fichiers MARC, et de programmeurs manipulant
des fichiers MARC, j'ai été confronté à ce problème et j'avais développé une
petite solution rapide :



#!/usr/bin/env perl

use strict;
use warnings;

use MARC::File::USMARC;
use MARC::Record;

use Getopt::Long;

my $config = { output =&gt; 'input' };

GetOptions($config, 'input=s', 'chunk=s', 'output=s', 'max=s');

if (not exists $config-&gt;{input} and not exists $config-&gt;{chunk}) {
    die &quot;Usage: $0 --input file --chunk size [--output file]\n&quot;;
} else {
    run($config-&gt;{input}, $config-&gt;{output}, $config-&gt;{chunk}, $config-&gt;{max});
    
}

sub run {
    my ($input, $output, $chunk, $max) = @_;

    my $marcfile = MARC::File::USMARC-&gt;in($input);
    
    my $fh = $output eq 'input' ? create_file($input) : create_file($output);
    my $cpt = 1;
        my $total = 0;
    while (my $record = $marcfile-&gt;next) {
        $total++;
        
        if (defined $max) {
            last if $total &gt; $max;
        }
        if ($cpt++ &gt; $chunk) {
            close $fh;
            $fh = $output eq 'input' ? create_file($input) : create_file($output);
            $cpt = 1;
        } 

        print $fh $record-&gt;as_usmarc;
    }   
    close $fh;
}

sub create_file {
    my ($output) = @_;
    my $cpt = 0;
    
    my $filename = sprintf('%s.%03d', $output, $cpt++);
    while (-e $filename) {
        $filename = sprintf('%s.%03d', $output, $cpt++);
    }

    open my $fh, '&gt;', $filename;
    return $fh;
}



Cet outil est l'exemple même de solution qu'un bibliothécaire - documentaliste
devrait être à même de programmer (pour autant qu'il souhaite programmer, bien
entendu). L'algorithme employé est loin d'être compliqué (même si cela reste
un bon exercice), et il s'agit d'une exploitation de modules existants (vive le CPAN !) pour
lesquels il existe de la documentation. Bref, un bel exemple de paresse et
de spécicialisation. 


Néanmoins, une meilleure solution que ce marcsplit.pl est sans aucun doute
l'utilisation de l'utilitaire yaz-marcdump comme l'indique Sébastien Hinderer. Voici quelques exemples :


yaz-marcdump -C 5000 export.mrc : cela créera des fichiers de 5000 notices
dont le nom sera de la forme suivante : 0000001, 0000002, etc


yaz-marcdump -C 5000 -s export_by_5000- export.mrc : permettra de
spécifier un préfixe aux fichiers créés, dans l'exemple, cela nous donnera
des fichiers de la forme suivante : export_by_5000-0000001,
export_by_5000-0000002, etc

]]></summary>
    <author>
        <name>manu</name>
        
    </author>
    
        <category term="Français" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="cpan" label="cpan" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="marc" label="MARC" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="marcrecord" label="MARC::Record" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl" label="perl" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="fr" xml:base="http://blog.bjornoya.be/lab_stacks/">
        <![CDATA[<p>Dernièrement sur la liste de diffusion <a href="http://perl4lib.perl.org/">perl4lib</a>, une <a href="http://www.mail-archive.com/perl4lib@perl.org/msg01380.html">question a été posée concernant l'existence d'une solution permettant de diviser un fichier MARC trop gros</a> en plusieurs fichiers plus petits. 
</p>
<p>
Comme beaucoup d'utilisateurs de fichiers MARC, et de programmeurs manipulant
des fichiers MARC, j'ai été confronté à ce problème et j'avais développé une
petite solution rapide :
</p>
<p>
<pre class='brush: perl'>
#!/usr/bin/env perl

use strict;
use warnings;

use MARC::File::USMARC;
use MARC::Record;

use Getopt::Long;

my $config = { output =&gt; 'input' };

GetOptions($config, 'input=s', 'chunk=s', 'output=s', 'max=s');

if (not exists $config-&gt;{input} and not exists $config-&gt;{chunk}) {
    die &quot;Usage: $0 --input file --chunk size [--output file]\n&quot;;
} else {
    run($config-&gt;{input}, $config-&gt;{output}, $config-&gt;{chunk}, $config-&gt;{max});
    
}

sub run {
    my ($input, $output, $chunk, $max) = @_;

    my $marcfile = MARC::File::USMARC-&gt;in($input);
    
    my $fh = $output eq 'input' ? create_file($input) : create_file($output);
    my $cpt = 1;
        my $total = 0;
    while (my $record = $marcfile-&gt;next) {
        $total++;
        
        if (defined $max) {
            last if $total &gt; $max;
        }
        if ($cpt++ &gt; $chunk) {
            close $fh;
            $fh = $output eq 'input' ? create_file($input) : create_file($output);
            $cpt = 1;
        } 

        print $fh $record-&gt;as_usmarc;
    }   
    close $fh;
}

sub create_file {
    my ($output) = @_;
    my $cpt = 0;
    
    my $filename = sprintf('%s.%03d', $output, $cpt++);
    while (-e $filename) {
        $filename = sprintf('%s.%03d', $output, $cpt++);
    }

    open my $fh, '&gt;', $filename;
    return $fh;
}
</pre>
</p>
<p>
Cet outil est l'exemple même de solution qu'un bibliothécaire - documentaliste
devrait être à même de programmer (pour autant qu'il souhaite programmer, bien
entendu). L'algorithme employé est loin d'être compliqué (même si cela reste
un bon exercice), et il s'agit d'une exploitation de modules existants (vive le CPAN !) pour
lesquels il existe de la documentation. Bref, un bel exemple de paresse et
de spécicialisation. 
</p>
<p>
Néanmoins, une meilleure solution que ce <i>marc<sub>split</sub>.pl</i> est sans aucun doute
l'utilisation de l'utilitaire <i>yaz-marcdump</i> comme l'indique <a href="http://www.mail-archive.com/perl4lib@perl.org/msg01388.html">Sébastien Hinderer</a>. Voici quelques exemples :
</p><ul>
<li>
<code>yaz-marcdump -C 5000 export.mrc</code> : cela créera des fichiers de 5000 notices
dont le nom sera de la forme suivante : <i>0000001</i>, <i>0000002</i>, etc
</li>
<li>
<code>yaz-marcdump -C 5000 -s export_by_5000- export.mrc</code> : permettra de
spécifier un préfixe aux fichiers créés, dans l'exemple, cela nous donnera
des fichiers de la forme suivante : <i>export_by_5000-0000001</i>,
<i>export_by_5000-0000002</i>, etc
</li>
</ul>]]>
    </content>
</entry>

<entry>
    <title>Un coup d&apos;oeil sur les calendriers</title>
    <link rel="alternate" type="text/html" href="http://blog.bjornoya.be/lab_stacks/2009/12/un-coup-doeil-sur-les-calendriers.html" />
    <id>tag:blog.bjornoya.be,2009:/lab_stacks//1.18</id>

    <published>2009-12-10T18:33:50Z</published>
    <updated>2009-12-10T18:42:21Z</updated>

    <summary>Depuis quelques années maintenant, une initiative de la communauté Perl, que
l&apos;on peut appeler une tradition maintenant, s&apos;organise à cette période. Il
s&apos;agit d&apos;un calendrier de l&apos;Avent. Du premier décembre au jour de Noël
(l&apos;Avent donc), un article est publié pour expliquer tantôt un module, tantôt
une technique, ou encore un élément de la culture d&apos;un monger 1. 


A ma connaissance, il existe quatre calendriers de l&apos;Avent dans la communauté
Perl cette année. Chacun est consacré à un projet particulier de la
communauté : 


Perl : le calendrier du langage lui-même : http://www.perladvent.org
Perl 6 : 
le calendrier du futur Perl 6 : http://perl6advent.wordpress.com/
Catalyst : le calendrier d&apos;un des frameworks web écrits en Perl :
http://www.catalystframework.org/calendar
Plack : 
un rackup écrit en Perl : http://advent.plackperl.org/



J&apos;ai fait une courte recherche pour savoir si des communautés d&apos;autres
langages de programmation avaient suivi l&apos;initiative, mais je n&apos;ai rien trouvé
de vraiment suivi :


Ruby en a fait un en 2006 et en 2008, mais visiblement rien cette année ; 


PHP en a fait un en 2007, et un cette année ;


je n&apos;ai rien trouvé pour Python ;


et je me suis arrêté là ! N&apos;hésitez pas à déposer un commentaire pour me
faire découvrir d&apos;autres calendriers de ce type. 




Personnellement, je trouve que c&apos;est une initiative intéressante, d&apos;une part
cela permet d&apos;en apprendre plus sur un langage ou un logiciel en particulier,
et puis cela permet également d&apos;assurer une sorte de promotion pour l&apos;objet du
calendrier. 


Bref, en ce qui me concerne, bien plus intéressant que le calendrier d&apos;une célèbre marque de pneus, par exemple ;-)






Notes de bas de page: 

1 en français, on parlera de mongueur


</summary>
    <author>
        <name>manu</name>
        
    </author>
    
        <category term="Français" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="culture" label="culture" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl" label="perl" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="fr" xml:base="http://blog.bjornoya.be/lab_stacks/">
        <![CDATA[<p>Depuis quelques années maintenant, une initiative de la <a href="http://www.perl.org">communauté Perl</a>, que
l'on peut appeler une tradition maintenant, s'organise à cette période. Il
s'agit d'un calendrier de l'Avent. Du premier décembre au jour de Noël
(l'Avent donc), un article est publié pour expliquer tantôt un module, tantôt
une technique, ou encore un élément de la culture d'un <i>monger</i> <sup><a class="footref" name="fnr.1" href="#fn.1">1</a></sup>. 
</p>
<p>
A ma connaissance, il existe quatre calendriers de l'Avent dans la communauté
Perl cette année. Chacun est consacré à un projet particulier de la
communauté : 
</p>
<ul>
<li><strong>Perl</strong> : le calendrier du langage lui-même : <a href="http://www.perladvent.org">http://www.perladvent.org</a></li>
<li><strong>Perl 6</strong> : 
le calendrier du futur Perl 6 : <a href="http://perl6advent.wordpress.com/">http://perl6advent.wordpress.com/</a></li>
<li><strong>Catalyst</strong> : le calendrier d'un des <i>frameworks</i> web écrits en Perl :
<a href="http://www.catalystframework.org/calendar">http://www.catalystframework.org/calendar</a></li>
<li><strong>Plack</strong> : 
un <em>rackup</em> écrit en Perl : <a href="http://advent.plackperl.org/">http://advent.plackperl.org/</a></li>
</ul>
</p>

<p>J'ai fait une courte recherche pour savoir si des communautés d'autres
langages de programmation avaient suivi l'initiative, mais je n'ai rien trouvé
de vraiment suivi :
</p><ul>
<li>
Ruby en a fait un en <a href="http://www.rubyinside.com/advent2006/">2006</a> et en <a href="http://www.rubyinside.com/the-2008-ruby-advent-calendar-1381.html">2008</a>, mais visiblement rien cette année ; 
</li>
<li>
PHP en a fait un en <a href="http://shiflett.org/blog/2007/dec/php-advent-calendar-day-1">2007</a>, et un <a href="http://phpadvent.org/2009">cette année</a> ;
</li>
<li>
je n'ai rien trouvé pour Python ;
</li>
<li>
et je me suis arrêté là ! N'hésitez pas à déposer un commentaire pour me
faire découvrir d'autres calendriers de ce type. 

</li>
</ul>

<p>Personnellement, je trouve que c'est une initiative intéressante, d'une part
cela permet d'en apprendre plus sur un langage ou un logiciel en particulier,
et puis cela permet également d'assurer une sorte de promotion pour l'objet du
calendrier. 
</p>
<p>
Bref, en ce qui me concerne, bien plus intéressant que le <a href="http://www.pirellical.com/thecal/home.page">calendrier d'une célèbre marque de pneus</a>, par exemple ;-)
</p>




<div id="footnotes">
<h2 class="footnotes">Notes de bas de page: </h2>
<div id="text-footnotes">
<p class="footnote"><sup><a class="footnum" name="fn.1" href="#fnr.1">1</a></sup> en français, on parlera de <b>mongueur</b>
</p>
</div>
</div>]]>
    </content>
</entry>

<entry>
    <title>A long time ago</title>
    <link rel="alternate" type="text/html" href="http://blog.bjornoya.be/lab_stacks/2009/11/a-long-time-ago.html" />
    <id>tag:blog.bjornoya.be,2009:/lab_stacks//1.17</id>

    <published>2009-11-30T09:23:19Z</published>
    <updated>2009-11-30T09:28:14Z</updated>

    <summary> Cela fait maintenant un bail que je n&apos;ai plus publié de billets sur ce
blog, mais cela ne signifie pas que Perl ne m&apos;a pas été utile dans
l&apos;intervalle. En fait, ce serait même plutôt le contraire ! Pour le moment, il
m&apos;est surtout utile pour faire des prototypes me permettant de mieux
comprendre certaines technologies. 


Ainsi, dans le GNU/Linux Magazine France du mois de novembre 2009, il y a un
article (Mettez un sphinx dans votre moteur de recherche !) sur un outil sur
lequel j&apos;avais déjà jetté un bref coup d&apos;oeil : Sphinx. Je n&apos;ai pas encore eu
le temps de finir l&apos;article (je suis en retard sur tout, je vous dis !), mais
le principe est de fournir un point d&apos;entrée à une base de données via une
requête. Les résultats de cette requête est alors indexée par un logiciel
extérieur (Sphinx en l&apos;occurrence). Ensuite lorsque l&apos;on veut effectuer une
recherche en texte intégral sur cette base de données, on commence par
interroger Sphinx pour obtenir les identifiants des données, on peut ensuite
récupérer les données directement dans la base de données. 


Je n&apos;ai pas de bases de données suffisamment importantes sous la main que pour
pouvoir vérifier si les promesses de performances sont au rendez-vous, mais
d&apos;après l&apos;auteur de l&apos;article, c&apos;est le cas ! 


Je m&apos;interroge donc sur la possibilité d&apos;utiliser Sphinx pour créer des OPACs
« nouvelle génération ». L&apos;avantage étant que le simple fait d&apos;ajouter Sphinx
dans le jeu permet d&apos;exploiter un langage de requête bien plus riche que les
OPACs classiques.


J&apos;ai déjà utilisé cette technique de l&apos;indexation par un programme extérieur
pour mettre à disposition une base de données Winisis via le protocole
Z39.50. J&apos;avais utilisé pour cela Perl, avec les modules suivants :

KinoSearch : 
s&apos;occupe de la partie indexation ;
Net::Z3950::SimpleServer : s&apos;occupe de la partie Z39.50.



Bref, tout cela me donne envie de tenter de réaliser un équivalent de Sphinx, mais en
Perl. En exploitant la versatilité de DBI, cela permettrait d&apos;offrir ce
service d&apos;indexation à quantité de bases de données ! 
</summary>
    <author>
        <name>manu</name>
        
    </author>
    
        <category term="Français" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="cpan" label="cpan" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="dbi" label="DBI" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="fulltextsearch" label="fulltext search" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="kinosearch" label="KinoSearch" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="netz3950simpleserver" label="Net-Z3950-SimpleServer" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl" label="perl" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="sphinx" label="Sphinx" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="fr" xml:base="http://blog.bjornoya.be/lab_stacks/">
        <![CDATA[ <p>Cela fait maintenant un bail que je n'ai plus publié de billets sur ce
blog, mais cela ne signifie pas que Perl ne m'a pas été utile dans
l'intervalle. En fait, ce serait même plutôt le contraire ! Pour le moment, il
m'est surtout utile pour faire des prototypes me permettant de mieux
comprendre certaines technologies. 
</p>
<p>
Ainsi, dans le <a href="http://www.gnulinuxmag.com/index.php/2009/10/30/gnulinux-magazine-n°121-novembre-2009-chez-votre-marchand-de-journaux">GNU/Linux Magazine France du mois de novembre 2009</a>, il y a un
article (<i>Mettez un sphinx dans votre moteur de recherche !</i>) sur un outil sur
lequel j'avais déjà jetté un bref coup d'oeil : <a href="http://www.sphinxsearch.com/">Sphinx</a>. Je n'ai pas encore eu
le temps de finir l'article (je suis en retard sur tout, je vous dis !), mais
le principe est de fournir un point d'entrée à une base de données via une
requête. Les résultats de cette requête est alors indexée par un logiciel
extérieur (<a href="http://www.sphinxsearch.com/">Sphinx</a> en l'occurrence). Ensuite lorsque l'on veut effectuer une
recherche en texte intégral sur cette base de données, on commence par
interroger <a href="http://www.sphinxsearch.com/">Sphinx</a> pour obtenir les identifiants des données, on peut ensuite
récupérer les données directement dans la base de données. 
</p>
<p>
Je n'ai pas de bases de données suffisamment importantes sous la main que pour
pouvoir vérifier si les promesses de performances sont au rendez-vous, mais
d'après l'auteur de l'article, c'est le cas ! 
</p>
<p>
Je m'interroge donc sur la possibilité d'utiliser <a href="http://www.sphinxsearch.com/">Sphinx</a> pour créer des <a href="http://fr.wikipedia.org/wiki/Online_public_access_catalog">OPACs</a>
« nouvelle génération ». L'avantage étant que le simple fait d'ajouter <a href="http://www.sphinxsearch.com/">Sphinx</a>
dans le jeu permet d'exploiter un langage de requête bien plus riche que les
OPACs classiques.
</p>
<p>
J'ai déjà utilisé cette technique de l'indexation par un programme extérieur
pour mettre à disposition une base de données <a href="http://portal.unesco.org/ci/en/ev.php-URL_ID=5330&amp;URL_DO=DO_TOPIC&amp;URL_SECTION=201.html">Winisis</a> via le protocole
<a href="http://www.loc.gov/z3950/">Z39.50</a>. J'avais utilisé pour cela Perl, avec les modules suivants :
<ul>
<li><a href="http://search.cpan.org/dist/KinoSearch">KinoSearch</a> : 
s'occupe de la partie indexation ;</li>
<li><a href="http://search.cpan.org/dist/Net-Z3950-SimpleServer/">Net::Z3950::SimpleServer</a> : s'occupe de la partie Z39.50.</li>
</ul>
</p>

<p>Bref, tout cela me donne envie de tenter de réaliser un équivalent de <a href="http://www.sphinxsearch.com/">Sphinx</a>, mais en
Perl. En exploitant la versatilité de <a href="http://search.cpan.org/dist/DBI/">DBI</a>, cela permettrait d'offrir ce
service d'indexation à quantité de bases de données ! 
</p>]]>
    </content>
</entry>

<entry>
    <title>Un outil en plus : CPAN::Mini::Webserver</title>
    <link rel="alternate" type="text/html" href="http://blog.bjornoya.be/lab_stacks/2009/11/un-outil-en-plus-cpanminiwebserver.html" />
    <id>tag:blog.bjornoya.be,2009:/lab_stacks//1.16</id>

    <published>2009-11-10T22:52:42Z</published>
    <updated>2009-11-10T22:53:57Z</updated>

    <summary> Perl est vraiment un outil que j&apos;apprécie dans ma boîte à outils, et comme
beaucoup d&apos;autres programmeurs Perl, ce que j&apos;apprécie particulièrement, c&apos;est
de pouvoir compter sur le travail de tant d&apos;autres pour m&apos;aider à résoudre mes
problèmes quotidiens. Parfois, les services rendus ne sont pas de l&apos;ordre du
support pour terminer un travail, mais simplement de rendre une situation
encore plus comfortable.


M&apos;appuyant souvent sur le CPAN, j&apos;en suis venu à me faire une copie sur mon
disque dur que je garde synchronisé aussi régulièrement que possible. Ce
travail est réalisé par l&apos;excellent minicpan (CPAN::Mini). Me voici donc
dans la situation agréable d&apos;avoir toujours à porter de main une archive du
CPAN, que je sois connecté à Internet ou non. Mais le CPAN ne se limite pas à
cela, c&apos;est également l&apos;outil que je consulte pour lire la documentation (oui,
je sais perldoc est là pour cela), mais que faire quand je suis sur la route
? C&apos;est simple, utiliser minicpanwebserver (CPAN::Mini::Webserver). Ce
dernier s&apos;appuie sur le fichier de configuration de minicpan, et met à
disposition le tout via un serveur web. Je peux maintenant faire des
recherches, lire la documentation, les tests, et je peux même lancer
l&apos;installation à partir de cette interface. Bref, un CPAN survitaminé ! A
essayer ! 
</summary>
    <author>
        <name>manu</name>
        
    </author>
    
        <category term="Français" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="cpan" label="cpan" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="minicpan" label="minicpan" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl" label="perl" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="toolbox" label="toolbox" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="fr" xml:base="http://blog.bjornoya.be/lab_stacks/">
        <![CDATA[ <p>Perl est vraiment un outil que j'apprécie dans ma boîte à outils, et comme
beaucoup d'autres programmeurs Perl, ce que j'apprécie particulièrement, c'est
de pouvoir compter sur le travail de tant d'autres pour m'aider à résoudre mes
problèmes quotidiens. Parfois, les services rendus ne sont pas de l'ordre du
support pour terminer un travail, mais simplement de rendre une situation
encore plus comfortable.
</p>
<p>
M'appuyant souvent sur le <a href="http://search.cpan.org">CPAN</a>, j'en suis venu à me faire une copie sur mon
disque dur que je garde synchronisé aussi régulièrement que possible. Ce
travail est réalisé par l'excellent <b>minicpan</b> (<a href="http://search.cpan.org/dist/CPAN-Mini/">CPAN::Mini</a>). Me voici donc
dans la situation agréable d'avoir toujours à porter de main une archive du
CPAN, que je sois connecté à Internet ou non. Mais le <a href="http://search.cpan.org">CPAN</a> ne se limite pas à
cela, c'est également l'outil que je consulte pour lire la documentation (oui,
je sais <code>perldoc</code> est là pour cela), mais que faire quand je suis sur la route
? C'est simple, utiliser <b>minicpan<sub>webserver</sub></b> (<a href="http://search.cpan.org/dist/CPAN-Mini-Webserver/">CPAN::Mini::Webserver</a>). Ce
dernier s'appuie sur le fichier de configuration de <b>minicpan</b>, et met à
disposition le tout via un serveur web. Je peux maintenant faire des
recherches, lire la documentation, les tests, et je peux même lancer
l'installation à partir de cette interface. Bref, un <a href="http://search.cpan.org">CPAN</a> survitaminé ! A
essayer ! 
</p>]]>
    </content>
</entry>

<entry>
    <title>Am I connected?</title>
    <link rel="alternate" type="text/html" href="http://blog.bjornoya.be/lab_stacks/2009/10/am-i-connected.html" />
    <id>tag:blog.bjornoya.be,2009:/lab_stacks//1.15</id>

    <published>2009-10-31T22:40:19Z</published>
    <updated>2009-10-31T22:42:02Z</updated>

    <summary>La plupart des outils que je développe s&apos;appuie sur LWP, et donc, j&apos;ai besoin
d&apos;un accès au web pour les faire fonctionner (belle lapalissade !). Et parmi
ces outils, certains sont prévus pour se lancer via cron, et donc se pose la
question de savoir ce qui se passe pour le programme quand il se lance et que
je ne suis pas connecté. Une des manières de traiter le problème consiste à
modifier le programme de manière à ne lancer le traitement que lorsque l&apos;accès
au web est opérationnel. C&apos;est ici que LWP::Online vient me rendre service. Il
me permet d&apos;importer une fonction, online(), qui va vérifier si un accès
au web est bien présent. Si c&apos;est le cas, la fonction retournera une valeur
positive. LWP::Online vérifie l&apos;accès au web en vérifiant la présence des
copyrights sur certains sites comme Google et Yahoo!, cela rajoute donc une
certaine latence dans votre programme, mais cela reste intéressant pour
certains outils. 
</summary>
    <author>
        <name>manu</name>
        
    </author>
    
        <category term="Français" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="cpan" label="cpan" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="lwp" label="lwp" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl" label="perl" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="fr" xml:base="http://blog.bjornoya.be/lab_stacks/">
        <![CDATA[<p>La plupart des outils que je développe s'appuie sur <a href="http://search.cpan.org/dist/libwww-perl/">LWP</a>, et donc, j'ai besoin
d'un accès au web pour les faire fonctionner (belle lapalissade !). Et parmi
ces outils, certains sont prévus pour se lancer via <a href="http://en.wikipedia.org/wiki/Crontab">cron</a>, et donc se pose la
question de savoir ce qui se passe pour le programme quand il se lance et que
je ne suis pas connecté. Une des manières de traiter le problème consiste à
modifier le programme de manière à ne lancer le traitement que lorsque l'accès
au web est opérationnel. C'est ici que <a href="http://search.cpan.org/dist/LWP-Online/">LWP::Online</a> vient me rendre service. Il
me permet d'importer une fonction, <i>online()</i>, qui va vérifier si un accès
au web est bien présent. Si c'est le cas, la fonction retournera une valeur
positive. <a href="http://search.cpan.org/dist/LWP-Online/">LWP::Online</a> vérifie l'accès au web en vérifiant la présence des
<i>copyrights</i> sur certains sites comme <a href="http://www.google.com">Google</a> et <a href="http://www.yahoo.com">Yahoo!</a>, cela rajoute donc une
certaine latence dans votre programme, mais cela reste intéressant pour
certains outils. 
</p>]]>
    </content>
</entry>

<entry>
    <title>Un biscuit pour un autre</title>
    <link rel="alternate" type="text/html" href="http://blog.bjornoya.be/lab_stacks/2009/10/un-biscuit-pour-un-autre.html" />
    <id>tag:blog.bjornoya.be,2009:/lab_stacks//1.14</id>

    <published>2009-10-22T21:13:44Z</published>
    <updated>2009-10-22T21:17:59Z</updated>

    <summary><![CDATA[ Dernièrement, je me suis trouvé confronté à un problème plutôt idiot, mais
néanmoins gênant. J'utilise depuis quelques années maintenant les services
offerts par un site. J'ai dû me connecter à ce site dernièrement, mais 


je ne me souvenais plus de mon mot de passe !

la réinitialisation du mot de passe était difficiel car pas moyen de me souvenir de l'adresse de courrier électronique employée pour créer le compte !



Damned! Comment faire ? 


Et bien, se féliciter d'être paresseux ! En effet, pour profiter des services
de ce site, je m'étais écrit un petit robot en Perl avec LWP. Ce brave outil
fonctionnait toujours puisqu'il s'appuyait sur un cookie. Ce cookie était
dans le format propriétaire de HTTP::Cookies, je devais donc le convertir dans
le format de Mozilla Firefox. 


Aussitôt dit, aussitôt fait. Une petite recherche sur le web, et je trouve un
article des mongueurs expliquant un cas de conversion de cookies, mais de
Mozilla vers LWP. Après quelques tâtonnements, j'ai finalement adapté le
programme. Le voici :

#!/usr/bin/env perl

use strict;
use warnings;

use HTTP::Cookies;
use HTTP::Cookies::Mozilla;
use Getopt::Long;

my $config = {};

GetOptions( $config, 'from=s', 'to=s' );

die _usage() unless _valid_config( $config );

my $input_jar = HTTP::Cookies-&gt;new( file =&gt; $config-&gt;{from} );
bless $input_jar, 'HTTP::Cookies::Mozilla';

$input_jar-&gt;save( $config-&gt;{to} );

sub _usage {
    return &quot;Usage: $0 --from cookies.lwp --to cookies.mozilla\n&quot;;
}

sub _valid_config {
    my $config = shift;

    if (exists $config-&gt;{from} and exists $config-&gt;{to}) {
        return 1;   
    } else {
        return 0;
    }
}



Il m'a donc suffit d'appeler ce programme de la manière suivante : $./cookies_converter -f my_lwp_cookie.txt -t /path/to/mozilla/profile/cookies.sqlite 


Ensuite, j'ai pu aller sur la page de mon compte pour changer mon mot de
passe et mettre une adresse de courrier électronique plus récente. 
]]></summary>
    <author>
        <name>manu</name>
        
    </author>
    
        <category term="Français" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="lwp" label="lwp" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl" label="perl" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="fr" xml:base="http://blog.bjornoya.be/lab_stacks/">
        <![CDATA[ <p>Dernièrement, je me suis trouvé confronté à un problème plutôt idiot, mais
néanmoins gênant. J'utilise depuis quelques années maintenant les services
offerts par un site. J'ai dû me connecter à ce site dernièrement, mais 
</p><ol>
<li>
je ne me souvenais plus de mon mot de passe !
</li>
<li>la réinitialisation du mot de passe était difficiel car pas moyen de me souvenir de l'adresse de courrier électronique employée pour créer le compte !
</li>
</ol>

<p><i>Damned!</i> Comment faire ? 
</p>
<p>
Et bien, se féliciter d'être paresseux ! En effet, pour profiter des services
de ce site, je m'étais écrit un petit robot en <a href="http://www.perl.org">Perl</a> avec <a href="http://search.cpan.org/dist/libwww-perl/">LWP</a>. Ce brave outil
fonctionnait toujours puisqu'il s'appuyait sur un <a href="http://fr.wikipedia.org/wiki/Cookie_(informatique)">cookie</a>. Ce <i>cookie</i> était
dans le format propriétaire de <a href="http://search.cpan.org/dist/libwww-perl/lib/HTTP/Cookies.pm">HTTP::Cookies</a>, je devais donc le convertir dans
le format de <a href="http://www.mozilla.com/en-US/firefox/firefox.html">Mozilla Firefox</a>. 
</p>
<p>
Aussitôt dit, aussitôt fait. Une petite recherche sur le web, et je trouve un
<a href="http://articles.mongueurs.net/magazines/linuxmag56.html#h4.1">article</a> des <a href="http://www.mongueurs.net/">mongueurs</a> expliquant un cas de conversion de <i>cookies</i>, mais de
Mozilla vers LWP. Après quelques tâtonnements, j'ai finalement adapté le
programme. Le voici :
<pre class='brush: perl'>
#!/usr/bin/env perl

use strict;
use warnings;

use HTTP::Cookies;
use HTTP::Cookies::Mozilla;
use Getopt::Long;

my $config = {};

GetOptions( $config, 'from=s', 'to=s' );

die _usage() unless _valid_config( $config );

my $input_jar = HTTP::Cookies-&gt;new( file =&gt; $config-&gt;{from} );
bless $input_jar, 'HTTP::Cookies::Mozilla';

$input_jar-&gt;save( $config-&gt;{to} );

sub _usage {
    return &quot;Usage: $0 --from cookies.lwp --to cookies.mozilla\n&quot;;
}

sub _valid_config {
    my $config = shift;

    if (exists $config-&gt;{from} and exists $config-&gt;{to}) {
        return 1;   
    } else {
        return 0;
    }
}
</pre>
</p>
<p>
Il m'a donc suffit d'appeler ce programme de la manière suivante : <code>$./cookies_converter -f my_lwp_cookie.txt -t /path/to/mozilla/profile/cookies.sqlite</code> 
</p>
<p>
Ensuite, j'ai pu aller sur la page de mon compte pour changer mon mot de
passe et mettre une adresse de courrier électronique plus récente. 
</p>]]>
    </content>
</entry>

<entry>
    <title>Aidez-moi à remplir mon buffer</title>
    <link rel="alternate" type="text/html" href="http://blog.bjornoya.be/lab_stacks/2009/10/aidez-moi-a-remplir-mon-buffer.html" />
    <id>tag:blog.bjornoya.be,2009:/lab_stacks//1.13</id>

    <published>2009-10-19T15:26:55Z</published>
    <updated>2009-10-19T15:30:59Z</updated>

    <summary>Au détour d&apos;un tweet, j&apos;ai découvert un petit outil venant compléter
emacs. Il s&apos;agit du projet perl-completion.el. Ce dernier permet
d&apos;avoir une auto-complétion intelligente, c&apos;est-à-dire qui ne se limite pas
aux contenus des buffers ouverts. Vous pouvez ainsi obtenir une aide pour le
nom des modules, mais aussi des méthodes exportées par ces modules. Bref, un
must ! 


Si vous voulez en voir plus, il y a un screencast qui vous permettra
d&apos;apprécier le travail fait. Il y a également un dépôt git en ligne. 


Enjoy!

</summary>
    <author>
        <name>manu</name>
        
    </author>
    
        <category term="Français" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="emacs" label="emacs" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl" label="perl" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="fr" xml:base="http://blog.bjornoya.be/lab_stacks/">
        <![CDATA[<p>Au détour d'un <a href="http://twitter.com/learnemacs/status/4406693678"><i>tweet</i></a>, j'ai découvert un petit outil venant compléter
<a href="http://www.gnu.org/software/emacs/">emacs</a>. Il s'agit du projet <a href="http://www.emacswiki.org/emacs/PerlCompletion">perl-completion.el</a>. Ce dernier permet
d'avoir une auto-complétion intelligente, c'est-à-dire qui ne se limite pas
aux contenus des <i>buffers</i> ouverts. Vous pouvez ainsi obtenir une aide pour le
nom des modules, mais aussi des méthodes exportées par ces modules. Bref, un
<i>must</i> ! 
</p>
<p>
Si vous voulez en voir plus, il y a un <a href="http://www.vimeo.com/4739908">screencast</a> qui vous permettra
d'apprécier le travail fait. Il y a également un <a href="http://github.com/imakado/perl-completion/">dépôt git en ligne</a>. 
</p>
<p>
<i>Enjoy!</i>
</p>
]]>
    </content>
</entry>

<entry>
    <title>Donnez-moi vos feuilles !</title>
    <link rel="alternate" type="text/html" href="http://blog.bjornoya.be/lab_stacks/2009/10/-peu-de-temps-pour.html" />
    <id>tag:blog.bjornoya.be,2009:/lab_stacks//1.12</id>

    <published>2009-10-08T19:34:46Z</published>
    <updated>2009-10-08T19:40:53Z</updated>

    <summary><![CDATA[ 
Peu de temps pour programmer ces derniers temps, mais qu'importe, voici un
petit outil programmé aujourd'hui. Il permet d'afficher les feuilles d'un
document XML. En effet, j'ai eu entre les mains un fichier à convertir, il
s'agissait d'un export XML provenant de BCDI. Or, je ne connaissais
pas ce vocabulaire XML et je voulais illustrer une migration de données.
j'avais donc besoin d'une liste des feuilles de cet arbre XML, où je pourrai
tirer quelques éléments pour effectuer la pseudo migration. Aussitôt pensé,
aussitôt fait. 


Perl peut utiliser la libxml avec le module XML::LibXML et via cette
dernière, je peux appliquer des expressions XPath sur mon fichier
XML. L'expression XPath en question est **//*[count()=0]*. Le reste est
vraiment simplissime.


Voici le code : 

#!/usr/bin/env perl

use strict;
use warnings;

use XML::LibXML;
use Getopt::Long;

my $config = {};

GetOptions( $config, 'xml=s' );

_usage() if not _validated( $config );

my $parser = XML::LibXML-&gt;new();
my $catalog = $parser-&gt;parse_file( $config-&gt;{xml} );

my @nodes = $catalog-&gt;findnodes( '//*[count(*)=0]' );
my %leaf_nodes;
foreach my $node (@nodes) {
    my $path = $node-&gt;nodePath();
    $path =~ s/\[\d+\]//g;
    $leaf_nodes{$path}++;
}

print ($_, $/) foreach keys %leaf_nodes;

sub _usage {
    die &quot;Usage: $0 --xml file.xml\n&quot;;
}

sub _validated {
    my $config = shift;
    
    if (exists $config-&gt;{xml}) {
        return 1;
    } else {
        return 0;
    }
}



L'outil est tellement simpliste qu'il ne me sera probablement plus utile
demain, mais au moins, j'ai une base pour analyser un éventuel fichier XML
en vue d'une migration. Les prochains billets traiteront d'ailleurs
probablement de migration de catalogues de bibliothèques. 
]]></summary>
    <author>
        <name>manu</name>
        
    </author>
    
        <category term="Français" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="catalogue" label="catalogue" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="migration" label="migration" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl" label="perl" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="xml" label="xml" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="xpath" label="xpath" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="fr" xml:base="http://blog.bjornoya.be/lab_stacks/">
        <![CDATA[ <p>
Peu de temps pour programmer ces derniers temps, mais qu'importe, voici un
petit outil programmé aujourd'hui. Il permet d'afficher les feuilles d'un
document XML. En effet, j'ai eu entre les mains un fichier à convertir, il
s'agissait d'un export XML provenant de <a href="http://bcdi.crdp2-poitiers.org/site/">BCDI</a>. Or, je ne connaissais
pas ce vocabulaire XML et je voulais illustrer une migration de données.
j'avais donc besoin d'une liste des feuilles de cet arbre XML, où je pourrai
tirer quelques éléments pour effectuer la pseudo migration. Aussitôt pensé,
aussitôt fait. 
</p>
<p>
Perl peut utiliser la <a href="http://xmlsoft.org">libxml</a> avec le module <a href="http://search.cpan.org/dist/XML-LibXML/">XML::LibXML</a> et via cette
dernière, je peux appliquer des expressions XPath sur mon fichier
XML. L'expression XPath en question est **//*[count(<b>)=0]*</b>. Le reste est
vraiment simplissime.
</p>
<p>
Voici le code : 
<pre class='brush: perl'>
#!/usr/bin/env perl

use strict;
use warnings;

use XML::LibXML;
use Getopt::Long;

my $config = {};

GetOptions( $config, 'xml=s' );

_usage() if not _validated( $config );

my $parser = XML::LibXML-&gt;new();
my $catalog = $parser-&gt;parse_file( $config-&gt;{xml} );

my @nodes = $catalog-&gt;findnodes( '//*[count(*)=0]' );
my %leaf_nodes;
foreach my $node (@nodes) {
    my $path = $node-&gt;nodePath();
    $path =~ s/\[\d+\]//g;
    $leaf_nodes{$path}++;
}

print ($_, $/) foreach keys %leaf_nodes;

sub _usage {
    die &quot;Usage: $0 --xml file.xml\n&quot;;
}

sub _validated {
    my $config = shift;
    
    if (exists $config-&gt;{xml}) {
        return 1;
    } else {
        return 0;
    }
}
</pre>
</p>
<p>
L'outil est tellement simpliste qu'il ne me sera probablement plus utile
demain, mais au moins, j'ai une base pour analyser un éventuel fichier XML
en vue d'une migration. Les prochains billets traiteront d'ailleurs
probablement de migration de catalogues de bibliothèques. 
</p>]]>
    </content>
</entry>

</feed>
