diff options
author | Chimrod <contact+git@chimrod.com> | 2013-04-16 21:27:30 +0200 |
---|---|---|
committer | Chimrod <contact+git@chimrod.com> | 2013-04-16 21:27:30 +0200 |
commit | 66a5a0cdccd464930a232c87f91e1b0805f255a5 (patch) | |
tree | 1563108cc22cfdc250108eb25b3beaf51d398dff |
initial commit
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 & hal.block.is_volume = true & 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 Binary files differnew file mode 100755 index 0000000..9f68e07 --- /dev/null +++ b/content/images/2011avril23_120334.jpg diff --git a/content/images/Capture-Navit-1-e1332786990864.png b/content/images/Capture-Navit-1-e1332786990864.png Binary files differnew file mode 100755 index 0000000..5ce1f2a --- /dev/null +++ b/content/images/Capture-Navit-1-e1332786990864.png diff --git a/content/images/Capture-Navit-e1332787251467.png b/content/images/Capture-Navit-e1332787251467.png Binary files differnew file mode 100755 index 0000000..3ab8c70 --- /dev/null +++ b/content/images/Capture-Navit-e1332787251467.png diff --git a/content/images/conf-300x175.jpg b/content/images/conf-300x175.jpg Binary files differnew file mode 100755 index 0000000..8673916 --- /dev/null +++ b/content/images/conf-300x175.jpg diff --git a/content/images/filezilla-300x140.jpg b/content/images/filezilla-300x140.jpg Binary files differnew file mode 100755 index 0000000..481a7b7 --- /dev/null +++ b/content/images/filezilla-300x140.jpg diff --git a/content/images/menu.png b/content/images/menu.png Binary files differnew file mode 100755 index 0000000..304f73c --- /dev/null +++ b/content/images/menu.png diff --git a/content/images/puttygen-300x276.jpg b/content/images/puttygen-300x276.jpg Binary files differnew file mode 100755 index 0000000..c0fa4c2 --- /dev/null +++ b/content/images/puttygen-300x276.jpg 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 Binary files differnew file mode 100755 index 0000000..559e684 --- /dev/null +++ b/theme/screenshot.png 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 Binary files differnew file mode 100755 index 0000000..89dd169 --- /dev/null +++ b/theme/static/images/atom.jpg diff --git a/theme/static/images/atom.png b/theme/static/images/atom.png Binary files differnew file mode 100755 index 0000000..15611d1 --- /dev/null +++ b/theme/static/images/atom.png diff --git a/theme/static/images/fond.jpg b/theme/static/images/fond.jpg Binary files differnew file mode 100755 index 0000000..ae3d2a1 --- /dev/null +++ b/theme/static/images/fond.jpg diff --git a/theme/static/images/header.jpg b/theme/static/images/header.jpg Binary files differnew file mode 100755 index 0000000..8b07029 --- /dev/null +++ b/theme/static/images/header.jpg diff --git a/theme/static/images/rss.jpg b/theme/static/images/rss.jpg Binary files differnew file mode 100755 index 0000000..f91d8ec --- /dev/null +++ b/theme/static/images/rss.jpg diff --git a/theme/static/images/rss.png b/theme/static/images/rss.png Binary files differnew file mode 100755 index 0000000..1ac38dd --- /dev/null +++ b/theme/static/images/rss.png 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 :</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"><<</a> + {% else %} + <a href="{{ SITEURL }}/{{ page_name }}{{ articles_page.previous_page_number() }}.html"><<</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">>></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;"> </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 %} |