summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChimrod <contact+git@chimrod.com>2013-04-16 21:27:30 +0200
committerChimrod <contact+git@chimrod.com>2013-04-16 21:27:30 +0200
commit66a5a0cdccd464930a232c87f91e1b0805f255a5 (patch)
tree1563108cc22cfdc250108eb25b3beaf51d398dff
initial commit
-rw-r--r--Makefile76
-rwxr-xr-xcontent/Informatique/apache.rst46
-rwxr-xr-xcontent/Informatique/awesome.rst97
-rwxr-xr-xcontent/Informatique/backup.rst77
-rwxr-xr-xcontent/Informatique/chiffrage.rst74
-rwxr-xr-xcontent/Informatique/chroot.rst230
-rwxr-xr-xcontent/Informatique/elinks.rst47
-rwxr-xr-xcontent/Informatique/fail2ban.rst162
-rwxr-xr-xcontent/Informatique/fonctionnel.rst190
-rwxr-xr-xcontent/Informatique/invisible.rst106
-rwxr-xr-xcontent/Informatique/navit.rst212
-rwxr-xr-xcontent/Informatique/rst.rst181
-rwxr-xr-xcontent/Informatique/rstodt.rst59
-rwxr-xr-xcontent/Informatique/sftp.rst138
-rwxr-xr-xcontent/Informatique/vala.rst153
-rwxr-xr-xcontent/Informatique/wiimote.rst121
-rwxr-xr-xcontent/Informatique/wiimote1.rst60
-rwxr-xr-xcontent/Perso/inculture.rst103
-rwxr-xr-xcontent/Perso/infrarouge.rst19
-rwxr-xr-xcontent/Perso/net.rst51
-rwxr-xr-xcontent/ecafe.rst119
-rwxr-xr-xcontent/ecafe2.rst58
-rwxr-xr-xcontent/images/2011avril23_120334.jpgbin0 -> 196681 bytes
-rwxr-xr-xcontent/images/Capture-Navit-1-e1332786990864.pngbin0 -> 385853 bytes
-rwxr-xr-xcontent/images/Capture-Navit-e1332787251467.pngbin0 -> 84016 bytes
-rwxr-xr-xcontent/images/conf-300x175.jpgbin0 -> 15558 bytes
-rwxr-xr-xcontent/images/filezilla-300x140.jpgbin0 -> 11550 bytes
-rwxr-xr-xcontent/images/menu.pngbin0 -> 21904 bytes
-rwxr-xr-xcontent/images/puttygen-300x276.jpgbin0 -> 16717 bytes
-rwxr-xr-xcontent/publish.sh6
-rwxr-xr-xpelicanconf.py41
-rw-r--r--publishconf.py18
-rwxr-xr-xtheme/LISEZ-MOI.rst16
-rwxr-xr-xtheme/screenshot.pngbin0 -> 68419 bytes
-rwxr-xr-xtheme/static/css/main.css280
-rwxr-xr-xtheme/static/css/pygment.css205
-rwxr-xr-xtheme/static/css/styles.css25
-rwxr-xr-xtheme/static/images/atom.jpgbin0 -> 2640 bytes
-rwxr-xr-xtheme/static/images/atom.pngbin0 -> 3000 bytes
-rwxr-xr-xtheme/static/images/fond.jpgbin0 -> 1378 bytes
-rwxr-xr-xtheme/static/images/header.jpgbin0 -> 49473 bytes
-rwxr-xr-xtheme/static/images/rss.jpgbin0 -> 2630 bytes
-rwxr-xr-xtheme/static/images/rss.pngbin0 -> 2631 bytes
-rwxr-xr-xtheme/templates/archives.html17
-rwxr-xr-xtheme/templates/article.html40
-rwxr-xr-xtheme/templates/author.html2
-rwxr-xr-xtheme/templates/authors.html0
-rwxr-xr-xtheme/templates/base.html55
-rwxr-xr-xtheme/templates/categories.html17
-rwxr-xr-xtheme/templates/category.html31
-rwxr-xr-xtheme/templates/header.html3
-rwxr-xr-xtheme/templates/index.html31
-rwxr-xr-xtheme/templates/menu.html53
-rwxr-xr-xtheme/templates/meta.html5
-rwxr-xr-xtheme/templates/navigator.html15
-rwxr-xr-xtheme/templates/page.html12
-rwxr-xr-xtheme/templates/tag.html31
-rwxr-xr-xtheme/templates/tags.html13
58 files changed, 3295 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..824b521
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,76 @@
+PELICAN=pelican
+PELICANOPTS=
+
+BASEDIR=$(CURDIR)
+INPUTDIR=$(BASEDIR)/content
+OUTPUTDIR=$(BASEDIR)/output
+CONFFILE=$(BASEDIR)/pelicanconf.py
+PUBLISHCONF=$(BASEDIR)/publishconf.py
+
+FTP_HOST=localhost
+FTP_USER=anonymous
+FTP_TARGET_DIR=/
+
+SSH_HOST=localhost
+SSH_PORT=22
+SSH_USER=root
+SSH_TARGET_DIR=/var/www
+
+DROPBOX_DIR=~/Dropbox/Public/
+
+help:
+ @echo 'Makefile for a pelican Web site '
+ @echo ' '
+ @echo 'Usage: '
+ @echo ' make html (re)generate the web site '
+ @echo ' make clean remove the generated files '
+ @echo ' make regenerate regenerate files upon modification '
+ @echo ' make publish generate using production settings '
+ @echo ' make serve serve site at http://localhost:8000'
+ @echo ' make devserver start/restart develop_server.sh '
+ @echo ' ssh_upload upload the web site via SSH '
+ @echo ' rsync_upload upload the web site via rsync+ssh '
+ @echo ' dropbox_upload upload the web site via Dropbox '
+ @echo ' ftp_upload upload the web site via FTP '
+ @echo ' github upload the web site via gh-pages '
+ @echo ' '
+
+
+html: clean $(OUTPUTDIR)/index.html
+ @echo 'Done'
+
+$(OUTPUTDIR)/%.html:
+ $(PELICAN) $(INPUTDIR) -o $(OUTPUTDIR) -s $(CONFFILE) $(PELICANOPTS)
+
+clean:
+ find $(OUTPUTDIR) -mindepth 1 -delete
+
+regenerate: clean
+ $(PELICAN) -r $(INPUTDIR) -o $(OUTPUTDIR) -s $(CONFFILE) $(PELICANOPTS)
+
+serve:
+ cd $(OUTPUTDIR) && python -m SimpleHTTPServer
+
+devserver:
+ $(BASEDIR)/develop_server.sh restart
+
+publish:
+ $(PELICAN) $(INPUTDIR) -o $(OUTPUTDIR) -s $(PUBLISHCONF) $(PELICANOPTS)
+
+ssh_upload: publish
+ scp -P $(SSH_PORT) -r $(OUTPUTDIR)/* $(SSH_USER)@$(SSH_HOST):$(SSH_TARGET_DIR)
+
+rsync_upload: publish
+ rsync -e "ssh -p $(SSH_PORT)" -P -rvz --delete $(OUTPUTDIR) $(SSH_USER)@$(SSH_HOST):$(SSH_TARGET_DIR)
+
+dropbox_upload: publish
+ cp -r $(OUTPUTDIR)/* $(DROPBOX_DIR)
+
+ftp_upload: publish
+ lftp ftp://$(FTP_USER)@$(FTP_HOST) -e "mirror -R $(OUTPUTDIR) $(FTP_TARGET_DIR) ; quit"
+
+github: publish
+ ghp-import $(OUTPUTDIR)
+ git push origin gh-pages
+
+.PHONY: html help clean regenerate serve devserver publish ssh_upload rsync_upload dropbox_upload ftp_upload github
diff --git a/content/Informatique/apache.rst b/content/Informatique/apache.rst
new file mode 100755
index 0000000..1101266
--- /dev/null
+++ b/content/Informatique/apache.rst
@@ -0,0 +1,46 @@
+.. -*- mode: rst -*-
+.. -*- coding: utf-8 -*-
+
+Un code retour personalisé avec apache
+######################################
+
+:date: 2012-08-12
+:tags: Libre, Hébergement
+
+Petite astuce pour un problème que j'ai rencontré il y a quelques temps avec
+apache. Je souhaitais modifier le code retour d'une requête (en l'occurrence
+remplacer un code 403 par 404).
+
+J'ai été surpris de ne trouver aucun module pour le faire, sécurité,
+redirection ou autre contrôle sur les requêtes.
+
+La solution trouvée fut d'utiliser un script cgi, qui se charge de faire la
+réponse à la place d'apache, et est appelé en page d'erreur. Cela donne :
+
+.. code-block:: bash
+
+ ScriptAlias /cgi-bin/ /home/www/cgi/
+ ErrorDocument 403 /cgi-bin/404.cgi
+
+Le script en question est fait en bash pour simplifier les choses :
+
+.. code-block:: bash
+
+ #!/bin/sh
+ echo Status: 404 Not Found
+ echo Content-type: text/html
+ echo
+ cat << EOM
+ <!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">
+ <html><head>
+ <title>404 Not Found</title>
+ </head><body>
+ <h1>Not Found</h1>
+ <p>The requested URL ${REQUEST_URI} was not found on this server.</p>
+ <hr>
+ <address>Apache/2.2.22 (Debian) Server at chimrod.com Port 80</address>
+ </body></html>
+ EOM
+ exit 0
+
+et voilà !
diff --git a/content/Informatique/awesome.rst b/content/Informatique/awesome.rst
new file mode 100755
index 0000000..0e9e6e9
--- /dev/null
+++ b/content/Informatique/awesome.rst
@@ -0,0 +1,97 @@
+.. -*- mode: rst -*-
+.. -*- coding: utf-8 -*-
+
+Un menu pour awesome
+####################
+
+:date: 2010-06-06
+:tags: Libre
+
+Awesome est un window manager (wm) en mode pavement ( les fenêtres se
+disposent de manière à ne jamais se chevaucher ). Cela permet de ne pas
+avoir à se soucier de la manière dont il faut gérer l'affichage des
+applications.
+
+|Awesome|
+
+Une des particularité est que sa configuration se fait par un fichier de
+script exécuté au lancement du bureau. Cela permet de paramétrer comme
+on le souhaite le bureau sans être limité par le WM. La contrepartie est
+que cela est plus difficile à prendre en main, et une erreur de code
+entraîne un écran gris au lieu du bureau que l'on souhaite obtenir... Le
+langage utilisé ( Lua ) est un langage connu pour sa légèreté. Pour
+l'instant, le projet étant encore assez jeune, il n'existe pas encore
+beaucoup de modules standardisés pour configurer le système, mais je
+pense que ceux-ci ne tarderont pas à venir...
+
+Pour l'instant la configuration n'est pas encore stabilisée, certains
+composants changent au cours d'une version à une autre, ce qui casse
+parfois la mise à jour et oblige à retravailler les scripts de mise de
+configuration. Je pense cependant que tout cela suit la bonne direction
+et que ces soucis finiront par disparaître avec le temps et les versions
+suivantes
+
+La plupart des actions peuvent être associées à un raccourci clavier, et
+si il est possible d'affiche une barre d'outil à chaque applications («
+titlebar »), on prend vite l'habitude de s'en passer et de tout
+contrôler au clavier. On est d'autant plus aidé par cela par
+`shifty <http://awesome.naquadah.org/wiki/Shifty>`_ une extension qui
+permet de « programmer » la manière dont on veut que les fenêtres
+s'affichent : sur quel écran, avec quels paramètres etc. Cela permet par
+exemple d'avoir une configuration pour des applications utilisant
+plusieurs fenêtres ( je pense par exemple à Gimp ) paramétrée comme on
+le souhaite…
+
+On prend vite l'habitude également d'utiliser plusieurs « tags » (
+l'équivalent de bureaux virtuels mais un peu plus étendus ) : ceux-ci
+peuvent être paramétrés pour afficher des applications sépicifiques (
+j'ai par exemple adapté ma configuration pour que *web* affiche firefox,
+ou que *news* affiche le couple elinks/newsbeuter pour lire mes flux
+RSS…
+
+Bien sûr le temps de paramétrage au début est un peu long, mais
+maintenant que l'API est stable, il n'est plus nécessaire de tout
+reprendre à chaque fois que l'on met à jour awesome.
+
+Je trouvais qu'il manquait à Awesome un menu avec les actions
+disponibles sur les fenêtres : la faire passer au premier plan, la
+minimiser… Tout ceci est disponible avec des raccourcis claviers, mais
+il n'y a pas d'option centralisée pour les retrouver. J'ai donc décidé
+de me plonger un petit peu dans lua pour produire le menu que voilà :
+
+|Menu pour awesome| Le menu permet les actions suivantes :
+
+- On top : Pour mettre le client sélectionné au premier plan et le
+ rendre flottant
+- Sticky : Faire apparaître le client sur tous les tags
+- Minimize : Réduire le client
+- Close : Fermer le client
+- Move To : Déplacer le client vers un autre tag
+
+Le script fonctionne avec awesome 3.4.5, les versions antérieures ne
+sont pas forcement compatibles suite à un changement dans l'ABI du menu.
+J'essaierai également de le mettre à jour pour les versions suivantes (
+du moins tant que je m'en servirai…)
+
+Pour le faire fonctionner, il faut télécharger le script et le placer
+dans son répertoire ${HOME}/.config/awesome . Ensuite, éditer le fichier
+rc.lua et y ajouter la ligne suivante en en-tête :
+
+::
+
+ require("mymenu")
+
+et dans la partie Key Binding :
+
+::
+
+ clientkeys = awful.util.table.join(
+ […]
+ awful.key({ modkey, }, "Down", function(c) menu_instance = newAppMenu(c) end),
+
+Le menu apparaîtra sur le raccourci Mod4 + Flèche du bas
+
+Le fichier : `mymenu.lua <http://chimrod.com/downloads/mymenu.lua>`_
+
+.. |Awesome| image:: http://awesome.naquadah.org/index/320x240-screen.png
+.. |Menu pour awesome| image:: |filename|../images/menu.png
diff --git a/content/Informatique/backup.rst b/content/Informatique/backup.rst
new file mode 100755
index 0000000..8b6fc90
--- /dev/null
+++ b/content/Informatique/backup.rst
@@ -0,0 +1,77 @@
+.. -*- mode: rst -*-
+.. -*- coding: utf-8 -*-
+
+Un système de backup automatique
+################################
+
+:date: 2009-10-18
+:tags: Libre
+
+On le sait tous, il faut faire des sauvegardes de manière régulière. On
+le sais également, pour que celles-ci se fasse sur le long terme, il
+faut que celles-ci se fassent de manière automatique, et sur un autre
+support que le PC que l'on souhaite sauvegarder. Le problème qui se pose
+est le suivant : comment concilier ces deux conditions sur un PC de
+bureau ( ne disposant donc pas d'une série de serveur allumés en
+permanences et prêt à recevoir nos sauvegardes en continue… ) ?
+
+Pour répondre à tout cela, nous allons mettre en place un système de backup sur
+disque dur externe, qui se lancera à chaque fois que notre disque sera monté. À
+chaque fois que le disque dur sera allumé, la sauvegarde s'enclenchera. Cela ne
+garantie pas, bien sûr que les sauvegardes se feront à un intervalle régulier,
+mais cela garantie au moins que nous n'aurons pas à nous en soucier. Pour cela
+nous allons utiliser les outils qui sont disponibles sous un environnement
+Linux : rsync et hal. Cet article nous présente une base pour faire notre
+sauvegarde `Une sauvegarde améliorée avec rsync
+<http://informatique-et-liberte.tuxfamily.org/2009/05/10/une-sauvegarde-amelioree-avec-rsync/>`_.
+Nous allons juste devoir le modifier un petit peu pour répondre à un problème
+qui arrive souvent avec les périphériques USB : selon que d'autres
+périphériques sont déjà montés ou non, nous ne savons pas dans quel répertoire
+nous allons nous trouve. Il va donc falloir mettre en place une ligne pour
+récupérer le répertoire dans lequel nous sommes. Il ne nous reste plus qu'à
+trouver le moyen de l'éxécuter automatiquement pour cela nous allons utiliser
+halevt. Le script est disponible `ici
+<http://chimrod.com/downloads/backup.sh>`_
+
+Comme son nom l'indique, halevt est un gestionnaire d'évènements pour hal. Hal
+est un gestionnaire d'évènement matériel sous Linux; il envoie des informations
+à chaque fois que des informations sont envoyées depuis les composants. Cela
+permet de détecter le branchement d'un périphérique USB et de le monter sur le
+bureau ( et qui nous simplifie grandement la vie aujourd'hui !!!). Halevt est
+un démon à l'écoute des informations qui nous sont envoyées par hal, et
+d'activer des actions en conséquence : par exemple pour lancer l'antivirus sur
+la clef usb, reconfigurer le mappage du clavier en fonction de la marque que
+l'on branche etc. Pour notre part, nous allons nous contenter de lancer un
+script (celui du backup mentionné plus haut ).
+
+Pour commencer nous allons devoir identifier le lecteur à mettre sous
+surveillance : inutile de se baser sur les noms de montage habituels ( /dev/sda
+par exemple ) en effet en fonction des périphériques déjà branchés nous
+n'allons pas obtenir la même configuration. Nous allons utiliser les point de
+montage défini dans /dev/disk/by-uuid qui permet d'obtenir l'identifiant
+de notre disque (et qui sera repris par la suite dans la configuration de hal
+). Une fois que nous avons relevé quel est le disque concerné, il faut mettre
+en place une entrée pour notre évènement dans la configuration de halevt :
+
+::
+
+ <halevt:Device match="hal.block.device &amp; hal.block.is_volume = true &amp; hal.volume.uuid = fd20536f-7b80-4a80-8c3d-b5bebe8fb484">
+ <halevt:Property name="hal.volume.is_mounted">
+ <halevt:Action value="true" exec="bash $hal.volume.mount_point$/chemin/script/backup-ssh.sh"/>
+ </halevt:Property>
+ </halevt:Device>
+
+Cela si halevt est exécuté avec les droits de l'utilisateur lançant le
+backup. Si on le fait tourner en démon, il faut trouver une autre
+solution ( sur mon poste j'ai utilisé sudo, mais on peut très bien se
+baser sur le sticky bit pour donner les droits au script ). De même,
+dans la configuration mise en place, le script se trouve sur le disque
+de stockage ( de manière à pouvoir le lancer à la main si le démon n'est
+pas disponible ), cela peut être adapté en fonction de chacun…
+
+Dans le cas d'une configuration multi-utilisateur, je pense qu'il est
+nécessaire de passer par un script qui lance les différentes sauvegardes sous
+le bon groupe de l'utilisateur à chaque fois. ( Ce qui en plus permet d'éviter
+le problème du sudo ) mais je n'ai pas eu besoin d'aller jusque là pour
+l'instant ! À vous d'adapter ce que je vous propose en fonction de votre
+configuration !
diff --git a/content/Informatique/chiffrage.rst b/content/Informatique/chiffrage.rst
new file mode 100755
index 0000000..1ceef6b
--- /dev/null
+++ b/content/Informatique/chiffrage.rst
@@ -0,0 +1,74 @@
+.. -*- mode: rst -*-
+.. -*- coding: utf-8 -*-
+
+Mettre en place une solution de chiffrage avec authentification forte
+#####################################################################
+
+:date: 2008/11/07
+:tags: Libre
+
+Voici une méthode que j'ai mis en place pour protéger l'accès à mon
+répertoire /home via Cryptsetup. Il existes de nombreux tutoriels
+expliquant comment créer une partition chiffrée, je ne vais pas
+détailler cela ici. L'intérêt du script que je propose ici est qi'il se
+lance au moment du login, et qu'il va chercher le mot de passe sur une
+clef USB.
+
+Charger le mot de passe contenu dans la clef USB
+------------------------------------------------
+
+Il suffit juste de l'insérer avant de se logguer, et de la retirer une
+fois l'authentification réussie.
+
+Voici le script en question
+
+::
+
+ #!/bin/sh
+
+ #Si la clef n'est pas insérée, refuse le login
+ [ -b /dev/disk/by-uuid/chemin-de-la-clef ] || exit 1
+
+ if [ -b /dev/mapper/home ]
+ then
+ #Si la partition est deja montée, connecte
+ exit 0
+ else
+
+ # Monte la clef
+ mkdir /tmp/clef/
+ mount /dev/disk/by-uuid/chemin-de-la-clef /tmp/clef/ 2>/tmp/out
+
+ # Déchiffre la partition
+ /sbin/cryptsetup luksOpen -d /tmp/clef/clef /dev/disk/by-uuid/chemin-de-la-clef home 2>>/tmp/out
+
+ # Démonte la clef, elle peut maintenant être retirée sans pb
+ umount /tmp/clef
+ rmdir /tmp/clef/
+
+ mount -o defaults -t ext2 /dev/mapper/home /home
+ exit 0
+
+ fi
+
+Bien sûr, il faut que la clef soit contenue dans le fichier clef sur le
+périphérique USB.
+
+Mettre le script au login de l'utilisateur
+------------------------------------------
+
+Maintenant, 2ème étape, il s'agit de lancer ce script au moment où
+l'utilisateur vient de se logguer. Comme je passe par un login manager
+sur mon portable ( GDM ), j'ai choisi d'utiliser ses ressources pour
+lancer le script. En effet, GDM possède des scripts qui sont lancés aux
+différents moments de la connexion. Ce qui nous intéresse ici se trouve
+dans le fichier : /etc/gdm/PostLogin/Default
+
+Il suffit d'y coller notre script ( ou d'y faire appel ) , et notre partition
+sera activée automatiquement lors de la connexion ( et seulement si le mot de
+passe est valide ).
+
+On peut obtenir des paramètres de la part de GDM dans ce script, nom de
+l'utilisateur qui se loggue, répertoire de login etc, cela permet de
+personnaliser notre script si on le souhaite.. Un code de retour en erreur
+refusera le login, que le mot de passe entré soit bon ou non...
diff --git a/content/Informatique/chroot.rst b/content/Informatique/chroot.rst
new file mode 100755
index 0000000..ce5a733
--- /dev/null
+++ b/content/Informatique/chroot.rst
@@ -0,0 +1,230 @@
+.. -*- mode: rst -*-
+.. -*- coding: utf-8 -*-
+
+Mettre en place un environnement sftp chrooté
+#############################################
+
+:date: 2010-04-08
+:tags: Libre, Hébergement
+
+*Note* : Je propose une autre approche pour mettre en place cette
+solution :
+`mettre-en-place-un-environnement-sftp-chroote-2/ <|filename|sftp.rst>`_
+
+La demande
+~~~~~~~~~~
+
+Ma copine m'a demandé de trouver une solution simple pour échanger des
+fichier avec sa sœur, msn posant des problèmes… J'ai pensé à mon serveur
+ssh et mettre en place une connexion sftp pour ça. Sur le principe cela
+a été adopté avec une petite présentation de filezilla (je ne sais pas
+s'il existe des clients sftp intégrés sous windows ?), j'ai donc
+commencé à mettre en place le système. De mon côté, la condition
+principale est de n'autoriser les connexions que par clef publique ( pas
+de mot de passe ), ma copine a tenu à ce que sa sœur ne puisse pas
+accéder aux documents présents dans son home, et du mien à ce que l'on
+ne puisse pas pour autant se promener dans l'arborescence du serveur :
+il va donc falloir chrooter l'environnement. Il existe pas mal de
+documentation la dessus sur internet, mais je me suis souvent retrouvé
+face à des exemples incorrects ou incompatible avec le fait de passer
+par une clef publique, je vais donc détailler les problèmes rencontrés.
+
+Le compte + clef publique
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+La première étape est de créer le compte, cela se fait assez simplement
+:
+
+::
+
+ # adduser ${user}
+
+|Création de la clef ssh avec puttygen| et en répondant aux questions
+par défaut… Vient ensuite la clef publique : filezilla gère les clefs
+privés au format ppk ( putty ) et je n'ai pas trouvé d'outil pour les
+générer sous windows. Je suis donc passé par wine + puttygen pour créer
+la clef. Une fois celle-ci crée, on enregistre la partie publique et la
+partie privée de la clef. La clef publique va être enregistrée dans le
+fichier ${user}/.ssh/know\_host sur le serveur pour autoriser le client
+à s'y connecter. La clef privée sera enregistrée de son côté au format
+ppk pour être utilisée par filezilla (il est possible à partir de ce
+fichier de générer une clef privée de type openssh ).
+
+|image1|
+
+Il faut ensuite intégrer la clef privée dans filezilla en passant par
+les paramètres : elle sera automatiquement lue à la connexion ( il faut
+choisir «interactive» dans le type d'authentification ). ( Attention :
+sous windows j'ai rencontré des problèmes avec un répertoire contenant
+des accents, la clef semblait être lue, mais la connexion ne se faisait
+pas pour autant. )
+
+Chrooter l'environnement
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Aujourd'hui il est possible de chrooter nativement un environnement sftp
+avec openssh. Il faut pour cela mettre en place une condition sur
+l'utilisateur ( ou le groupe ) pour faire le chroot :
+
+::
+
+ Match user ${user}
+ ChrootDirectory /var/chroot/
+ X11Forwarding no
+ AllowTcpForwarding no
+ ForceCommand internal-sftp
+
+Dans cet exemple le chemin /var/chroot sera utilisé comme racine lors
+des connexions sftp. Ce répertoire doit être détenu par root:root et
+avoir les droits 755. Cela veut dire que si notre utilisateur à pour
+répertoire home /home/${user}, il se retrouvera dans
+/var/chroot/home/${user} lors des connexions sftp. Il est nécessaire de
+conserver le répertoire home de l'utilisateur pour que ssh accepte une
+connexion par clef. En effet, lorsque l'utilisateur va se connecter, ssh
+va lire dans son répertoire personnel pour lire le fichier
+.ssh/know\_host et autoriser ou non la clef qui se présente. Ce qui
+signifie que si l'on modifie le répertoire personnel, il faut aussi
+déplacer cette arborescence ( hors de question dans ce cas de mettre /
+comme racine de l'utilisateur ). À noter : j'ai préféré faire le match
+sur le nom de l'utilisateur plutôt que sur son groupe ( le groupe sera
+utilisé par ailleurs ). Dans le cas où nous avons plusieurs
+utilisateurs, il est possible de les mettre à la suite ( séparés par des
+virgules ). J'ai vu de nombreux tutoriaux qui indiquent comme répertoire
+de chroot « /home/%u » ( le répertoire de l'utilisateur standard ), et
+qui demandent de changer le répertoire de login de l'utilisateur par « /
+». Je pense que c'est une très mauvaise idée : d'une part parce que cela
+oblige à déposer les clefs à la racine du serveur, mais aussi à cause de
+la contrainte d'openssh demandant à ce que le répertoire root soit
+détenu par root : cela veut dire que l'utilisateur n'a pas le droit de
+déposer de fichiers ou de créer de répertoires dans son propre home ! Le
+plus simple est donc de prendre un autre répertoire pour l'échange, et
+laisser le home de l'utilisateur pour la configuration. ( Cela permet
+aussi d'être sûr que le répertoire .ssh ne sera pas effacé par erreur
+par l'utilisateur… ) J'ai donc mis un lien symbolique pour lier le /home
+de l'utilisateur avec son répertoire d'échange :
+
+::
+
+ # mkdir /home/${user}/echanges
+ # ln -s /var/chroot/home/${user} /home/${user}/echanges
+
+On retrouvera ainsi la possibilité de voir les fichiers déposés en
+passant par le /home de l'utilisateur ( même si ce dernier ne pourra pas
+y aller… )
+
+Isoler l'environnement
+~~~~~~~~~~~~~~~~~~~~~~
+
+Maintenant que nous avons empêché l'utilisateur de se balader sur
+l'ordinateur, nous allons l'empêcher de se balader dans les autres
+répertoires des utilisateurs : cela se fait en une ligne de commande
+(pour chacun des répertoires que nous allons ouvrir en sftp : )
+
+::
+
+ # for fichier in /var/chroot/home/*; do chmod o-r ${fichier}; done
+
+Et voilà ! Les utilisateurs peuvent voir qu'il existe d'autres comptes
+que le leur, mais ne peuvent pas y accéder.
+
+Autoriser le partage
+~~~~~~~~~~~~~~~~~~~~
+
+Maintenant que nous avons fermé les droits de manière générale il nous
+reste à autoriser le partage des fichiers ( après tout c'était le but de
+la demande !) de manière plus fine. Cela implique pour moi deux choses :
+
+#. permettre à un autre utilisateur d'accéder aux données présentes
+#. permettre à un autre utilisateur de déposer ( ou de supprimer des
+ donnée )
+
+Pour le premier point, c'est facile il suffit d'ajouter l'utilisateur A
+au groupe de l'utilisateur B :
+
+::
+
+ # usermod -a -G ${user} ${un_autre_utilisateur}
+
+Et l'utilsateur un\_autre\_utilisateur pourra donc accéder à l'ensemble
+des fichier pour les lire ( et éventuellement les rapatrier chez lui).
+Pour le second point ( possibilité d'écrire et modifier ) c'est un peu
+plus compliqué; en gros nous voulons que les fichiers déposés par sftp
+dans le répertoire de l'utilisateur ait comme groupe d'appartenance
+celui du propriétaire du répertoire ( quel que soit l'utilisateur qui
+dépose ) et qu'ils soient modifiable par le groupe ( g+w ) du
+propriétaire. Par exemple : l'utilisateur A dépose un fichier dans le
+répertoire d'échange de l'utilisateur B. Il faut que les droits de ce
+fichier se présentent ainsi une fois le transfert terminé :
+
+::
+
+ $ ls -l fichier
+ -rw-rw---- 1 utilisateurA utilisateurB
+
+( ainsi l'un et l'autre pourront supprimer le fichier ). Pour cela nous
+allons utiliser une « bidouille » de l'os : le sgid bit. Derrière ce nom
+barbare se trouve un marqueur qui permet de fixer le droit de tous les
+fichiers qui seront créés dans le répertoire ( plus d'info
+`ici <http://en.wikipedia.org/wiki/Setuid>`_ ). Pour le déterminer on
+passe par chmod :
+
+::
+
+ # chmod g+s /var/chroot/${user}
+
+Cela détermine bien quel est le groupe qui sera propriétaire du fichier,
+mais cela ne donne pas à ce groupe le droit de le modifier pour autant !
+Sous linux, c'est la commande umask qui permet de déterminer les droits
+des fichiers. Le problème est qu'il s'agit d'une commande lié à
+l'environnement de l'utilisateur, et non pas aux répertoires sur
+lesquels nous travaillons ( à moins de passer par les ACLs mais cela est
+déjà assez compliqué comme ça… ). Ici, nous sommes dans un environnement
+sftp, sans shell de login, donc sans possibilité d'exécuter la commande
+directement, il faut que ce soit le serveur sftp qui le configure. J'ai
+trouvé énormément de documentations ( la plupart des bidouillages ) pour
+contourner le problème, mais la solution la plus simple vient de la
+dernière version d'OpenSSH (5.4 ) sortie le 8 mars dernier.
+
+|image2|
+
+Une nouvelle option sur le serveur sftp permet d'indiquer quel est
+l'umask qui sera appliqué ( dans notre cas 002) : dans le
+fichier/etc/ssh/sshd\_config nous allons configurer les paramètres par
+défaut du serveur sftp : Remplacer :
+
+::
+
+ Subsystem sftp /usr/lib/openssh/sftp-server.sh
+
+par :
+
+::
+
+ Subsystem sftp /usr/lib/openssh/sftp-server -u 002
+
+Pour définir les droits umask qui seront appliqués par défaut pour
+toutes les connexions sftp par défaut. Ce paramétrage est à redéfinir
+pour les paramétrages personnalisés ( bloc Match ) :
+
+::
+
+ ForceCommand internal-sftp -u 002
+
+Conclusion
+~~~~~~~~~~
+
+Nous avons un environnement bien hermétique, pouvant gérer
+l'augmentation du nombre de compte ( il suffit de refaire les chmod dans
+notre environnement chrooté à la création du compte ), et hermétique. Le
+paramétrage côté serveur est effectivement assez lourd au début, mais je
+pense que la mise à jour ne demande pas trop de travail, et on gère les
+droits de manière assez fine ( en passant par les groupes ce qui me
+semble être dans la mentalité unix ). Pour le client, il n'y a pas grand
+chose à paramétrer ( récupérer la clef et l'intégrer ), et il n'y a
+aucun risque que celui-ci vienne casser son paramétrage. On peut même
+sauvegarder sa clef privée dans son home (le vrai ), au cas où il
+perdrait le fichier.
+
+.. |Création de la clef ssh avec puttygen| image:: |filename|../images/puttygen-300x276.jpg
+.. |image1| image:: |filename|../images/filezilla-300x140.jpg
+.. |image2| image:: |filename|../images/conf-300x175.jpg
diff --git a/content/Informatique/elinks.rst b/content/Informatique/elinks.rst
new file mode 100755
index 0000000..6f85114
--- /dev/null
+++ b/content/Informatique/elinks.rst
@@ -0,0 +1,47 @@
+.. -*- rst -*-
+.. -*- coding: utf-8 -*-
+
+Scripter elinks
+###############
+
+:date: 2012-02-18
+:tags: Libre
+
+elinks_ est un navigateur web, destiné à être utilisé en console. Il s'agit
+pour moi d'un très bon navigateur secondaire, en complément de firefox, qui à
+l'avantage de permettre une navigation légère, sans effets de javascript,
+publicités, idéale pour lire l'actualité, un peu moins pour faire une recherche
+sur un sujet.
+
+La semaine dernière, j'ai envoyé un message_ sur la mailing list du projet pour
+indiquer que je souhaitai entreprendre quelques modifications dans le code dans
+le but de le rendre davantage modulaire. Il est nativement scriptable dans
+différents langages (lua, python, perl...) mais les possbilités de scripts
+restent très limitées et ne permettent pas de changer grand chose au
+comportement du navigateur. Quand on a prit l'habitude de pouvoir configurer
+ses applications comme on le souhaite, cela devient difficile de ne pas pouvoir
+le faire.
+
+J'ai donc choisi de me pencher davantage sur le langage lua pour mettre en
+place les modifications voulues. J'ai déjà une expérience du lua comme scripts
+côté client, pour l'instant jamais du côté de l'API C. Après avoir lutté une
+petit peu, j'ai fini par comprendre et suis aujourd'hui en train de mettre les
+objets qui m'intéressent.
+
+Le but est de permettre de scripter complètement la navigation : aujourd'hui,
+les seules interractions possibles permettent de modifier l'URL au moment où
+celle-ci est entrée, mais aucun accès au document n'est donné : impossible de
+récupérer les URLs, impossible de sélectionner un lien dans la page, ou de
+naviguer dans celle-ci. C'est tout cela que je souhaite mettre en place, en
+proposant une API orientée objet qui sera modulable et réutilisable par la
+suite.
+
+Pour l'instant, les modifications ne sont pas encore visibles, je fait le
+commit sur mon propre serveur git, mais je rendrai public mon projet dès que
+j'aurai obtenu un résultat intéressant : je n'attendrai pas d'avoir fini pour
+tout publier; soyez patient !
+
+.. _elinks: http://elinks.or.cz/index.html
+.. _message: http://linuxfromscratch.org/pipermail/elinks-dev/2012-February/002049.html
+
+
diff --git a/content/Informatique/fail2ban.rst b/content/Informatique/fail2ban.rst
new file mode 100755
index 0000000..993c704
--- /dev/null
+++ b/content/Informatique/fail2ban.rst
@@ -0,0 +1,162 @@
+.. -*- mode: rst -*-
+.. -*- coding: utf-8 -*-
+
+Une gestion avancée de fail2ban
+-------------------------------
+
+:date: 2008/09/15
+:tags: Libre, Hébergement
+
+Beaucoup d'articles sont déjà parus sur l'utilisation de fail2ban pour
+protéger son ordinateur. Je vais parler ici d'une utilisation avancée de
+fail2ban, couplé avec le pare-feu iptables dans le but de faire plein de
+joli de choses avec ceux qui tentent d'accéder à nos Pcs !
+
+Pour rappel, fail2ban permet de bloquer certaines IPs en fonction de ce
+que les logs renvoient comme messages. Il est possible de déterminer les
+ports sur lesquels les IPs seront bloquées et la durée du blocage. En ce
+qui concerne les filtres qui déclencheront ou non le blocage, cela se
+base sur des regex, et on peut déterminer le nombre de tentatives avant
+qu'un blocage ne soit appliqué.
+
+Dans l'esprit du projet, fail2ban empêche les attaques par force brute,
+mais nous allons voir qu'il est tout à fait possible de l'utiliser dans
+d'autres fins.
+
+Créer de nouvelles règles de filtrage
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Dans un premier temps, nous allons mettre en place une nouvelle règle de
+blocage pour, par exemple, bloquer les IPs en fonction des codes
+d'erreurs d'apache.
+
+Mettre en place une nouvelle règle se fait de manière très simple, il
+suffit de créer un fichier contenant la regex à appliquer, et de mettre
+une référence vers ce fichier dans la configuration de fail2ban.
+
+Dans notre cas, pour bloquer les IPs ayant générés une erreur 403 ou une
+erreur 401 dans apache, notre regex se présentera ainsi :
+
+::
+
+ failregex = :80 .* ".*" 403 = :80 .* ".*" 401
+
+(Celle-ci est bien sûr à adapter en fonction de la manière dont vous
+affichez vos logs de connexions. )
+
+Dans le fichier de configuration de fail2ban ( /etc/fail2ban/jail.conf
+), nous allons demander la lecture de ce fichier en indiquant quelques
+paramètres supplémentaires :
+
+::
+
+ [apache-block]
+ enabled = true #Oui on active
+ port = http #On ne bloque que le port 80
+ filter = apache-block # le nom du fichier que l'on a créé juste avant
+ action = %(action_)s
+ logpath = /tmp/log/apache*/*access.log
+ maxretry = 1 #Nombre de tentatives
+ banaction = iptables-redirect # L'action à appliquer sur l'IP
+ bantime = 3600 # Le temps pendant lequel l'ip sera bannie.
+
+
+Créer de nouvelles actions
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Une fois que fail2ban aura lancé une procédure de blocage sur une
+connexion, il va lancer un script contenant les actions à réaliser sur
+cette IP. D'habitude ce script contient une règle iptables qui bloque
+l'adresse, et une autre règle qui supprime ce blocage.
+
+Nous allons maintenant jouer avec iptables pour réaliser quelques
+effets intéressant avec nos IPs à bannir :
+
+Relancer la durée du blocage :
+
+Par défaut, fail2ban retire le blocage sur l'IP une fois que la durée
+spécifiée est écoulée. Je trouve ceci limité car cela n'empêche pas
+l'attaquant de continuer ses attaques et se retrouver prêt à refaire une
+attaque dès que cette durée est écoulée. De plus, cela peut donner une
+information sur la durée pendant laquelle nous filtrons son adresse.
+
+iptables propose un module, modrecent, permettant de bloquer une IP
+pendant une durée déterminée, et de réinitialiser cette durée si jamais
+une nouvelle connexions venait à être réalisée durant cette période.
+
+Pour ceci nous allons devoir une règle iptables, en dehors de fail2ban,
+qui consistera à bloquer une IP pendant telle période :
+
+Dans fail2ban, nous allons créer un nouveau fichier action, qui se
+présentera comme suit :
+
+::
+
+ #On crée une nouvelle table
+ actionstart = iptables -N fail2ban-<name>
+ #On bloque les connexions 2 fois sur 3
+ iptables -A fail2ban- -m statistic --mode random --probability .33 -j REJECT --reject-with icmp-host unreachable
+ iptables -A fail2ban-<name> -j DROP
+ #On insère une nouvelle règle qui met à jour le compteur à chaques nouvelles tentatives tant que le délai n'est pas écoulé
+ iptables -I INPUT -p <protocol> -m multiport --dports <port> -m recent --update --seconds 360000 --name fail2ban-- -j fail2ban-<name>
+
+ #Pour bannir une IP, il suffit de l'écrire dans le fichier de configuration de mod-recent
+ actionban = echo <ip> > /proc/net/ipt_recent/fail2ban-<name>
+
+Mettre un message d'alerte :
+
+On peut décider d'annoncer à notre utilisateur bloqué que nous avons
+banni son IP. Cela peut être utile si nous avons mis en place des règles
+de filtrage très strictes et qu'un utilisateur peut se retrouver bloqué
+sans avoir tenté la moindre intrusion ( mieux vaut être trop prudent que
+pas assez )
+
+Pour cela, nous allons avoir besoin d'un service qui consistera à
+afficher le texte sur demande. Hors de question de demander ça à apache
+ou autre serveur web, nous allons mettre en place notre propre serveur
+web, qui présentera une page statique, toujours identique.
+
+socat et tout désigné pour cela. Dans notre exemple nous allons le
+faire tourner en tant que serveur, sur un port ouvert, et avec des
+droits limités. Notre règle iptables consistera juste à rediriger les
+connexions entrantes sur le port 80 vers le port où l'on fait tourner
+socat.
+
+::
+
+ sudo -u nobody socat tcp4-listen:6666,reuseaddr,fork exec:"cat /etc/apache2/banned.html" &
+
+et la règle iptables à mettre en place :
+
+::
+
+ #On crée la règle sur la table de préroutage :
+ actionstart = iptables -t nat -N fail2ban-<name>
+ iptables -t nat -A fail2ban-<name> -j RETURN
+ iptables -t nat -I PREROUTING -p <protocol> -m multiport --dports <port>-j fail2ban-<name>
+
+ iptables -N fail2ban-<name>
+ iptables -A fail2ban-<name> -j RETURN
+ iptables -I INPUT -p <protocol> -m multiport --dports <port> -j fail2ban-<name>
+
+et pour lancer l'action, là encore, on simule une perte de paquet pour
+ralentir le temps d'affichage de la page
+
+::
+
+ actionban = iptables -t nat -I fail2ban-<name> 1 -s -p tcp -m multiport --dports <port> -m statistic --mode nth --every 3 -j REDIRECT --to-port 6666
+ iptables -I fail2ban-<name> 1 -s -j DROP
+
+Les règles d'unban et de stop se font en symetrique de ban et start, en
+supprimant des règles crées.
+
+Voilà, cela permet de mettre en place une sécurité personnalisée et
+adaptée, qui sort déjà des outils et configuration standards ( ce qui
+est toujours une bonne chose en matière de sécurité ). Les exemples que
+j'ai donné ne sont que des suggestions, et il possible de faire beaucoup
+d'autres choses avec un peu d'imaginations. Je vous renvoie au manuel
+d'iptables qui présente la liste de tous les modules existants, et de
+regarder un peu les paramètres disponibles parmi les fichiers de
+configuration de fail2ban. Mon seul regret est qu'à ce jour, ce
+programme ne gère pas encore les Ip en v6, mais ça n'est - pour
+l'instant - pas encore critique..
diff --git a/content/Informatique/fonctionnel.rst b/content/Informatique/fonctionnel.rst
new file mode 100755
index 0000000..292d8eb
--- /dev/null
+++ b/content/Informatique/fonctionnel.rst
@@ -0,0 +1,190 @@
+
+Programmation fonctionnelle (I)
+###############################
+
+:date: 2012-11-09
+:tags: Programmation
+
+Dans cet article, je vais essayer de présenter différents cas de programmation
+fonctionnelle en essayant de partir d'un cas pratique pour présenter les
+difficultés et solutions disponibles.
+
+Je vais présenter ici des exemples dans le langage python, par ce qu'il s'agit
+d'un langage simple, pouvant être utilisé de manière fonctionnelle (dans une
+certaine limite). Je me contente d'un python `basique` et ne vais pas chercher
+entrer dans des syntaxes spécifiques, le but étant ici de servir de support, et
+non pas de présenter le langage.
+
+Un besoin
+=========
+
+Imaginons la situation suivante : une application reçoit des données d'un
+client et doit les traiter. Ces données arrivent dans des fichiers textes,
+chaque ligne du fichier correspond à une donnée à traiter.
+
+Un programme
+============
+
+Commençons le programme, pour lire le fichier commençons par le localiser :
+
+.. code-block:: python
+
+ def get_file(nom):
+ chemin = os.path.join("repertoire", nom)
+ return open(chemin)
+
+Cette fonction est simple : elle prend en argument un nom de fichier, et
+retourne le fichier correspondant. On peut également dire qu'elle effectue la
+transformation suivante :
+
+.. code-block:: ocaml
+
+ get_file: String -> File
+
+Cette notation indique que le type de la fonction est le suivant : elle prend
+un string en entrée, et retourne un file en sortie. Nous l'utiliserons
+régulièrement dans cet article.
+
+Dans notre cas, nous n'avons pas un fichier a traiter, mais une série de
+fichiers. Nous allons donc devoir appeler la fonction sur tous nos nom de
+fichiers. La première solution est la solution itérative, à travers une boucle
+:
+
+.. code-block:: python
+
+ def transforme(noms):
+ fichiers = []
+ for nom in noms
+ fichiers.append(get_file(nom))
+ return fichiers
+
+À la fin de l'exécution de la boucle, la liste `fichiers` contient la liste des
+fichiers construits à partir de la liste `noms`.
+
+C'est une opération très fréquente et bien qu'elle soit très courte. Essayons
+de réfléchir un peu à ce que nous venons de faire en terme de type : notre but
+est de transformer une liste de String en liste de File de la manière suivante
+:
+
+.. code-block:: ocaml
+
+ transforme: List[String] -> List[File]
+
+Si l'on généralise, on peut essayer de créer une fonction qui aurait le schéma
+suivant :
+
+.. code-block:: ocaml
+
+ transforme: List[A] -> List[B]
+
+Cette fonction a par contre besoin d'une transformation à appliquer pour
+transformer A en B, dans notre cas, cette transformation a déjà été créée plus
+haut !
+
+Notre schéma devient donc le suivant :
+
+.. code-block:: ocaml
+
+ transforme: (A -> B) -> List[A] -> List[B]
+
+Récrivons donc notre fonction transforme de cette manière:
+
+.. code-block:: python
+
+ def transforme(func, source):
+ results = []
+ for nom in source
+ results.append(func(nom))
+ return results
+
+ fichiers = transforme(get_file, noms)
+
+Et voilà ! Nous avons maintenant notre fonction générique, destinée à changer
+le contenu de notre liste. Qu'est ce que cela apporte par rapport à la version
+impérative que nous avons écrit tout à l'heure ? En fait pas grand chose. Sauf
+que la fonction `transforme` est présente nativement dans python. Elle
+s'appelle en fait `map`, et effectue le même travail.
+
+Nous aurions donc tout aussi bien pu écrire :
+
+.. code-block:: python
+
+ fichiers = map(get_file, noms)
+
+Une réflexion
+=============
+
+Pourquoi avoir écrit tout ça ? Par ce que semblant de rien, nous avons changé
+notre manière de concevoir le programme : au lieu d'écrire une suite
+d'instructions qui s'exécutent séquentiellement, nous venons d'appliquer des
+transformations dans un contexte : la liste des noms de fichiers est notre
+contexte de base, sur lequel nous appliquons des transformations pour créer un
+autre contexte.
+
+Ces transformations ne modifient pas notre contexte initial, et par la suite
+les transformations que nous continueront d'appliquer ne modifieront rien non
+plus de notre environnement. Dans cet esprit, l'ensemble du programme peut être
+perçu comme un grande transformation qui s'applique sur un point d'entrée
+initial.
+
+Une théorie
+===========
+
+La fonction `map` que nous venons de présenter ici, s'inscrit en fait dans un
+cadre de fonctions plus vaste : les foncteurs_. Il s'agit d'une notion
+mathématique que l'on retrouve appliquée en informatique.
+
+.. _foncteurs: http://fr.wikipedia.org/wiki/Foncteur
+
+Comme vu précédemment, un objet foncteur F est un objet ayant la signature
+suivante :
+
+.. code-block:: ocaml
+
+ map: (A -> B) -> F[A] -> F[B]
+
+Le foncteur a deux contraintes, qui sont plutôt intuitives:
+
+identité
+--------
+
+Soit la fonction `id` défini comme suit:
+
+.. code-block:: python
+
+ def id(x):
+ return x
+
+alors on a l'égalité suivante :
+
+.. code-block:: python
+
+ map(id, fichiers) == fichiers
+
+Autrement dit, le foncteur ne doit pas modifier la structure de la donnée. On
+peut essayer de repenser la fonction `transforme` écrite plus haut pour briser
+cette règle, je laisse au lecteur le soin de réfléchir à cette question.
+
+composition
+-----------
+
+La deuxième contrainte est celle de la composition :
+
+.. code-block:: python
+
+ map(f(g), source) = map(f, map(g, source))
+
+C'est à dire qu'il est possible de composer les fonctions les entre elles :
+c'est encore heureux, car cela permet de chaîner les traitements entre eux…
+
+Une conclusion
+==============
+
+Notre contexte est ici une liste, mais nous allons voir par la suite qu'il en
+existe beaucoup d'autres, ce qui va nous faciliter la vie… Cela va venir dans
+les articles qui suivent.
+
+Une fois les deux contraintes validées, nous allons pouvoir construire de
+nouveaux types basés sur ce foncteur. Et derrière la solution informatique mise
+en place, je vais essayer de présenter les concepts mathématiques qui sont
+derrière.
diff --git a/content/Informatique/invisible.rst b/content/Informatique/invisible.rst
new file mode 100755
index 0000000..f531336
--- /dev/null
+++ b/content/Informatique/invisible.rst
@@ -0,0 +1,106 @@
+.. -*- mode: rst -*-
+.. -*- coding: utf-8 -*-
+
+Les utilisateurs invisibles de Linux
+####################################
+
+:date: 2010-02-17
+:tags: Libre
+
+Bonjour à tous, pour mon premier article sur le planet-libre, je
+voudrais faire part d'une réflexion qui m'interpelle depuis un moment
+concernant l'univers Linux : le fait que les utilisateurs non
+administrateurs soient exclus de toute la documentation/prise en main
+que l'on peut trouver sur le système. Je ne donne ici que quelques
+aspects de cette réflexion mais je pense qu'elle touche l'ensemble des
+participants au monde du libre.
+
+La plupart des articles que l'on peut voir sur le net qui concernent
+l'utilisation du PC sous Linux restent limités à un point : souvent ils
+oublient le fait que plusieurs utilisateurs puissent être enregistrés
+sur le PC, et que tous ne soient pas forcément des administrateurs (
+ceux qui peuvent avoir des droits root sur la machine ). Pourquoi donc ?
+Est-ce que cela signifie que la plupart des linuxiens sont les seuls à
+utiliser le PC ? C'est possible, mais là n'est pas mon sujet. Je pense
+que le problème est que les utilisateurs sont pour l'instant invisible
+de la littérature sur Linux que l'on peut trouver sur le net. À la fois
+invisible du côté des distributions, et invisible du côté des
+communautés.
+
+Le problème se retrouve présent dans deux aspects : d'une part dans la
+documentation s'adressant aux administrateurs, et d'autre part dans la
+documentaiton s'adressant aux utilisateurs.
+
+Si l'on suit les manipulations que l'on peut trouver un peu partout sur
+le net, on trouve souvent des modifications qui ont pour conséquences de
+modifier la configuration générale du système, et l'on trouve plus
+souvent des modifications dans /etc/ que dans ~/.config/
+
+Suivre les besoins des utilisateurs
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Tous les utilisateurs n'utilisent pas forcément l'ordinateur de la même
+manière et il faut prévoir quels sont leurs besoin avant de se lancer
+dans une opération générale. Par exemple, il n'y a pas longtemps était
+paru sur le planet-libre un article sur privoxy qui se terminait par une
+manière élégante d'utiliser privoxy sans configuration
+supplémentaire[1]. Or privoxy est lent pour traiter les sites puisant
+des ressources un peu partout — par exemple google news ou planet-libre
+(!) et se transformer en inconfort pour l'utilisateur.
+
+Les mises à jour
+~~~~~~~~~~~~~~~~
+
+Faire une mise à jour est toujours quelque chose de périlleux, et l'on
+ne sait pas forcément comment le système va réagir; entre le logiciel
+qui ne fonctionne plus car sa configuration a changé ou celui qui ne
+fonctionne plus car un bug a été introduit dans la nouvelle version, les
+risques sont possibles ( je n'ai par exemple pu plus lire de dvd lors de
+la mise à jour du noyau 2.6.30[2]… )
+
+Je ne veux pas relancer le débat sur le packaging des distributions (
+rolling release contre version fixes) mais le problème doit être posé :
+comment être sûr en faisant une mise à jour que l'on ne va pas casser
+tel composant ?
+
+En plus des modifications générales sur la configuration que peuvent
+introduire les modifications, on peut se retrouver dans la situation
+inverse : l'utilisateur n'a pas le droit de visualiser les fichiers de
+logs, d'installer un paquet ou de modifier un fichier de configuration
+et ne pourra donc pas suivre la documentation qu'il peut trouver ici et
+là sur le net.
+
+Pouvoir utiliser ses propres applications ?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Les distributions n'ont pour l'instant pas de solutions pour gérer
+l'installation de paquets par un utilisateur normal ( qui irait
+s'installer dans /opt// par exemple ), pouvant être installés sans droit
+root, et ne pouvant être exécutés que par l'utilisateur ayant fait son
+installation.
+
+Utiliser des commandes non root
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+En fait, ce système que l'on nous décrit ouvert ne l'est réellement que
+si l'on est admin dessus. Pour les autres, la manipulation se limite à
+bash, python… Dans la documentation, on trouve même des exemples
+demandant à l'utilisateur d'être root alors qu'une commande équivalente
+peut être lancée par un utilisateur normal ( par exemple $netstat -ie au
+lieu de #ifconfig )
+
+Ce problème de l'utilisateur non root est pour l'instant contourné (
+par exemple en configurant sudo dès l'installation ), mais il reste
+posé, et n'est jamais attaqué de front.
+
+Le fait que cette situation ne soit jamais évoquée est pour moi
+significative de l'utilisation faite de linux aujourd'hui : bien loin du
+grand public. Nous sommes tous ici des utilisateurs bidouilleurs, et ne
+voyons pas forcément une utilisation quotidienne d'un utilisateur
+standard. Je ne veux pas en faire une généralisation sur l'avenir de
+Linux et une remise en cause nécessaire. Je pose juste ici un constat
+sur une situation qui est pour moi, encore trop souvent invisible.
+
+[2] `Artisan Numérique » Se prémunir des "SpyWebs" avec
+Privoxy <http://artisan.karma-lab.net/node/1204>`_ [1]
+`http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=557340 <http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=557340>`_
diff --git a/content/Informatique/navit.rst b/content/Informatique/navit.rst
new file mode 100755
index 0000000..d15add6
--- /dev/null
+++ b/content/Informatique/navit.rst
@@ -0,0 +1,212 @@
+.. -*- mode: rst -*-
+.. -*- coding: utf-8 -*-
+
+Un gps libre avec Navit
+#######################
+
+:date: 2012-03-26
+:tags: Libre
+
+Depuis un peu plus d'un an maintenant, j'ai choisi d'utiliser Navit comme
+logiciel de navigation. Dans ce billet, je propose de faire un petit retour
+d'expérience sur ce logiciel et la manière de l'utiliser pour calculer les
+trajets à l'aide d'un GPS.
+
+Présentation
+============
+
+Navit est un logiciel de navigation, ce que l'on appelle souvent un « GPS ». Le
+logiciel fonctionne en mode déconnecté, c'est à dire qu'il à besoin de lire les
+cartes en local, mais ne nécessite aucune connexion réseau lors de la
+navigation. C'est un avantage qui lui permet de fonctionner sur des netbook
+sans clef 3G.
+
+Et c'est là tout l'avantage par rapport à une solution de navigation intégrée :
+il permet de transformer n'importe quel netbook (voire smartphone) en une
+solution de navigation GPS gratuitement ! Par rapport aux GPS que l'on
+rencontre souvent en voiture, le coût est ridicule !
+
+Fonctionnement
+==============
+
+À partir d'une connexion GPS intégrée (comme sur les smartphone) ou externe
+(par USB), Navit va mettre à jour en temps réel l'affichage de la carte et le
+calcul du trajet. La connexion gps est réalisée avec gpsd, capable de
+réceptionner les données depuis la plupart des récepteurs gps. Je n'ai eu aucun
+problème pour réaliser la connexion entre navit et gpsd, la carte commençant à
+se déplacer toute seule une fois les leds du GPS indiquant qu'il s'était
+synchronisé.
+
+Navit n'intègre aucune carte : par contre l'application a la possibilité
+d'utiliser les cartes dans les formats suivants :
+
+* garmin (pas testé)
+* reiserplan
+* openstreetmap_ (voir plus bas)
+
+Une caractéristique de navit est de ne pas présenter d'interface par défaut :
+tout passe par des modules que l'on vient rajouter dans l'interface et qui
+s'afficheront par dessus la carte. Par exemple :
+
+* Le nom de la rue sur laquelle on se trouve
+* L'heure d'arrivée
+* La vitesse
+* La distance avant le prochain changement de route
+* Une alerte quand on dépasse la vitesse autorisée
+* etc.
+
+Des configurations déjà prêtes sont disponibles sur le wiki et peuvent être
+téléchargées. Cela permet d'adapter l'affichage en fonction du support sur
+lequel l'application est lancée : sur un smartphone on privilégiera un
+affichage en vertical avec moins de modules par rapport à un ordinateur.
+
+Configuration
+=============
+
+Navit se base sur gpsd pour récupérer les données en provenance du récepteur.
+Je ne rentre pas ici dans l'installation et la configuration de gpsd, et vous
+renvoie vers la documentation de votre distribution pour le configurer.
+
+.. Note::
+
+ Il n'est pas nécessaire de disposer d'un récepteur GPS pour utiliser Navit.
+ C'est alors à l'utilisateur de déplacer la carte pour suivre son trajet,
+ mais en dehors de ce point, l'application se comportera de la même manière.
+
+Nous allons ensuite télécharger notre première carte, en passant par le `Navit
+planet extractor`_, qui propose de télécharger son jeu de carte sur internet :
+
+
+.. Note::
+
+ Notez l'url, nous allons la réutiliser plus tard !
+
+La configuration de navit est disponible dans le répertoire /etc/navit/ .
+Seulement, pour plus de commodité, nous allons la copier dans notre répertoire
+utilisateur :
+
+.. code-block:: bash
+
+ cp -r /etc/navit/ ~/.navit/
+
+Nous allons maintenant éditer le fichier XML est ajouter la carte dans la liste
+des cartes disponibles :
+
+.. code-block:: XML
+
+ <mapset enabled="yes">
+ <map type="binfile" enabled="yes" data="${VOTRE/CHEMIN/VERS/carte.bin}"/>
+ </mapset>
+
+Si l'on souhaite intégrer plusieurs cartes, il faut insérer plusieurs fois ce
+nœud XML.
+
+Relançons maintenant navit, la carte devrait s'afficher ! (Il se peut que vous
+ne voyiez rien car Navit n'est pas forcément positionné chez vous : on va donc
+chercher dans les villes une proche de chez nous et choisir de l'afficher sur
+la carte.)
+
+.. image:: |filename|../images/Capture-Navit-e1332787251467.png
+ :width: 400
+
+On peut déjà commencer à calculer les trajets et essayer différents habillages.
+Sur le wiki vous pouvez télécharger des thèmes déjà préparés qu'il suffit
+d'installer.
+
+Limitations
+===========
+
+Même si le logiciel est utilisable au quotidien, il n'est pas parfait. (Il
+s'est cependant grandement amélioré dans ses dernières versions, je recommande
+d'utiliser la version 0.5 qui corrige de nombreux soucis dans l'interface et la
+consommation mémoire.)
+
+* Une fâcheuse tendance de navit et de ne pas prendre en compte les limites
+ géographiques des villes. En conséquence, la sélection de la destination
+ à partir de la ville et des noms de rues n'est pas fiable : certaines
+ rues n'apparaissent pas alors qu'elles sont enregistrées sur la carte, ou
+ (plus grave), peut se tromper de ville. Il m'est déjà arrivé de me rendre
+ à destination, dans la bonne rue, mais pas dans la bonne ville !
+
+ J'ai maintenant pris l'habitude de n'entrer les destinations qu'à partir
+ de la carte, et non pas à partir de l'index des rues.
+
+* Par rapport aux solutions commerciales, capables d'afficher l'état du
+ trafic, Navit est vraiment en retard. On peut résumer en disant qu'il
+ s'agit davantage d'une carte interactive qu'une solution de guidage, il
+ reste nécessaire de prévoir son trajet avant de partir.
+
+* Un autre regret est de ne pas pouvoir sélectionner des « points de
+ passage », pour affiner le trajet. La seule solution est de choisir
+ préparer à l'avance dan les favoris les destinations et les faire évoluer
+ au fur du trajet.
+
+* Enfin, contrairement aux gps embarqués, on est dépendant de la qualité du
+ support : si l'on dispose d'un portable avec écran brillant, on sera
+ forcément gêné lors du suivi de la navigation.
+
+.. image:: |filename|../images/Capture-Navit-1-e1332786990864.png
+ :width: 400
+
+
+OpenstreetMap
+=============
+
+Impossible de parler de navit sans aborder openstreetmap ! Pour faire une
+analogie, openstreetmap est à la cartographie ce que wikipédia est à
+l'encyclopédie : une plateforme donnant à chacun le moyen la possibilité de
+contribuer.
+
+La navigation GPS est pour moi l'utilisation la plus pratique de ce service :
+d'une part parce que les cartes sont libres, et d'autre part parce que cela
+donne envie de contribuer à son tour : en rajoutant les feux aux carrefours,
+les parkings, en fonction des différents trajets que l'on réalise; on voit à
+l'utilisation les défaut sur les cartes, et une fois de retour chez soi, on
+corrige la carte en fonction.
+
+OpenstreetMap change très vite, et les cartes sont mises à jour en continu.
+C'est pourquoi je vous propose d'automatiser le téléchargement de vos cartes.
+Rien de mieux pour ça qu'une tâche dans un cron !
+
+Vous vous souvenez de l'url que je vous avais demander de noter dans un coin
+tout à l'heure ? C'est maintenant qu'elle va être réutilisée.
+
+.. code-block:: bash
+
+ $ crontab -e
+
+Dans l'éditeur de texte qui s'ouvre, on va entrer notre tâche planifiée :
+
+.. code-block:: bash
+
+ 25 3 * * 1 wget -O ~/sync/.navit/carte.bin ${url} > /dev/null 2>&1
+
+Ainsi, la carte se mettra à jour automatiquement !
+
+J'ai dit tout à l'heure qu'openstreetmap permettait à tout un chacun de
+modifier les cartes, cela signifie que, comme wikipédia, la qualité des cartes
+est inégale selon les endroits que vous visitez : il n'y a probablement pas de
+problème dans une grande ville, mais cela risque d'être plus compliqué pour
+retrouver le nom d'une rue dans un hameau ou un petit village. Dans ce cas,
+n'hésitez pas à mettre à jour la carte ! (Ça n'est pas l'objet de l'article
+ici, mais il existe de nombreux tutoriels pour vous expliquer comment faire.)
+
+Conclusion
+==========
+
+J'ai parlé du coût de la solution au début de l'article : il s'agit du coût du
+récepteur GPS. On peut en trouver par 30€ sur ebay, ce qui est investissement
+suffisant pour se lancer (si l'on compare aux gps tactiles qui sont vendus en
+supermarché).
+
+Pour ma part, j'utilise un récepteur ND100 de globalsat_.
+
+Au final on dispose donc d'une aide à la navigation qui s'avère très pratique,
+et assez amusante ! On a l'avantage de disposer de cartes gratuites et mises à
+jour en permanence (même si la qualité laisse parfois à désirer), mais aussi de
+ne pas dépendre d'un système fermé (il est possible de modifier les cartes à
+l'aide de l'éditeur d'OpenstreetMap quand on rencontre des erreurs).
+
+.. _`Navit planet extractor`: http://maps3.navit-project.org/
+.. _openstreetmap: http://www.openstreetmap.org/
+.. _globalsat: http://www.ebay.com/sch/?_nkw=globalsat%20nd%20100&clk_rvr_id=327330038890
diff --git a/content/Informatique/rst.rst b/content/Informatique/rst.rst
new file mode 100755
index 0000000..7555e60
--- /dev/null
+++ b/content/Informatique/rst.rst
@@ -0,0 +1,181 @@
+.. -*- mode: rst -*-
+.. -*- coding: utf-8 -*-
+
+Blogguer en rst sous wordpress
+##############################
+
+:date: 2010-10-04
+:tags: Libre
+
+
+Le format reStructuredText_ est un langage de balise (un peu comme le HTML, ou
+le laTex ), issu du monde de la programmation. Son but est de répondre au
+problème suivant : comment écrire du texte simplement et sans avoir besoin
+d'apprendre une syntaxe spécifique (ou du moins un minimum), tout en
+conservant des possibilité de formatage et d'export ?
+
+.. _reStructuredText : http://docutils.sourceforge.net/rst.html
+
+Présentation de RST
+===================
+
+Quand on écrit un article (par exemple ici cet article de blog), il est
+nécessaire d'indiquer des directives de mise en page : ceci est un paragraphe,
+ceci est un lien, inclure une image, une citation… Pour cela on ne passe pas
+par un logiciel de traitement de texte pour le faire (openOffice) : c'est lourd
+et cela n'apporte rien, mais la plupart du temps par un éditeur intégré au blog
+qui permet de formater notre texte.
+
+Cet éditeur se charge pour nous de formater le texte en quelques clics. Le
+problème est que bien souvent ce texte ne pourra pas sortir du blog (par
+exemple pour prendre un extrait de l'article et l'utiliser ailleurs, nous
+sommes obligés de passer à nouveau par cette interface)
+
+Une autre solution est de rédiger notre texte directement dans le format de
+sortie (par exemple HTML), mais cela nécessite de connaître la syntaxe, et ne
+rend pas la lecture du fichier source très lisible (essayez de lire un article
+de presse en HTML avec un éditeur de texte pour voir…)
+
+Le format reStructuredText se veut être une réponse à ces problèmes : un
+fichier RST est lisible (le fichier source est compréhensible et peut être lu
+directement), ne nécessite pas de connaissances particulières (du moins peu), et
+à l'avantage de pouvoir être exporté dans de nombreux format de sortie (odt,
+pdf, latex, html…) On dispose donc d'un format unique pouvant servir à écrire
+des articles de blog, des documents de travail, ou encore de la documentation.
+
+La syntaxe est très simple, et ne charge pas le document à la lecture. Par
+exemple pour voir le document ayant servi à générer cet article est disponible
+ici_ : on laisse des lignes blanches pour indiquer que l'on passe d'un
+paragraphe à un autre, ou « souligne » avec les caractères = _ ou - les titres
+et les sous-titres, et le résultat donne un document très aéré et agréable à
+travailler.
+
+.. _ici : http://chimrod.com/downloads/blog/article.rst
+
+Plugin wordpress
+================
+
+Il existe un plugin wordpress qui permet d'utiliser ce format pour l'écriture
+de documents dans le blog. À chaque fois que l'on va publier un article, le
+plugin va tester si le fichier est au format rst, et dans ce cas, va en faire
+la conversion en html en passant par la commande rst2html.
+
+**Attention**, pour le mettre en place, il est
+nécessaire d'avoir un accès à la machine pour y installer quelques
+applications.
+
+Pré-requis
+----------
+
+Python doit être disponible sur la machine, ainsi que le script rst2html (je
+ne pense pas que cela soit le cas pour les blogs hébergés et cela limite les
+possibilités).
+
+.. code-block:: console
+
+ $ sudo aptitude install python-docutils
+
+Installation
+------------
+
+Il s'agit juste d'un fichier à installer dans le répertoire des plugin de
+wordpress. Celui-ci est disponible sur launchpad_ et ne pose aucun problème de
+compatibilité.
+
+.. _launchpad : http://bazaar.launchpad.net/~gldnspud/rest-wordpress/trunk/files
+
+Le fichier README explique comment l'installer et le paramétrage à faire; les
+options (comme le chemin vers rst2pdf) se font directement dans le fichier php.
+
+.. code-block:: php startinline=True
+
+ // Set this to the prefix of your docutils installation.
+ $prefix = "/usr/local";
+
+ // Set this to the path of rst2html.py
+ $rst2html = "$prefix/bin/rst2html.py";
+
+Un petit test devrait montrer le résultat tout de suite. Dans le cas où le
+contenu est vide, regardez les logs d'erreur du serveur web, vous devriez y
+trouver les causes de votre erreur.
+
+Coloration syntaxique
+---------------------
+
+Il est possible de disposer de la coloration syntaxique automatique du code :
+
+.. code-block:: python
+
+ import os
+ # Standard hello world stuff
+ class Hello()
+ def do_it(self)
+ print "Hello world"
+
+ if __name__ == '__main__':
+ Hello().do_it()
+
+ def main()
+ print "Hello world"
+
+Pour intégrer la coloration syntaxique, il faut passer par pygment (un
+programme python qui s'occupe de ça) :
+
+.. code-block:: console
+
+ # aptitude install python-pygments
+
+Ensuite il va falloir modifier le script à lancer. En effet, par défaut, la
+commande rst2pdf n'intègre pas la coloration de code. Nous allons donc devoir
+modifier la commande à exécuter pour le faire (j'ai mis à disposition le script
+à télécharger_). Assurez vous que le script peut être exécuté par l'utilisateur
+lancé par le service web.
+
+.. _télécharger : http://chimrod.com/downloads/scripts/rst2html-pygments.py
+
+La CSS n'est pas inclue dans le document et peut être définie à l'extérieur. Il
+est possible de définir son style à partir de pygment avec la commande suivante
+(pour appliquer le style tango) :
+
+.. code-block:: console
+
+ $ pygmentize -S tango -f html > style.css
+
+Conclusion
+==========
+
+Je cherchais depuis un petit moment une solution pour pouvoir écrire mes
+articles sans me connecter au blog. Les applications clientes ne me convenant
+pas tout à fait, le RST me permet d'utiliser une application totalement séparée
+du blog (par exemple VIM) et un format pérenne.
+
+Je ne sais pas s'il existe une solution équivalente pour les autres moteurs de
+blog, le RST étant encore un format assez jeune, et n'est pas encore très
+répandu…
+
+Sans être aussi complet que le latex, il est bien plus souple et
+beaucoup plus facile à utiliser. De plus il s'agit bien sûr d'un format
+ouvert, pouvant générer des documents sous openOffice, en PDF, voire en latex
+pour ceux qui veulent…
+
+Édit (29/05/11)
+===============
+
+Je reviens sur le plugin en constatant que par défaut, celui-ci met en cache le
+contenu de l'article, même si celui-ci est déjà en html. Une petite
+modification dans le code permet de ne sauvegarder le fichier que s'il s'agit
+d'un fichier rst :
+
+Rechercher dans le script la chaîne suivante :
+
+.. code-block:: php
+
+ if ($pos === false) {
+ // No modeline.
+ $rval = wpautop($text);
+
+Et rajouter la ligne suivante en dessous :
+
+.. code-block:: php
+
+ return $rval;
diff --git a/content/Informatique/rstodt.rst b/content/Informatique/rstodt.rst
new file mode 100755
index 0000000..9011cb9
--- /dev/null
+++ b/content/Informatique/rstodt.rst
@@ -0,0 +1,59 @@
+.. -*- mode : rst -*-
+.. -*- coding: utf-8 -*-
+
+Coloration syntaxique avec rst2odt
+##################################
+
+:date: 2012-08-18
+:tags: Libre
+
+|logo|
+
+Le langage rst, déjà évoqué dans un `article précédent`_, possède plusieurs
+formats sortie : pdf, odt, html, xml… Cependant, les outils pour générer la
+sortie ne prennent pas tous les même paramètres, et il est difficile de faire
+un fichier source qui soit compatible avec l'ensemble des compilateurs.
+
+La coloration syntaxique
+========================
+
+La coloration syntaxique, par exemple, n'est pas traitée de la même manière
+selon l'outil utilisé. Nous retrouvons deux directives :
+
+=========== ===============================================
+Nom Outils
+=========== ===============================================
+code-block rst2pdf_, sphynx…
+sourcecode rst2odt
+=========== ===============================================
+
+La première est devenue un standard, la seconde n'est prise en compte que par
+rst2odt (et est en plus un peu lourde à mettre en place).
+
+La modification
+===============
+
+Heureusement, c'est assez facile d'ajouter de nouvelles directives, et il est
+possible de modifier le script à lancer pour prendre en compte la directive
+code-block !
+
+Vous pouvez télécharger le script modifié ici_. J'ai repris l'option
+d'`inclusion de fichier`, mais je ne gère pas les limites (je n'en avais pas
+besoin).
+
+Et voilà, ça s'utilise comme ça :
+
+.. code-block:: console
+
+ $ python bin/rst2odt.py --strip-comments --stylesheet=resources/template.odt\
+ --add-syntax-highlight source.rst source.odt
+
+(Source de l'image : Kea_)
+
+.. |logo| image:: http://farm4.staticflickr.com/3609/3325975129_a8e246dd20_s.jpg
+.. _article précédent: |filename|rst.rst
+.. _rst2pdf: http://rst2pdf.ralsina.com.ar/
+.. _ici: http://chimrod.com/downloads/rst2odt.py
+.. _inclusion de fichier: http://rst2pdf.ralsina.com.ar/handbook.html#file-inclusion
+.. _Kea: http://www.flickr.com/photos/k_e_a/3325975129/
+
diff --git a/content/Informatique/sftp.rst b/content/Informatique/sftp.rst
new file mode 100755
index 0000000..59edfe5
--- /dev/null
+++ b/content/Informatique/sftp.rst
@@ -0,0 +1,138 @@
+.. -*- mode: rst -*-
+.. -*- coding: utf-8 -*-
+
+Mettre en place un environnement sftp chrooté (2)
+#################################################
+
+:date: 2011-06-07
+:tags: Hébergement
+
+Il y a quelques temps, j'avais publié un billet indiquant comment mettre en
+place un environnement sftp chrooté, dans lequel l'utilisateur ne peut pas
+sortir du répertoire qui lui est assigné.
+
+La solution que j'avais proposé ( modifier la configuration de sshd ) était
+compliquée et lourde a mettre en place. Parmi les commentaires, le logiciel
+mysecureshell_ avait été évoqué.
+
+Présentation
+============
+
+Mysecureshell est une commande qui se lance au login de l'utilisateur sur la
+machine. Il dispose de nombreuses possibilité de paramétrage (débit, droits),
+tout en restant très simple à administrer. De plus, il empêche l'utilisateur
+d'ouvrir une connexion sur la machine, il ne peut que se connecter en sftp.
+
+Nous allons voir ici comment le
+mettre en place sur une machine Debian destinée à accueillir des
+connexions sftp.
+
+La documentation en ligne est complète et accessible voici néanmoins une
+description qui reprend les principes de l'installation.
+
+Installation
+============
+
+Mysecureshell n'est malheureusement pas disponible dans les dépôts debian. Il
+est donc nécessaire d'ajouter un dépôt externe pour l'installer. Le site web
+fournit des `paquets d'installation`_ pour la plupart des distributions (debian,
+fedora…)
+
+Une fois que le dépôt est ajouté, il suffit de l'installer en lançant la
+commande suivante (toujours sous debian) :
+
+.. code-block:: console
+
+ # aptitude install mysecureshell
+
+
+Configuration
+=============
+
+Configuration de mysecureshell
+------------------------------
+
+La configuration se fait dans le fichier /etc/ssh/sftp-config
+
+Voici les champs importants à noter :
+
+=============== ==============================================================
+Champs Signification
+=============== ==============================================================
+GlobalDownload Il s'agit du débit maximal qui sera utilisé quand le serveur
+ uploadera des fichiers vers les clients
+GlobalUpload La même chose pour l'upload
+StayAtHome Empêcher l'utilisateur de naviguer hors de son répertoire
+ personnel
+VirtualChroot Met en place un faux home pour l'utilisateur
+Home Défini le home que verra l'utilisateur lorsqu'il se connectera
+=============== ==============================================================
+
+Je conseille de séparer le home « unix » de l'utilisateur de son home
+« chrooté ». Cela permet de mettre en place des fichiers dans le fichier home
+de l'utilisateur, sans que celui-ci ne puisse les consulter :
+
+Cela se fait tout simplement en mettant l'option VirtualChroot à True, et en
+définissant le Home `mysecureshell` vers un sous-répertoire du home `unix` :
+
+
+.. code-block:: bash
+
+ StayAtHome true
+ VirtualChroot true
+ Home /home/$USER/sftp
+
+
+Cela oblige à créer pour chaque utilisateur un répertoire sftp dans son home.
+Lorsque l'utilisateur se connectera, il accedera uniquement à répertoire sftp,
+mais ne pourra pas naviguer plus haut, ni consulter les autres répertoire des
+autres utilisateurs.
+
+
+Gestion des comptes
+-------------------
+
+La configuration est assez simple : pour chaque utilisateur nous allons indiquer
+que mysecureshell est la commande à exécuter lors du login de l'utilisateur.
+Cela se fait en modifiant le fichier /etc/passwd.
+
+.. code-block:: console
+
+ invite:x:1002:1002:,,,:/home/invite:/bin/bash
+
+et le remplacer le dernier champs ainsi :
+
+
+.. code-block:: console
+
+ invite:x:1002:1002:,,,:/home/invite:/bin/Mysecureshell
+
+Sauvegarder, et voilà, la configuration va s'appliquer lors de la prochaine
+connexion de l'utilisateur.
+
+Mise à jour de la configuration
+-------------------------------
+
+Lorsque les fichiers de configuration sont mis à jour, les connexions existantes
+ne sont affectées. Elles ne le deviennent qu'à partir de la prochaine
+reconnexion de l'utilisateur.
+
+Il est tout à fait possibile de forcer mysecureshell à appliquer les
+modifications, mais cela oblige à `reconnecter les utilisateurs`_
+
+Au final
+========
+
+Il n'y a pas grand chose à faire finalement, et c'est agréable de voir la
+configuration se faire aussi rapidement ! Il est vrai que le site web de
+l'application peut sembler amateur, mais cela ne reflète en rien la qualité de
+l'application.
+
+J'abandonne donc avec plaisir la méthode que j'avais mis en place dans mon
+précédent billet pour passer sur mysecureshell !
+
+.. _mysecureshell : http://mysecureshell.sourceforge.net/fr/index.html
+.. _paquets d'installation : http://mysecureshell.sourceforge.net/fr/installpak.html
+.. _reconnecter les utilisateurs : http://mysecureshell.sourceforge.net/fr/confman.html#question9
+
+.. vim: filetype=rst
diff --git a/content/Informatique/vala.rst b/content/Informatique/vala.rst
new file mode 100755
index 0000000..7ca8e8e
--- /dev/null
+++ b/content/Informatique/vala.rst
@@ -0,0 +1,153 @@
+.. -*- mode: rst -*-
+.. -*- coding: utf-8 -*-
+
+Présentation de Vala
+####################
+
+:date: 2010-06-11
+:tags: Libre, Programmation
+
+J'ai découvert une présentation du langage dans GLMF n°127 qui
+l'utilisait pour se brancher sur le pare-feu. Cela ayant aiguisé ma
+curiosité, j'ai cherché à en savoir davantage sur le langage. Le langage
+C m'a toujours paru difficile à aborder. Non pas au niveau de sa
+syntaxe, mais au sujet de l'accès à sa documentation et aux librairies
+disponibles. Pour moi qui suis habitué à Java ou à Python, j'ai regardé
+Vala comme un moyen de mettre un pied dans le C. Je vais essayé de
+présenter ma manière de le voir, après avoir fait une petite plongée
+dedans…
+
+Présentation
+~~~~~~~~~~~~
+
+Le langage Vala à été créé par les développeurs de Gnome pour qu'ils
+puissent disposer d'un langage de haut niveau. Gnome ayant eu pendant
+quelques temps un pied ( dansant ) dans mono, Vala en est très inspiré.
+( Je ne connais pas mono et ne peux donc pas lancer de comparatif, je
+vous renvoie donc à celui présenté par Gnome `par rapport à
+C# <http://live.gnome.org/Vala/QuickIntroForCSharpProgrammers>`_, et
+pour `Java <http://live.gnome.org/Vala/ValaForJavaProgrammers>`_ ). Le
+langage est ensuite compilé en C, et GCC est utilisé pour la compilation
+d'un exécutable. On est donc dans un langage intermédiaire, qui reste
+très proche du C comme nous allons le voir par la suite.
+
+Analyse
+~~~~~~~
+
+Langage objet haut niveau Vala est tout d'abord un langage haut niveau :
+on y retrouve des *interface* ( pour pouvoir moduler le code facilement
+), des *delegate* ( qui permettent de de définir un type de fonction
+pour un callback ), une gestion *événementielle* ( gérer le
+déclenchement de plusieurs méthodes dans le code par un appel unique ) …
+On dispose donc d'un langage objet assez riche pour éviter d'avoir
+passer du temps sur des détails et se concentrer sur le programme et son
+déroulement. Il est pensé objet et l'on retrouve vite ses marques, tout
+comme l'on sent qu'il est assez facile d'« abstraire » le code pour
+faire une application qui n'en reste pas un simple script… Je n'ai pas
+envie de détailler la syntaxe du langage et tout ce qu'il intègre car
+vous pourrez trouver tout cela en ligne. Je vous renvoie au
+`tutoriel <http://live.gnome.org/Vala/Tutorial>`_ qui explique la
+structure du langage en détail, qui présentent des exemples détaillés.
+La GLib Le langage est basé sur la GLib, la librairie standard utilisé
+dans les applications GTK. La plupart des types primitifs ( int… ) sont
+donc en réalités des types issus de cette librairie ( gint…). On accède
+ainsi à l'ensemble des méthodes de la GLib, diffusées sous formes de
+classes objets et bien documentées ( la
+`valadoc <http://valadoc.org/index.html>`_ ). Cela rejoint l'histoire de
+Vala puisque La GLib est tout utilisée par les développeurs Gnome ( on
+constate d'ailleurs que la plupart des composants Gnome ont une entrée
+dans cette Valadoc ). Il ne faut cependant pas croire que l'on dispose
+avec cette bibliothèque standard d'un ensemble de routines aussi riche
+que dans le package standard d'un Java ou d'un Python : la GLib est
+avant tout destinée à des développeurs C, et beaucoup des méthodes
+standard du C n'y sont pas disponibles. Pour parer cela, Vala propose
+une classe POSIX[LIEN] proposant les méthodes standard du C, mais
+celle-ci n'est pas exhaustive et il nous arrive souvent de tomber sur
+une fonction qui ne nous est pas accessible via le langage haut niveau
+qu'est Vala. Les Bindings Pour répondre à cela, propose la possibilité
+de mettre en place un binding vers une libraire C de manière native. (
+Normal me direz vous, le code en sortie de Vala est du C ! ) On peut
+donc très facilement utiliser n'importe quelle libraire existante. Vala
+étant un langage objet, il devient donc possible d'utiliser les
+librairies standard au sein d'un code objet de haut niveau. Cela ne
+demande que quelques lignes, demandant au minimum le fichier dans lequel
+se trouve la définition de la méthode, et sa signature. Exemple du
+binding définissant la méthode execl ( issue du fichier
+/usr/share/vala/vapi/posix.vapi ) :
+
+::
+
+ [CCode (cheader_filename = "unistd.h")]
+ public int execl (string path, params string[] arg);
+
+et voici la signature de la méthode C correspondante :
+
+::
+
+ extern int execl (__const char *__path, __const char *__arg, ...) __THROW __nonnull ((1));
+
+Les types primitifs de la GLib étant basés sur les types primitifs C
+correspondant, il n'y a pas de problème de cast dans la plupart de cas.
+Toutefois, Vala utilise des char\* pour définir ses string : il est
+parfois nécessaire de mettre en place faire un cast quand une méthode
+nous un char[] : même dans le code haut niveau, le C n'est jamais loin…
+C'est souvent frustrant de devoir mettre en place un binding pour une
+fonction disponible en standard dans la libc. Je pense qu'il manque la
+possibilité d'inclure directement du code C dans le code vala, tout
+comme il est possible directement de l'assembleur dans du C. Cela
+permettrait un confort dans l'utilisation qui n'est pas disponible
+actuellement. À noter qu'un outil permet de mettre en place ces bindings
+pour les composants basés sur GObjet ( Gnome toujours… ). De plus de
+nombreux bindings sont disponibles pour les composants Gnome. Attention,
+cela n'empêchera pas d'avoir à installer les headers C correspondants !
+Les profils Il est possible d'utiliser des profils de compilation. Cette
+option encore expérimentale a été mise en place pour répondre à des
+réclamations de la part des utilisateurs qui voulaient programmer en
+Vala sans avoir de dépendances envers la GLib. Ainsi, il est possible
+d'appeler le compilateur avec la syntaxe suivante :
+
+::
+
+ valac --profile posix
+
+ce qui a pour conséquence de réduire le jeu de bibliothèque par défaut à
+celles disponibles dans la classe POSIX. Cela permet de limiter les
+dépendances du programmes, mais beaucoup de types standard de Vala
+deviennent de ce fait indisponible; on sent bien que le langage n'a pas
+été pensé pour ça.
+
+Conclusion
+~~~~~~~~~~
+
+Pour résumer, je dirais que Vala correspond à ce qu'il annonce : un
+langage haut niveau pour faciliter la création d'applications Gnome. Dès
+que l'on cherche à sortir de ce cadre, on se retrouve confronté à des
+limitations ( qui ne sont bien sûr pas insurmontable ) :
+
+- Pour ceux qui ne cherche pas à travailler sur du code Gnome,
+ embarquement de bibliothèques qui ne nous intéressent pas forcement.
+ ( Bien que sur ce point, la GLib est plutôt standard sur les PCs
+ ayant X d'installés )
+- Pour ceux qui cherchent un langage de haut niveau, le C est encore
+ trop présent entre les lignes pour pouvoir l'oublier complètement.
+ D'un autre côté, l'intégration du code C n'est pas toujours évidente
+ puisqu'elle oblige à déclarer des bindings pour des fonctions
+ standards.
+- Mais surtout, le fait que l'ensemble des fonctions de la libc ne
+ soient pas encore disponibles oblige à mettre le doigt dans les
+ bindings régulièrement.
+
+Le langage est bien sûr encore amené à évoluer, et les points que je
+cite ici ne sont pas pour autant rédhibitoires. D'un point de vue
+totalement subjectif Je trouve le langage simple mais sans trop de
+saveur. Ça reste un langage objet qui n'est bien sûr pas
+révolutionnaire; on sent qu'il ne fait que reprendre les concepts des
+langages qui l'ont inspiré, mais le produit est cohérent, et d'après les
+benchs génère un code plutôt optimisé ( en rapport avec le temps que
+l'on pourrait passer à produire le même code en C ). Après, je ne prend
+pas le même plaisir à programmer en Vala qu'en python ( j'avais bien dit
+que j'étais subjectif ^^ ). Cela dit, pour moi, qui ne suis pas un
+développeur Gnome, je suis plus intéressé par la possibilité d'avoir un
+langage haut niveau qui reste très proche du C, avec les performances
+qui vont avec; si le prix pour cela est une dépendance vers la GLib, ça
+reste un coût sommes toutes assez faible.
diff --git a/content/Informatique/wiimote.rst b/content/Informatique/wiimote.rst
new file mode 100755
index 0000000..21db1de
--- /dev/null
+++ b/content/Informatique/wiimote.rst
@@ -0,0 +1,121 @@
+.. -*- mode: rst -*-
+.. -*- coding: utf-8 -*-
+
+Controling the wiimote (I)
+##########################
+
+
+:date: 2009-03-11
+:tags: Programmation, Wiimote
+
+
+Creating the plugin for wminput
+-------------------------------
+
+There are a lot of tutorials about how to configure cwiid. I let you follow
+them for getting a functionnal system for your wiimote. You can read the links
+at the end of this article. Be sure your system works well before continuing.
+
+This is a code that we'll use as template for the creation of our driver. Used
+as main, it use pygame for displaying the infrared sources the wiimote can
+detect, but it is also compatible as plugin for wminput ( even if it does
+anything for now ).
+
+You can get it here :
+`wm\_control.py <http://www.chimrod.com/downloads/wiimote/ir_control_0.py>`_
+( This code is licenced under GPL 3+ )
+
+About the code :
+
+::
+
+ import wmplugin
+
+This import does not exist, but is created by wminput when executed. It provide
+the connexion with the wminput core. Just put ( or link ) the script in the
+wminput plugin path ( on my debian this is the /usr/lib/cwiid/plugins/ )
+
+::
+
+ def wmplugin_init(id, wiimote_arg):
+ wmplugin.set_rpt_mode(id, cwiid.RPT_IR | cwiid.RPT_BTN)
+ return
+
+ def wmplugin_info():
+ return [],
+ [("X", wmplugin.REL | wmplugin.ABS, 1024, 0, 0, 0),
+ ("Y", wmplugin.REL | wmplugin.ABS, 768, 0, 0, 0)],
+ []
+
+We instanciate the wiimote object here and configure it in the IR mode. The
+name is choosen by wminput if we want to use it as plugin. We define that the
+plugin return the coordonates X and Y in a relative system (
+you can get the signification of all the parameters here : `actions list
+<http://abstrakraft.org/cwiid/browser/trunk/wminput/action_enum.txt>`_)
+
+If we want to define new butons, we just have to name them in the first list,
+the'll be accessible in the configuration file as plugin.[buton\_name] = ACTION
+
+::
+
+ def wmplugin_exec(messages):
+ '''Wiimote callback managing method
+ Recieves a message list, each element is different, see the libcwiid docs'''
+ x = y = 0
+
+ for msg in messages:
+ if msg[0] == cwiid.MESG_IR:
+ x, y = ir_sensor.get_movement(msg)
+ return [], (x, y)
+
+Here is the core of our driver. The name is choosen by wminput too, as the
+format value we return. We have in parameter the list of the messages the
+wiimote has sent.
+
+If we have defined buton we need to return their state here. It is a boolean
+saying if the buton is pressed ( True ) or not ( False ).
+
+This method doesn't send any others parameters, and this is a problem when we
+need to store data between two calls ( ie for saving the cursor position ). One
+way for passing throught is to use global variables. But it is unelegant and
+can cause problems if we want to use our code in imports. So we'ill use a list
+as default parameter and let python save it as you can see here :
+
+::
+
+ >>> def meth(a=[]):
+ ... a.append(1)
+ ... print a
+ ...
+ >>> meth()
+ [1]
+ >>> meth()
+ [1, 1]
+ >>> meth()
+ [1, 1, 1]
+
+So the ir\_sensor.get\_movement method is defined with each parameter we
+want to save as an optional list
+
+::
+
+ def get_movement(msg, _old_points=[], _old_position = [0, 0]):
+ return 0, 0
+
+The get\_movement method need to return the difference between the old position
+of the cursor and the new one in tuple : (0, 0) mean that the cursor didn't
+move, (-10, 0) mean a deplacement to the left.
+
+For now, the plugin doesn't move the cursor, and doesn't read what the wiimote
+has sent. But you know everything for creating your own plugin for controlling
+your wiimote. You can use all the cwiid method for setting the led, activating
+the differents modes of your wiimote ( IR, Acc, rumble ... ), and define here
+your own actions.
+
+I'll explain the core of the movement analysis in IR mode in the next article.
+
+Links :
+ `The cwiid project <http://abstrakraft.org/cwiid/>`_
+
+`Install Cwiid ( Ubuntu Documentation
+) <https://help.ubuntu.com/community/CWiiD>`_
diff --git a/content/Informatique/wiimote1.rst b/content/Informatique/wiimote1.rst
new file mode 100755
index 0000000..94577d4
--- /dev/null
+++ b/content/Informatique/wiimote1.rst
@@ -0,0 +1,60 @@
+.. -*- mode: rst -*-
+.. -*- coding: utf-8 -*-
+
+Un pilote wiimote sous Linux en python
+--------------------------------------
+
+:date: 2009/02/19
+:tags: Programmation, Wiimote
+
+La wiimote est la manette de contrôle de la console wii de Nintendo, un
+outil merveilleux dont voici un petit résumé de ses fonctionnalités :
+
+- Accéléromètres
+- Caméra infrarouge
+- Émetteur/Récepteur Bluetooth
+- 11 boutons
+
+( voir le détail sur la page de
+`wikipédia <http://fr.wikipedia.org/wiki/Wiimote>`_ )
+
+En disposant d'un récepteur bluetooth, il est possible de se connecter à
+la télécommande et de récupérer ses informations, mieux, avec le projet
+`cwiid <http://abstrakraft.org/cwiid/>`_, on peut transformer la wiimote
+en souris !
+
+Ainsi selon le mode dans lequel se trouve la télécommande, on contrôle
+notre curseur en inclinant la télécommande, ou en la pointant vers une
+source infrarouge
+
+..
+
+ La source infrarouge pouvant être la sensor bar fournie avec la
+ console, ou une source externe, bougie lampe ou tout ce dont pouvez
+ disposer diffusant de la chaleur à partir d'un point unique
+
+Le pilote fourni avec cwiid fonctionne mais n'est pas optimisé. Il
+arrive que la souris parte dans une direction incontrôlée, ou de ne pas
+pouvoir accéder à certaines parties de l'écran.
+
+La faute est due au pilote intégré qui se contente juste de placer le
+pointeur sur la source infrarouge, avec quelques petites optimisations.
+
+En effet, le capteur de la wiimote nous indique quelle est la position
+de toutes les sources infrarouges perçues ( et nous fourni également des
+informations sur leur intensité ), mais la conversion en pointeur est
+laissée au pilote :
+
+- Quelle source choisir comme référence ?
+- Comment gérer les cas où une source est sortie du champ de vision ?
+- Comment réagir quand cette source revient dans le champ de vision ?
+
+Tout ceci doit être pris en compte pour pouvoir offrir une ergonomie au
+curseur et faciliter le contrôle.
+
+Heureusement pour nous le pilote nous donne la possibilité de réécrire
+nos propres moteurs, et donc de gérer nous même la manière dont on veut
+que la souris réagisse. Nous avons même le choix dans le langage ! En
+effet, nous pouvons choisir entre offrir un plugin compilé ( le pilote
+est écrit en C ), ou l'écrire en python. C'est cette deuxième option que
+je vais présenter dans les articles qui suivront.
diff --git a/content/Perso/inculture.rst b/content/Perso/inculture.rst
new file mode 100755
index 0000000..5a91592
--- /dev/null
+++ b/content/Perso/inculture.rst
@@ -0,0 +1,103 @@
+.. -*- mode: rst -*-
+.. -*- coding: utf-8 -*-
+
+Hadopi veut sauver l'inculture
+##############################
+
+:date: 2011-06-09
+
+Culture populaire contre culture financière
+-------------------------------------------
+
+On oppose souvent la culture populaire à la culture légitime. La culture
+populaire représente la culture de rue, alors que la culture légitime est une
+culture institutionnalisée, celle que l'on retrouve dans les musées et les
+écoles.
+
+La culture populaire, elle, fait peur. Ce n'est pas un fait nouveau elle a
+toujours fait peur : c'est celle que l'on ne contrôle pas, celle qui pointe du
+doigt les travers de la société, dans les bars hier, dans les cages d'escalier
+aujourd'hui, et sur internet demain.
+
+Hadopi ne cherche pas à opposer ces deux visions. La question n'est pas
+d'interdire les rassemblements sur internet comme on interdit les raves
+sauvages dans les champs en friche. La question est de contrôler la
+commercialisation de la culture; d'empêcher non pas qu'elle sorte du cadre
+institutionnalisé, mais du cadre financier. Il ne s'agit pas de protéger les
+auteurs en tant que créateurs d'art, il s'agit de protéger les auteurs en tant
+que producteurs de richesses.
+
+Les débats qui parlent actuellement de la culture ne sont plus des débats sur
+le contenu de ce qui fait la culture, mais des débats qui parlent de la culture
+en terme de revenus. Hadopi n'a pas pour vocation de protéger le hip-hop, la
+peinture, le slam, le théâtre.
+
+On parle de piratage des œuvres culturelles, mais arrêtons nous un instant :
+
+En quoi le fait de diffuser une œuvre (musicale, cinématographique…) nuit-elle
+à la culture ? Peut on contrefaire (puisqu'il s'agit bien du délit
+reproché aux pirates) de la culture ? Ça n'est pas la culture que l'on cherche
+à protéger, mais sa valeur marchande !
+
+Le regain d'intérêt contre hadopi, à l'heure où celui-ci devient un outil de
+marchandising (qui dépense 3 millions d'euros en campagne publicitaire) nous
+montre bien que l'on ne veut pas de ce modèle que l'on nous propose, et la
+solution est déjà dans le message : pour ne pas voir la culture devenir
+uniquement un bien commercial, il suffit de refuser hadopi !!
+
+Le réveil d'une autre forme de culture
+--------------------------------------
+
+Mais cette opposition nous fait oublier que la culture n'est pas uniquement
+artistique : bien que déconstruction pour faire de la culture de l'inculture_
+soit en chantier depuis longtemps maintenant, il ne faut pas oublier que la
+culture est avant tout politique !
+
+Les `parodies des spots publicitaires`_ sont autant des messages politiques
+qu'artistique, tout comme l'étaient ceux du `logo hadopi`_. Mais la
+contestation qui est soulevée est avant tout une question de vivre ensemble :
+internet a ce pouvoir de laisser les individus s'exprimer hors du cadre qui est
+imposé, légitimement ou non. Et le comportement des internautes vis-à-vis du
+téléchargement oblige à se questionner : ce mouvement populaire peut-il être
+contrôlé par la répression ?
+
+Parmi les solution proposée pour faire vivre les artistes, on retrouve la
+licence globale. Là encore arrêtons nous un instant :
+
+ * il s'agit d'une solution collective (l'ensemble de la population
+ participe aux frais, comme pour l'entretien des musées nationaux)
+ * il ne s'agit pas d'une solution marchande (la licence globale entraine
+ une prolifération des œuvres, et non pas une centralisation comme c'est
+ le cas aujourd'hui)
+
+Hors, ce sont justement ces deux points qui sont contestés par les partisans
+d'hadopi : la culture ne doit pas être partagée, elle doit rester entre les
+mains de ceux qui en vivent, pas de ceux qui la vivent !
+
+Sauvons l'inculture_, votons hadopi
+-----------------------------------
+
+Hadopi, en voulant protéger la Culture (celle avec un grand Cul), a réveillé
+les rancœurs et la colère des internautes. Pourquoi ? Tout simplement parce
+que cette culture que l'on nous présente à travers ce que l'on cherche à
+protéger n'a plus grand chose à voir avec la culture 'vécue', celle que l'on
+prend plaisir à découvrir et partager.
+
+Si j'écris aujourd'hui, c'est parce que je ne prend conscience que maintenant
+que le terme de culture a été dévoyée. Il n'y a pas de culture dans les MP3 ou
+les AVI qui s'échangent sur le P2P. Il n'y a que du loisir. L'industrie
+culturelle que l'on nous présente dans les médias n'existe pas (plus); elle a
+été supplantée par l'industrie du divertissement, qui s'exporte très bien, mais
+qui n'a plus rien à voir avec une volonté de diffusion de la culture. Au
+contraire ! Et je ne souhaite pas que cet élan culturel soit également dévoyé
+ici, sur internet.
+
+Et pour protéger cette culture, il faut de l'échange, il faut des opinions, des
+idées. Que l'on soit d'accord ou non, le débat doit être ouvert : il faut
+ramener du politique dans la culture.
+
+Merci de m'avoir lu.
+
+.. _parodies des spots publicitaires : http://www.journaldugeek.com/2011/06/09/les-internautes-detournent-la-campagne-de-pub-hadopi/
+.. _logo hadopi : http://fr.readwriteweb.com/2010/01/09/nouveautes/concours-remix-logo-hadopi/
+.. _inculture : http://tvbruits.org/spip.php?article981
diff --git a/content/Perso/infrarouge.rst b/content/Perso/infrarouge.rst
new file mode 100755
index 0000000..988cbc2
--- /dev/null
+++ b/content/Perso/infrarouge.rst
@@ -0,0 +1,19 @@
+.. -*- mode: rst -*-
+.. -*- coding: utf-8 -*-
+
+Photo infrarouge
+################
+
+:date: 2011-08-29
+
+Je me suis récemment essayé à la photo infrarouge; en mettant un filtre qui ne laisse
+passer que les rayons infrarouges devant l'objectif, il est possible de saisir des images
+que l'on ne verrait pas à l'œil nu.
+
+Ce n'est plus les couleurs qui sont saisies, mais la température : généralement l'eau et
+le ciel seront sombre, alors que les feuilles et l'herbe seront très clairs.
+
+Alors que les beaux jours reviennent, voici la photo d'un jardin d'enfants à midi :
+
+.. image:: |filename|../images/2011avril23_120334.jpg
+ :width: 650
diff --git a/content/Perso/net.rst b/content/Perso/net.rst
new file mode 100755
index 0000000..dbe952d
--- /dev/null
+++ b/content/Perso/net.rst
@@ -0,0 +1,51 @@
+.. -*- mode: rst -*-
+.. -*- coding: utf-8 -*-
+
+Le net en france
+----------------
+
+:date: 2009-02-25
+
+|HADOPI - Le Net en France : black-out|
+
+La quadrature du net lance un appel à la mobilisation contre le projet
+de loi Hadopi qui vise à réguler le "piratage" sur le net. non seulement
+en mettant en place la riposte graduée ( qui conduit à couper l'accès à
+internet ), mais en autorisant l'enregistrement et l'analyse des
+différentes communications qui transitent sur le réseau. A la base
+instaurée pour répondre à la demande des artistes pour lutter contre le
+piratage, cette loi va plus loin et permet des dérives qui font peur : à
+l'heure ou nos communication par téléphone, ou notre courrier ou nos
+sources d'informations passent par internet, il est important de
+protéger notre espace et de le défendre.
+
+Malheureusement, j'ai l'impression que personne ne chercher à protéger
+sa liberté sur le net. Les campagnes d'information sur les données
+personnelles n'empêchent pas les individus de continuer à s'inscrire
+massivement sur facebook ou d'utiliser msn pour communiquer, par
+commodité et par pratique, mais en oubliant que derrière tout ces
+services, il y a un prix à payer : celui de notre anonymat et de notre
+liberté.
+
+A l'heure il il devient anormal de chercher à protéger sa vie privée
+même "si l'on n'a rien à se reprocher", je pense qu'il faut rappeler à
+tous, que cet espace qui peut sembler si loin, si distant de notre vie,
+est en fait incrusté dans nos domicilies, nos consoles de jeux ou nos
+téléphones, et mettre en place des mesures de contrôles sur le net
+permettent de réduire très facilement les libertés de l'individu
+
+Facilement car :
+
+- Ce contrôle se fait en silence : il est fait de manière automatique
+ sans que l'individu ne s'en rende compte. La dérive étant que l'on ne
+ sait plus très bien quelle est la limite entre ce qui est contrôlé et
+ ce qui ne l'est pas.
+- Ce contrôle est global : avec la puissance des machines, il devient
+ possible de surveiller l'ensemble des connexions des internautes, et
+ de voir tout ce qui transite sur les réseaux.
+- Ce contrôle est permanent : pour les même raisons.
+
+Avant qu'il ne soit interdit d'utiliser un logiciel non conforme,
+essayons de préserver notre liberté et d'affirmer ce que nous défendons.
+
+.. |HADOPI - Le Net en France : black-out| image:: http://media.laquadrature.net/Quadrature_black-out_HADOPI_468x60px.gif
diff --git a/content/ecafe.rst b/content/ecafe.rst
new file mode 100755
index 0000000..b6d8668
--- /dev/null
+++ b/content/ecafe.rst
@@ -0,0 +1,119 @@
+.. -*- rst -*-
+.. -*- coding: utf-8 -*-
+
+Commentaires pratiques sur Hercules eCafé EX HD
+===============================================
+
+J'ai reçu ce week-end mon hercules ecafé hd. Ce netbook, présenté il y a
+quelques temps dans une dépêche, présente la caractéristique d'avoir une
+architecture arm et une distribution basée sur ubuntu.
+
+Ce portable est destiné à remplacer mon vieillissant eeepc701 dont la batterie
+est en train de mourir (ainsi que le boutons du touchpad, certaines touches du
+clavier etc)
+
+Premières impressions
+---------------------
+
+Premier regard, première déception : écran brillant. Ça commence bien ! En fait
+tout le PC est brillant, chouette ça va être sympa quand la coque sera pleine
+de tâche de doigts et de rayures. Je m'en doutais un peu au vu des photos sur
+le net, mais c'est toujours dommage quand on l'a entre ses mains. Tant pis, je
+vais devoir faire avec.
+
+Deuxième regard : impossible de retirer la batterie. Tout est caché sous une
+coque en plastique léger qui donne une impression cheap. En fait, il me faut
+prendre quelque temps pour bien le regarder et m'assurer que c'est bien
+ordinateur et non pas un jouet pour enfant que je tiens entre mes mains ! (En le
+regardant à nouveau au moment où j'écris cet article, ce sentiment m'est passé,
+mais il est vrai que ça m'a surpris au début, je pense que le poids très léger
+y est aussi pour quelque chose.)
+
+Démarrage de l'ordinateur, on retrouve la petite roue blanche en train de
+tourner nous confirmant que nous sommes sous un linux, avec les icônes
+provenant d'ubuntu. Après quelques questions posées dans des boites GTK pour
+créer le compte utilisateur, on se retrouve sur notre écran de login.
+
+Derrière cet écran, le bureau, qui intègre les applications et le menu. Ce menu
+est construit sur celui de gnome, et est éditable facilement. Je le trouve
+personnellement plutôt pratique est assez esthétique (il aurait davantage pu
+être contrôlable au clavier, mais c'est mon côté « awesome » qui parle).
+
+.. capture ecran
+
+Tentative de connexion wifi, à travers network manager, ça fonctionne sans
+aucun problème.
+
+En fait en découvrant tout ça je me sens prendre un coup de vieux : j'ai
+l'impression de sortir de ma ligne de commande et arriver dans un environnement
+graphique agréable à utiliser. Tout a été configuré sans que je cherche comment
+faire, dès le démarrage; linux n'est plus ce qu'il était..
+
+À l'usage
+=========
+
+On se rend vite compte que l'ordinateur n'est pas un foudre de guerre. Il est
+un peu plus véloce que mon 701, mais guère plus. D'un autre côté, je ne compte
+pas lui demander grand chose : un client mpd, vim, terminal, unison, du ssh et
+un peu de surf, ça reste fluide et réactif. (Je n'ai pas testé la lecture de
+vidéo, vu que ça ne fera pas parti de mes usages).
+
+L'autonomie est vraiment impressionnante, je ne me rend pas bien compte de ce
+que représente plus de 10h d'usage. J'espère juste que la batterie ne va pas
+vieillir trop vite (même si je commence avec une bonne marge !)
+
+.. capture autonomie
+
+Mon utilisation va rester simple (client mpd, client ssh, un peu de surf, pas
+de compilation), le pc ne va pas être trop chargé.
+
+Il y a pas mal d'applications installées, même si toutes ne sont pas visibles
+dans le menu (w3m et byobu sont installés par défaut, evolution aussi mais
+c'est une autre histoire).
+
+Par contre, les applications sont plutôt vieillissantes, c'est génant quand on
+a pris l'habitude d'utiliser firefox sync (et oui, on est en version 3.6!),
+même si ça ne touche que quelques fonctionnalités dans l'ensemble du système.
+
+Ouvrons le système
+==================
+
+Rajoutons le dépots ubuntu lucid, et lançons une mise à jour. Ça fonctionne
+sans problème. Par contre j'ai réussi à casser le système en passant sur
+maverick : la faute aux paquets installés de base qui n'intègrent pas
+correctement les dépendances (xorg notamment), résultat, dès qu'une mise à jour
+change l'api, ça ne passe plus. Bon, une fois qu'on a compris le truc, on peut
+s'en sortir.
+
+(Au passage j'ai ainsi pu tester la restauration du système, qui se fait très
+simplement avec une carte sd.)
+
+Le problème avec lucid, c'est que c'est quand même assez vieux : la version
+d'unison proposée ne peux pas dialoguer avec mon serveur, rxvt-unicode n'est
+pas disponible en 256 couleurs (j'ai pris deux exemples pas trop au hasard vu
+que j'ai utilisés deux solutions différentes pour contourner le problème)
+
+Si le paquet n'est pas trop récent on peut s'en sortir en l'installant depuis
+les dépôts de Maverick, il n'y a pas trop de différences entre les jeux de
+librairies et on ne casse pas grand chose.
+
+Pour les paquets plus récents, il faut mieux le backporter depuis oneiric
+(rappel express : on rajoute les dépôts source de la distribution que l'on
+souhaite rétroporter, et on le compile avec les librairies de la distribution
+courante) : ça prend du temps mais ça marche.
+
+Je suis en train de regarder comment me faire un environnement de compilation
+ARM sur ma tour.
+
+Au final
+========
+
+Le prix de l'ordinateur étant en train de baisser, il devient très intéressant.
+Je le réserve toutefois soit à une personne pas trop exigeante, qui se
+satisfera des applications installées par défaut, soit capable de se compiler
+ses paquets pour adapter le système. Entre les deux, on sera forcément deçu
+(voir le journal précédent à ce sujet). Je pense que sur ce site, il peut
+trouver preneur, mais il faut reconnaitre que les informations officielles ne
+sont pas très précises sur ce que l'on achète : derrière le slogan de
+simplicité se cache en un système assez exigeant qui reste assez limité à
+l'usage.
diff --git a/content/ecafe2.rst b/content/ecafe2.rst
new file mode 100755
index 0000000..29bb907
--- /dev/null
+++ b/content/ecafe2.rst
@@ -0,0 +1,58 @@
+.. -*- rst -*-
+.. -*- coding: utf-8 -*-
+
+Je ne m'attendais pas à ce que le journal soit transformé en dépêche, je
+remercie l'admin qui en a pris l'initiative, et je me rend compte en même temps
+que ce qui pouvait être assez long pour un journal (je voulais éviter le tl;dr)
+devient un peu court pour une dépêche !
+
+En même temps je ne voulais pas me contenter d'une description « commerciale »,
+et je avais envie d'avancer sur le terrain technique pour de présenter un peu
+ce qu'un linuxien est en mesure d'attendre avec le portable : comment faire les
+mises à jour; conséquences d'une architecture arm etc (voir les commentaires du
+journal).
+
+Au niveau de l'arm, le plus visible dans une utilisation quotidienne est
+l'absence de flash. Cela m'a paru tellement anecdotique que je n'ai pas pris la
+peine de le mentionner dans mon article - je suis davantage un habitué d'elinks
+que des sites flash.
+
+Je n'ai pas testé la lecture de vidéo sur le portable (j'ai une tour pour ça),
+ni testé de pousser la carte graphique dans ses retranchements.
+
+On sent qu'une attention a été poussée au niveau des applications : par exemple
+le client mail intégré au bureau propose une configuration automatique pour les
+mails gmails, yahoo.
+
+D'ailleurs, les applications : comme elles sont gratuites, hercules n'a pas
+lésiné : openoffice, tuxpaint, dcraw (?), firefox, chromium, w3m, rythmnbox,
+totem, empathy. Comme si l'on allait se servir de ce portable pour faire du
+traitement de texte ! Ah j'oubliais tomboy et fspot sont de la partie (merci
+gnome !)
+
+Et c'est bien là le paradoxe de cet ordinateur : le public ciblé n'est pas
+celui qui s'intéressera à l'ordinateur. On se retrouve vite limité si l'on
+n'est pas capable d'ourir un terminal.
+
+Sinon, le démarrage de l'ordinateur :
+
+ * 45 secondes : L'écran de login apparaît.
+ * 1 minute 15 : Le bureau s'affiche avec les icônes des lanceurs
+ * 2 secondes plus tard vim est lancé.
+
+Quand on rabat l'écran, le portable se met en veille (il s'agit en fait des
+options d'alimentation et d'énergie de gnome), l'appui sur le bouton
+d'alimentation provoque l'affichage d'une boite de dialogue proposant
+d'éteindre, redémarrer ou mettre en veille.
+
+La mise en veille justement : la sortie de veille se fait très rapidement (4
+secondes montre en main), le wifi se reconnecte automatiquement.
+
+Sinon, parmi les surprises, il y a un port pour carte SIM qui n'était pas
+mentionné. Si quelqu'un sait ce qu'on peut faire avec ? Également, vu que la
+batterie est intégrée, il y a un petit interrupteur pour proposer de passer
+l'alimentation uniquement sur le secteur.
+
+Voila, je rajouterai que le portable est proposé avec un service d'hébergement
+« dans le cloud », dont la première dose est gratuite. Je n'ai pas testé, vu
+que je dispose déjà de tout ça (auto-hébergement).
diff --git a/content/images/2011avril23_120334.jpg b/content/images/2011avril23_120334.jpg
new file mode 100755
index 0000000..9f68e07
--- /dev/null
+++ b/content/images/2011avril23_120334.jpg
Binary files differ
diff --git a/content/images/Capture-Navit-1-e1332786990864.png b/content/images/Capture-Navit-1-e1332786990864.png
new file mode 100755
index 0000000..5ce1f2a
--- /dev/null
+++ b/content/images/Capture-Navit-1-e1332786990864.png
Binary files differ
diff --git a/content/images/Capture-Navit-e1332787251467.png b/content/images/Capture-Navit-e1332787251467.png
new file mode 100755
index 0000000..3ab8c70
--- /dev/null
+++ b/content/images/Capture-Navit-e1332787251467.png
Binary files differ
diff --git a/content/images/conf-300x175.jpg b/content/images/conf-300x175.jpg
new file mode 100755
index 0000000..8673916
--- /dev/null
+++ b/content/images/conf-300x175.jpg
Binary files differ
diff --git a/content/images/filezilla-300x140.jpg b/content/images/filezilla-300x140.jpg
new file mode 100755
index 0000000..481a7b7
--- /dev/null
+++ b/content/images/filezilla-300x140.jpg
Binary files differ
diff --git a/content/images/menu.png b/content/images/menu.png
new file mode 100755
index 0000000..304f73c
--- /dev/null
+++ b/content/images/menu.png
Binary files differ
diff --git a/content/images/puttygen-300x276.jpg b/content/images/puttygen-300x276.jpg
new file mode 100755
index 0000000..c0fa4c2
--- /dev/null
+++ b/content/images/puttygen-300x276.jpg
Binary files differ
diff --git a/content/publish.sh b/content/publish.sh
new file mode 100755
index 0000000..da29cef
--- /dev/null
+++ b/content/publish.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+#mkvirtualenv pelican
+source ~/.virtualenvs/pelican/bin/activate
+cd ~/pelican/
+make html
+rsync -ra --del output/ /home/www/blog-chimrod/
diff --git a/pelicanconf.py b/pelicanconf.py
new file mode 100755
index 0000000..abbf488
--- /dev/null
+++ b/pelicanconf.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*- #
+
+AUTHOR = u'Chimrod'
+SITENAME = u'Chimrod'
+SITEURL = 'http://blog.chimrod.com/'
+
+TIMEZONE = 'Europe/Paris'
+
+DEFAULT_LANG = u'fr'
+
+#ARTICLE_DIR = 'articles'
+
+# Blogroll
+#LINKS = (('Pelican', 'http://docs.notmyidea.org/alexis/pelican/'),
+# ('Python.org', 'http://python.org'),
+# ('Jinja2', 'http://jinja.pocoo.org'),
+# ('You can modify those links in your config file', '#'),)
+
+# Social widget
+#SOCIAL = (('You can add links in your config file', '#'),
+# ('Another social link', '#'),)
+
+DEFAULT_PAGINATION = 4
+FEED_DOMAIN = SITEURL
+FEED_RSS = 'feed'
+FEED_ATOM = 'feeds/atom.xml'
+FEED_MAX_ITEMS=5
+TAG_FEED_RSS = 'feeds/%s.xml'
+TAG_FEED_ATOM = 'feeds/%s.atom'
+
+ARTICLE_URL = u'{date:%Y}/{date:%m}/{slug}/'
+ARTICLE_SAVE_AS = u'{date:%Y}/{date:%m}/{slug}/index.html'
+
+DISQUS_SITENAME='chimrod'
+
+THEME = 'theme'
+TYPOGRIFY = True
+
+from pelican.plugins import related_posts
+PLUGINS = [related_posts]
diff --git a/publishconf.py b/publishconf.py
new file mode 100644
index 0000000..e48e0d6
--- /dev/null
+++ b/publishconf.py
@@ -0,0 +1,18 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*- #
+
+import sys
+sys.path.append('.')
+from pelicanconf import *
+
+SITEURL = 'http://blog.chimrod.com'
+
+DELETE_OUTPUT_DIRECTORY = True
+
+# Following items are often useful when publishing
+
+# Uncomment following line for absolute URLs in production:
+#RELATIVE_URLS = False
+
+#DISQUS_SITENAME = ""
+#GOOGLE_ANALYTICS = ""
diff --git a/theme/LISEZ-MOI.rst b/theme/LISEZ-MOI.rst
new file mode 100755
index 0000000..56a60ef
--- /dev/null
+++ b/theme/LISEZ-MOI.rst
@@ -0,0 +1,16 @@
+Thème «Lightweight» pour pelican
+################################
+
+Description
+===========
+
+:Créé le: 14 février 2011
+:Technologies utilisées: xHTML5, CSS 1-3, polices TTF
+:Couleurs utilisées: Tons froids (gris/bleu)
+:Design extensif: Oui
+:Testé sous: Mozilla Firefox 4.0b10, Chromium 9.0.597.83, ELinks 0.12pre5
+:Langue: Français
+:Détails: Voire capture d'écran et source
+
+
+
diff --git a/theme/screenshot.png b/theme/screenshot.png
new file mode 100755
index 0000000..559e684
--- /dev/null
+++ b/theme/screenshot.png
Binary files differ
diff --git a/theme/static/css/main.css b/theme/static/css/main.css
new file mode 100755
index 0000000..63a1cc2
--- /dev/null
+++ b/theme/static/css/main.css
@@ -0,0 +1,280 @@
+@import url("pygment.css");
+@import url("styles.css");
+
+@font-face {
+ font-style: normal;
+ font-weight: normal;
+}
+
+header, footer, section, nav {
+ display: block;
+}
+
+body {
+ width: 710px;
+ margin: 0;
+ padding: 0;
+ font-size: .8em;
+ line-height: 1.3;
+ color: #111;
+ background : #323232;
+ margin-left: auto;
+ margin-right: auto;
+ font-family: "Lucida sans unicode",Lucida,Tahoma,Arial,sans-serif;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ margin: 1em 0 .5em 0;
+ line-height: 1.2;
+ font-style: normal;
+ font-weight: normal;
+ color: #AE4E00;
+}
+h1 {
+ font-size: 1.5em;
+}
+h2 {
+ font-size: 1.3em;
+}
+h2.page_title {
+ padding-left: 10px;
+ text-decoration: none;
+ font-size: 1.3em;
+ color: #AE4E00;
+ text-transform : capitalize;
+}
+h3 {
+ font-size: 1.15em;
+ margin-left: 5px;
+}
+h4 {
+ font-size: 1em;
+ margin-left: 30px;
+}
+
+ul, ol {
+ margin: .75em 0 .75em 32px;
+ padding: 0;
+}
+
+p {
+ margin: .75em;
+}
+
+pre, blockquote {
+ margin: 0.5em 1em;
+ border:1px solid #ccc;
+ background:#eee;
+ border-left: 3px solid #ae4e00;
+ overflow:auto;
+ color: #666666;
+ line-height: 1.22em;
+ padding-left: 10px;
+}
+
+pre {
+ font-size: medium;
+}
+
+table {
+ border: 1px dashed grey;
+ padding: 0;
+ margin: 15px 10px;
+}
+ td, th {
+ margin: 0;
+ padding: 2px 5px;
+ border: 1px dotted grey;
+ }
+
+hr {
+ height: 0;
+ width: 60%;
+ margin: 15px auto;
+ color: transparent;
+ border-bottom: 2px dotted grey;
+}
+
+address {
+ margin: .75em 0;
+ font-style: normal;
+}
+
+a {
+ text-decoration: underline;
+}
+a:link {
+ color: inherit;
+}
+a:visited {
+ color: inherit;
+}
+a:hover, a:focus, a:active {
+ color: slategrey;
+}
+
+a img {
+ border: none;
+}
+
+em {
+ font-style: italic;
+}
+strong {
+ font-weight: bold;
+}
+
+
+
+div#page {
+ background : url(../images/fond.jpg) repeat-y top center #323232;
+ margin: 5% auto 5% auto;
+}
+
+
+ header#header {
+ background-image: url("../images/header.jpg");
+ height: 333px;
+ }
+
+ #header>h1 {
+ left: 20px;
+ color: #BBBBBB;
+ letter-spacing: 1px;
+ font-size: 1.3em;
+ padding : 0;
+ padding-top: 20px;
+ padding-left: 15px;
+ margin: 15px 0 15px 0;
+ }
+ #header>h1>a {
+ text-decoration: inherit;
+ color: inherit;
+ }
+
+ nav#cssmenu {
+ width: 100%;
+ padding-top: 2px;
+ padding-bottom: 2px;
+ }
+
+ nav#menu a {
+ display: inline-block;
+ text-decoration: none;
+ margin: 2px;
+ padding: 1px;
+ border: 1px solid grey;
+ border-radius: 3px;
+ font-weight: bold;
+ color: #222;
+ }
+
+ nav#menu a:hover, nav#menu a.active {
+ border: 1px solid black;
+ color: black;
+ }
+
+ section#content {
+ float: left;
+ width: 700px;
+ line-height: 170%;
+ text-align: justify;
+ }
+ section#content a img {
+ max-width: 98%;
+ max-height: 98%;
+ margin-left: 15px;
+ }
+
+ section#content img {
+ max-width: 98%;
+ max-height: 98%;
+ }
+
+ section#content table#archives {
+ border: 0px ;
+ }
+
+ table#archives td, table#archives td {
+ border: 0px ;
+ }
+
+ section#content {
+ margin: 10px;
+ }
+ article.post h2.post_title {
+ margin: 20px 0 0 0;
+ padding: 0;
+ }
+
+ article.post time.meta {
+ color: #999999;
+ font-size: small;
+ }
+
+ article.post details.meta {
+ margin: 5px 0 0 0;
+ padding: 0;
+ }
+ article.post details.meta p {
+ margin: 0;
+ padding: 0;
+ }
+
+ .post details.meta {
+ margin: 0;
+ padding: 2px 3px;
+ font-size: .8em;
+ }
+
+ #content a#all_tags {
+ font-size: 1.8em;
+ }
+ #content ul#tag_list {
+ list-style-type: none;
+ }
+ #content dl#archives dt {
+ margin-left: 40px;
+ }
+ #content dl#archives dd {
+ text-align: center;
+ }
+
+ #content>nav.pagination {
+ width: 100%;
+ font-size: 14px;
+ text-align: center;
+ }
+ nav.pagination a {
+ text-decoration: none;
+ font-weight: bolder;
+ }
+
+// aside#sidebar {
+// float: right;
+// width: 24%;
+// }
+// #sidebar .widget {
+// margin-bottom: 10px;
+// }
+// #sidebar .widget ul {
+// list-style-type: none;
+// margin: auto auto auto 15px;
+// }
+// #sidebar .widget ul li:before {
+// content: '» ';
+// }
+//
+// #sidebar .widget ul a.more {
+// display: inline-block;
+// padding-top: 5px;
+// text-decoration: none;
+// }
+
+
+ footer#footer {
+ clear:both;
+ border-top: 1px solid grey;
+ padding: 5px 20px;
+ }
+
diff --git a/theme/static/css/pygment.css b/theme/static/css/pygment.css
new file mode 100755
index 0000000..594b0fa
--- /dev/null
+++ b/theme/static/css/pygment.css
@@ -0,0 +1,205 @@
+.hll {
+background-color:#FFFFCC;
+}
+.c {
+color:#408090;
+font-style:italic;
+}
+.err {
+border:1px solid #FF0000;
+}
+.k {
+color:#007020;
+font-weight:bold;
+}
+.o {
+color:#666666;
+}
+.cm {
+color:#408090;
+font-style:italic;
+}
+.cp {
+color:#007020;
+}
+.c1 {
+color:#408090;
+font-style:italic;
+}
+.cs {
+background-color:#FFF0F0;
+color:#408090;
+}
+.gd {
+color:#A00000;
+}
+.ge {
+font-style:italic;
+}
+.gr {
+color:#FF0000;
+}
+.gh {
+color:#000080;
+font-weight:bold;
+}
+.gi {
+color:#00A000;
+}
+.go {
+color:#303030;
+}
+.gp {
+color:#C65D09;
+font-weight:bold;
+}
+.gs {
+font-weight:bold;
+}
+.gu {
+color:#800080;
+font-weight:bold;
+}
+.gt {
+color:#0040D0;
+}
+.kc {
+color:#007020;
+font-weight:bold;
+}
+.kd {
+color:#007020;
+font-weight:bold;
+}
+.kn {
+color:#007020;
+font-weight:bold;
+}
+.kp {
+color:#007020;
+}
+.kr {
+color:#007020;
+font-weight:bold;
+}
+.kt {
+color:#902000;
+}
+.m {
+color:#208050;
+}
+.s {
+color:#4070A0;
+}
+.na {
+color:#4070A0;
+}
+.nb {
+color:#007020;
+}
+.nc {
+color:#0E84B5;
+font-weight:bold;
+}
+.no {
+color:#60ADD5;
+}
+.nd {
+color:#555555;
+font-weight:bold;
+}
+.ni {
+color:#D55537;
+font-weight:bold;
+}
+.ne {
+color:#007020;
+}
+.nf {
+color:#06287E;
+}
+.nl {
+color:#002070;
+font-weight:bold;
+}
+.nn {
+color:#0E84B5;
+font-weight:bold;
+}
+.nt {
+color:#062873;
+font-weight:bold;
+}
+.nv {
+color:#BB60D5;
+}
+.ow {
+color:#007020;
+font-weight:bold;
+}
+.w {
+color:#BBBBBB;
+}
+.mf {
+color:#208050;
+}
+.mh {
+color:#208050;
+}
+.mi {
+color:#208050;
+}
+.mo {
+color:#208050;
+}
+.sb {
+color:#4070A0;
+}
+.sc {
+color:#4070A0;
+}
+.sd {
+color:#4070A0;
+font-style:italic;
+}
+.s2 {
+color:#4070A0;
+}
+.se {
+color:#4070A0;
+font-weight:bold;
+}
+.sh {
+color:#4070A0;
+}
+.si {
+color:#70A0D0;
+font-style:italic;
+}
+.sx {
+color:#C65D09;
+}
+.sr {
+color:#235388;
+}
+.s1 {
+color:#4070A0;
+}
+.ss {
+color:#517918;
+}
+.bp {
+color:#007020;
+}
+.vc {
+color:#BB60D5;
+}
+.vg {
+color:#BB60D5;
+}
+.vi {
+color:#BB60D5;
+}
+.il {
+color:#208050;
+}
diff --git a/theme/static/css/styles.css b/theme/static/css/styles.css
new file mode 100755
index 0000000..ec426de
--- /dev/null
+++ b/theme/static/css/styles.css
@@ -0,0 +1,25 @@
+#cssmenu ul, #cssmenu hr { margin: 0px; }
+#cssmenu hr { margin: auto; }
+#cssmenu{ height:39px; display:block; padding:0; margin: 0; margin-left:10px; margin-right:10px; }
+#cssmenu > ul {list-style:inside none; padding:0; margin:0;}
+#cssmenu > ul > li {list-style:inside none; padding:0; margin:0; float:left; display:block; position:relative;}
+#cssmenu > ul > li > a{ outline:none; display:block; position:relative; padding:12px 20px; font: 13px/100% Arial, Helvetica, sans-serif; text-align:center; text-decoration:none; text-shadow:1px 1px 0 rgba(0,0,0, 0.4); }
+#cssmenu > ul > li:first-child > a{border-radius:5px 0 0 5px;}
+#cssmenu > ul > li > a:after{ content:''; position:absolute; border-right:1px solid; top:-1px; bottom:-1px; right:-2px; z-index:99; }
+#cssmenu ul li.has-sub:hover > a:after{top:0; bottom:0;}
+#cssmenu > ul > li.has-sub > a:before{ content:''; position:absolute; top:18px; right:6px; border:5px solid transparent; border-top:5px solid #fff; }
+#cssmenu > ul > li.has-sub:hover > a:before{top:19px;}
+#cssmenu ul li.has-sub:hover > a{ background:#3f3f3f; border-color:#3f3f3f; padding-bottom:13px; padding-top:13px; top:-1px; z-index:999; }
+#cssmenu ul li.has-sub:hover > ul, #cssmenu ul li.has-sub:hover > div{display:block;}
+#cssmenu ul li.has-sub > a:hover{background:#3f3f3f; border-color:#3f3f3f;}
+#cssmenu ul li > ul, #cssmenu ul li > div{ display:none; width:auto; position:absolute; top:38px; padding:10px 0; background:#3f3f3f; border-radius:0 0 5px 5px; z-index:999; }
+#cssmenu ul li > ul{width:200px;}
+#cssmenu ul li > ul li{display:block; list-style:inside none; padding:0; margin:0; position:relative;}
+#cssmenu ul li > ul li a{ outline:none; display:block; position:relative; margin:0; padding:8px 20px; font:10pt Arial, Helvetica, sans-serif; color:#fff; text-decoration:none; text-shadow:1px 1px 0 rgba(0,0,0, 0.5); }
+
+
+#cssmenu, #cssmenu > ul > li > ul > li a:hover{ background-color:#323232; }
+#cssmenu{border-color:#000;}
+#cssmenu > ul > li > a{border-right:1px solid #000; color:#fff;}
+#cssmenu > ul > li > a:after{border-color:#444;}
+#cssmenu > ul > li > a:hover{background:#111;}
diff --git a/theme/static/images/atom.jpg b/theme/static/images/atom.jpg
new file mode 100755
index 0000000..89dd169
--- /dev/null
+++ b/theme/static/images/atom.jpg
Binary files differ
diff --git a/theme/static/images/atom.png b/theme/static/images/atom.png
new file mode 100755
index 0000000..15611d1
--- /dev/null
+++ b/theme/static/images/atom.png
Binary files differ
diff --git a/theme/static/images/fond.jpg b/theme/static/images/fond.jpg
new file mode 100755
index 0000000..ae3d2a1
--- /dev/null
+++ b/theme/static/images/fond.jpg
Binary files differ
diff --git a/theme/static/images/header.jpg b/theme/static/images/header.jpg
new file mode 100755
index 0000000..8b07029
--- /dev/null
+++ b/theme/static/images/header.jpg
Binary files differ
diff --git a/theme/static/images/rss.jpg b/theme/static/images/rss.jpg
new file mode 100755
index 0000000..f91d8ec
--- /dev/null
+++ b/theme/static/images/rss.jpg
Binary files differ
diff --git a/theme/static/images/rss.png b/theme/static/images/rss.png
new file mode 100755
index 0000000..1ac38dd
--- /dev/null
+++ b/theme/static/images/rss.png
Binary files differ
diff --git a/theme/templates/archives.html b/theme/templates/archives.html
new file mode 100755
index 0000000..f3c2990
--- /dev/null
+++ b/theme/templates/archives.html
@@ -0,0 +1,17 @@
+{% extends "base.html" %}
+
+{%block title %}{{ SITENAME }} - Archives{%endblock%}
+
+{% block content %}
+ <h2 class="page_title">Archives</h2>
+ <table id="archives">
+ <tbody>
+ {% for article in dates %}
+ <tr>
+ <td>{{ article.date.date() }}</td>
+ <td><a href='{{ article.url }}'>{{ article.title }}</a></td>
+ </tr>
+ {% endfor %}
+ </tbody>
+ </table>
+{% endblock %}
diff --git a/theme/templates/article.html b/theme/templates/article.html
new file mode 100755
index 0000000..f66fe72
--- /dev/null
+++ b/theme/templates/article.html
@@ -0,0 +1,40 @@
+{% extends "base.html" %}
+
+{% block title %}{{ SITENAME }} - {{ article.title }}{% endblock %}
+
+{% block content %}
+ <article class="post">
+ <h2 class="page_title"><a href="{{ article.url }}" rel="bookmark" title="{{SITENAME}} - {{ article.title }}">{{ article.title }}</a></h2>
+ {%include 'meta.html'%}
+
+ <section class="post_content">
+ {{ article.content }}
+ </section>
+
+ </article>
+
+ {% if DISQUS_SITENAME %}
+ <div class="comments">
+ <h2>Commentaires&nbsp;:</h2>
+ <div id="disqus_thread"></div>
+ <script type="text/javascript">
+ var disqus_identifier = "{{ article.url }}";
+ (function() {
+ var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
+ dsq.src = 'http://{{ DISQUS_SITENAME }}.disqus.com/embed.js';
+ (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
+ })();
+ </script>
+ </div>
+ {% endif %}
+
+{#
+ {% if article.related_posts %}
+ <ul>
+ {% for related_post in article.related_posts %}
+ <li>{{ related_post.url }}</li>
+ {% endfor %}
+ </ul>
+ {% endif %}
+#}
+{% endblock %}
diff --git a/theme/templates/author.html b/theme/templates/author.html
new file mode 100755
index 0000000..0b37290
--- /dev/null
+++ b/theme/templates/author.html
@@ -0,0 +1,2 @@
+{% extends "index.html" %}
+{% block title %}{{ SITENAME }} - {{ author }}{% endblock %}
diff --git a/theme/templates/authors.html b/theme/templates/authors.html
new file mode 100755
index 0000000..e69de29
--- /dev/null
+++ b/theme/templates/authors.html
diff --git a/theme/templates/base.html b/theme/templates/base.html
new file mode 100755
index 0000000..93ae32c
--- /dev/null
+++ b/theme/templates/base.html
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html>
+<html lang="{{ DEFAULT_LANG }}" xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>{% block title %}{{ SITENAME }}{%endblock%}</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <link rel="stylesheet" href="{{ SITEURL }}/theme/css/{{ CSS_FILE }}" type="text/css" />
+ <link href="{{ SITEURL }}/feeds/all.atom.xml" type="application/atom+xml" rel="alternate" title="{{ SITENAME }} - Flux ATOM" />
+ {% if tag %}
+ {% if TAG_FEED_ATOM %}
+ <link href="{{ SITEURL }}/{{ TAG_FEED_ATOM % tag|e }}" type="application/atom+xml" rel="alternate" title="{{ SITENAME }} » {{ tag|e }} - Flux ATOM" />
+ {% endif %}
+ {% if TAG_FEED_RSS %}
+ <link href="{{ SITEURL }}/{{ TAG_FEED_RSS % tag|e }}" type="application/rss+xml" rel="alternate" title="{{ SITENAME }} » {{ tag }} - Flux RSS" />
+ {% endif %}
+ {% endif %}
+
+ {% if category %}
+ {% if CATEGORY_FEED_ATOM %}
+ <link href="{{ SITEURL }}/{{ CATEGORY_FEED_ATOM % category }}" type="application/atom+xml" rel="alternate" title="{{ SITENAME }} » {{ category|e }} - Flux ATOM" />
+ {% endif %}
+ {% if CATEGORY_FEED_RSS %}
+ <link href="{{ SITEURL }}/{{ CATEGORY_FEED_RSS % category }}" type="application/rss+xml" rel="alternate" title="{{ SITENAME }} » {{ category|e }} - Flux RSS" />
+ {% endif %}
+ {% endif %}
+
+ {% if GOOGLE_ANALYTICS %}
+ <script type="text/javascript">
+ var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
+ document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
+ </script>
+ <script type="text/javascript">
+ try {
+ var pageTracker = _gat._getTracker("{{GOOGLE_ANALYTICS}}");
+ pageTracker._trackPageview();
+ } catch(err) {}</script>
+ {% endif %}
+</head>
+<body>
+<div id="page">
+
+{% include 'header.html' %}
+{% include 'menu.html' %}
+
+ <section id="content">
+{% block content %}
+{% endblock %}
+ </section> <!-- /#content -->
+
+ <footer id="footer">
+ <p>Propulsé par <a href="http://getpelican.com/">Pelican</a>.</p>
+ </footer>
+</div> <!-- /#page -->
+</body>
+</html>
diff --git a/theme/templates/categories.html b/theme/templates/categories.html
new file mode 100755
index 0000000..0cd25d4
--- /dev/null
+++ b/theme/templates/categories.html
@@ -0,0 +1,17 @@
+{% extends "base.html" %}
+
+{% block title %}{{ SITENAME }} - Catégories{% endblock %}
+
+{% block content %}
+<h2 class="page_title">Liste des catégories</h2>
+<ul>
+{% for category, articles in categories %}
+ <li>
+ <a href="{{ category.url }}">{{ category }}</a> ({{ articles|count }})
+ {% if CATEGORY_FEED_RSS %}
+ <a href="{{ SITEURL }}/{{ CATEGORY_FEED_RSS % category }}" ><img src="theme/images/rss.png" /></a>
+ {% endif %}
+ </li>
+{% endfor %}
+</ul>
+{% endblock %}
diff --git a/theme/templates/category.html b/theme/templates/category.html
new file mode 100755
index 0000000..f476d93
--- /dev/null
+++ b/theme/templates/category.html
@@ -0,0 +1,31 @@
+{% extends "base.html" %}
+{% block title %}{{ SITENAME }} - {{ category}}{% endblock %}
+
+{% block content %}
+ <h2 class="page_title">Articles dans la catégorie «{{ category }}»</h2>
+ {% if articles %}
+ {% for article in (articles_page.object_list if articles_page else articles) %}
+ <article class="post">
+ <h2 class="title"><a href="{{ SITEURL }}/{{ article.url}}">{{ article.title }}</a></h2>
+ <time class="meta" datetime="{{ article.date.isoformat() }}" pubdate="pubdate">{{ article.locale_date }}</time>
+
+ <section class="post_content">
+ {{ article.summary }}
+ {% if not loop.last %}
+ <hr>
+ {% endif %}
+ </section>
+ </article>
+ {% endfor %}
+ {% endif %}
+ {% include 'navigator.html' %}
+
+ {% if CATEGORY_FEED_RSS %}
+ <a href="{{ FEED_DOMAIN }}/{{ CATEGORY_FEED_RSS % category|e}}" ><img src="../theme/images/rss.png" /></a>
+ {% endif %}
+
+ {% if CATEGORY_FEED_ATOM %}
+ <a href="{{ FEED_DOMAIN }}/{{ CATEGORY_FEED_ATOM % category|e}}" ><img src="../theme/images/atom.png" /></a>
+ {% endif %}
+
+{% endblock %}
diff --git a/theme/templates/header.html b/theme/templates/header.html
new file mode 100755
index 0000000..066d71a
--- /dev/null
+++ b/theme/templates/header.html
@@ -0,0 +1,3 @@
+<header id="header">
+ <h1><a href="{{ SITEURL }}/index.html">{{ SITENAME }}</a></h1>
+</header>
diff --git a/theme/templates/index.html b/theme/templates/index.html
new file mode 100755
index 0000000..245c708
--- /dev/null
+++ b/theme/templates/index.html
@@ -0,0 +1,31 @@
+{% extends "base.html" %}
+{% block title %}{{ SITENAME }} - Accueil{% endblock %}
+
+{% block content %}
+ {% if articles %}
+ {% for article in (articles_page.object_list if articles_page else articles) %}
+ <article class="post">
+ <h2 class="title"><a href="{{ SITEURL }}/{{ article.url}}">{{ article.title }}</a></h2>
+<time class="meta" datetime="{{ article.date.isoformat() }}" pubdate="pubdate">{{ article.locale_date }}</time>
+
+ <section class="post_content">
+ {{ article.summary }}
+ {% if not loop.last %}
+ <hr>
+ {% endif %}
+ </section>
+ </article>
+ {% endfor %}
+
+ {% include 'navigator.html' %}
+
+ {% if FEED_RSS %}
+ <a href="{{ FEED_DOMAIN }}/{{ FEED_RSS }}" ><img src="../theme/images/rss.png" /></a>
+ {% endif %}
+
+ {% if FEED_ATOM %}
+ <a href="{{ FEED_DOMAIN }}/{{ FEED_ATOM }}" ><img src="../theme/images/atom.png" /></a>
+ {% endif %}
+
+ {% endif %}
+{% endblock %}
diff --git a/theme/templates/menu.html b/theme/templates/menu.html
new file mode 100755
index 0000000..b8ecd50
--- /dev/null
+++ b/theme/templates/menu.html
@@ -0,0 +1,53 @@
+{% macro submenu(elements, link, name) -%}
+ {% if elements %}
+ <li class='has-sub'><a href="{{ SITEURL }}/{{link}}.html"><span>{{name}}</span></a>
+ <ul>
+ {% for tag, articles in elements %}
+ <li><a href="{{SITEURL}}/{{tag.url}}"><span>{{ tag }}</span></a></li>
+ {% endfor %}
+ </ul>
+ </li>
+ {% endif %}
+{%- endmacro %}
+
+<div id="cssmenu">
+<ul>
+ <li class='has-sub'><a href="{{ SITEURL }}/">Articles</a>
+ <ul>
+ {% for article in articles %}
+ {% if loop.index < FEED_MAX_ITEMS %}
+ <li><a href="{{ SITEURL }}/{{ article.url}}">{{ article.title }}</a></li>
+ {% endif %}
+ {% endfor %}
+ <hr/>
+ <li><a href="{{ SITEURL }}/archives.html">Archives</a>
+ </ul>
+ </li>
+
+ {{ submenu(categories, 'categories', 'Catégories') }}
+ {{ submenu(tags, 'tags', 'Mots-clefs') }}
+
+
+{#
+ {% if FEED or FEED_RSS %}
+ <li class='has-sub'><a href="{{ SITEURL }}/#">S'abonner</a>
+ <ul>
+ {% if FEED %}
+ <li><a href="{{ SITEURL }}/{{ FEED }}" rel="alternate">Flux ATOM</a></li>
+ {% endif %}
+ {% if FEED_RSS %}
+ <li><a href="{{ SITEURL }}/{{ FEED_RSS }}" rel="alternate">Flux RSS</a></li>
+ {% endif %}
+
+ {% if categories %}
+ {% for category, articles in categories %}
+ <li><a href="{{SITEURL}}/{{CATEGORY_FEED_ATOM % (category)}}"><span>{{ category }}</span></a></li>
+ {% endfor %}
+ {% endif %}
+ </ul>
+ </li>
+ {% endif %}
+#}
+
+</ul>
+</div>
diff --git a/theme/templates/meta.html b/theme/templates/meta.html
new file mode 100755
index 0000000..db36173
--- /dev/null
+++ b/theme/templates/meta.html
@@ -0,0 +1,5 @@
+ <details class="meta">
+ Publié le <time datetime="{{ article.date.isoformat() }}" pubdate="pubdate">{{ article.locale_date }}</time>
+ {% if article.author %} par {{ article.author }}{% endif %} dans «<a href="{{ SITEURL }}/{{ article.category.url }}">{{ article.category }}</a>».
+ {% if article.tags %}Mots-clés: {% for tag in article.tags %}{%if loop.index > 1%}, {%endif%}<a href="{{ SITEURL }}/{{ tag.url }}">{{ tag }}</a>{% endfor %}</p>{% endif %}
+ </details>
diff --git a/theme/templates/navigator.html b/theme/templates/navigator.html
new file mode 100755
index 0000000..50ca559
--- /dev/null
+++ b/theme/templates/navigator.html
@@ -0,0 +1,15 @@
+{% if articles_page %}
+ <nav class="pagination">
+ {% if articles_page.has_previous() %}
+ {% if articles_page.previous_page_number() == 1 %}
+ <a href="{{ SITEURL }}/{{ page_name }}.html">&#60;&#60;</a>
+ {% else %}
+ <a href="{{ SITEURL }}/{{ page_name }}{{ articles_page.previous_page_number() }}.html">&#60;&#60;</a>
+ {% endif %}
+ {% endif %}
+ Page <b>{{ articles_page.number }}</b> sur <b>{{ articles_paginator.num_pages }}</b>
+ {% if articles_page.has_next() %}
+ <a href="{{ SITEURL }}/{{ page_name }}{{ articles_page.next_page_number() }}.html">&#62;&#62;</a>
+ {% endif %}
+ </nav>
+{% endif%}
diff --git a/theme/templates/page.html b/theme/templates/page.html
new file mode 100755
index 0000000..4a2a9b7
--- /dev/null
+++ b/theme/templates/page.html
@@ -0,0 +1,12 @@
+{% extends "base.html" %}
+{% block title %}{{ page.title }}{% endblock %}
+{% block content %}
+ <h1 class="page_title"><a href="{{ SITEURL }}/{{ page.url }}">{{ page.title }}</a></h1>
+ {% if PDF_PROCESSOR %}<a href="{{ SITEURL }}/pdf/{{ page.slug }}.pdf">get
+ the pdf</a>{% endif %}
+ <div style="clear: both;">&nbsp;</div>
+ <section class="page_content">
+ {{ page.content }}
+ </section>
+
+{% endblock %}
diff --git a/theme/templates/tag.html b/theme/templates/tag.html
new file mode 100755
index 0000000..49ed222
--- /dev/null
+++ b/theme/templates/tag.html
@@ -0,0 +1,31 @@
+{% extends "base.html" %}
+{% block title %}{{ SITENAME }} - «{{ tag }}»{% endblock %}
+
+{% block content %}
+ <h2 class="page_title">Articles avec le mot-clé «{{ tag }}»</h2>
+ {% if articles %}
+ {% for article in (articles_page.object_list if articles_page else articles) %}
+ <article class="post">
+ <h2 class="title"><a href="{{ SITEURL }}/{{ article.url}}">{{ article.title }}</a></h2>
+<time class="meta" datetime="{{ article.date.isoformat() }}" pubdate="pubdate">{{ article.locale_date }}</time>
+
+ <section class="post_content">
+ {{ article.summary }}
+ {% if not loop.last %}
+ <hr>
+ {% endif %}
+ </section>
+ </article>
+ {% endfor %}
+ {% endif %}
+ {% include 'navigator.html' %}
+
+ {% if TAG_FEED_RSS %}
+ <a href="{{ FEED_DOMAIN }}/{{ TAG_FEED_RSS % tag|e}}" ><img src="../theme/images/rss.png" /></a>
+ {% endif %}
+
+ {% if TAG_FEED_ATOM %}
+ <a href="{{ FEED_DOMAIN }}/{{ TAG_FEED_ATOM % tag|e}}" ><img src="../theme/images/atom.png" /></a>
+ {% endif %}
+
+ {% endblock %}
diff --git a/theme/templates/tags.html b/theme/templates/tags.html
new file mode 100755
index 0000000..681e408
--- /dev/null
+++ b/theme/templates/tags.html
@@ -0,0 +1,13 @@
+{% extends "base.html" %}
+
+{% block title %}{{ SITENAME }} - Mots-clés{% endblock %}
+
+{% block content %}
+<h2 class="page_title">Liste des mots-clés</h2>
+<ul id="tag_list">
+{% for tag, articles in tags %}
+<li><a href="{{SITEURL}}/{{tag.url}}">{{ tag }}</a> ({{ articles|count }})
+</li>
+{% endfor %}
+</ul>
+{% endblock %}