Tous les articles par Bruno

OpenOffice.org Writer – NumĂ©rotation des titres

J’ai souvent des problĂšmes avec la numĂ©rotation des titres sous OpenOffice.org Writer. J’utilise logiquement les styles pour dĂ©finir mes titres de paragraphes mais je ne trouvais pas pratique d’affecter la numĂ©rotation correspondante. Je passais par le menu “Format > Bullets and numbering…” (Dans la version française c’est “Format > Puces et numĂ©rotation…“).

En fait ce n’est pas ce menu qu’il faut utiliser, mais “Tools > Outline numbering…” (Dans la version française c’est “Outils > NumĂ©rotation des chapitres…“). Choisir le niveau (Level) de 1 Ă  10 (1-10) et affecter la numĂ©rotation dĂ©sirĂ©e.

Numérotation des titres avec OpenOffice.org Writer

Simple, mais pas dans le bon menu je trouve. Il suffit de le savoir.

Greasemonkey et chaque site devient mien

Greasemonkey est une extension Ă  Mozilla Firefox qui permet de dĂ©finir des Javascript personnels qui ne sont appliquĂ©s qu’à certains sites. Cela permet de les personnaliser Ă  nos besoins.
J’ai donc eu l’idĂ©e d’utiliser et tester ce plugin pour faciliter l’utilisation d’un site que je consulte rĂ©guliĂšrement, Ă  savoir LinuxFR. En effet, les commentaires des articles sont prĂ©sentĂ©s sous forme d’une arborescence. Si la premiĂšre branche d’un commentaire est assez facile Ă  suivre, il est plus ardu de rattacher les commentaires suivants Ă  celui auquel ils rĂ©pondent.

Nom de code : PAPA

Je vais donc essayer de construire un script pour Greasemonkey qui va me permettre à partir de n’importe quel commentaire de retrouver facilement celui auquel il se rattache. Son pùre. Ce projet s’appellera donc provisoirement PAPA en attendant d’avoir plus d’inspiration.

Références

Pour commencer, voici quelques url qui peuvent ĂȘtre utiles pour faire des user scripts avec Greasemonkey :
–  « Writing User Scripts », explication rapide sur la crĂ©ation de scripts Greasemonkey,
–  « Gecko DOM Reference »
–  Une liste de User scripts alimentĂ©e par un wiki,
–  Le site UserScripts qui veut proposer un outil plus poussĂ© pour catĂ©goriser les diffĂ©rents scripts.
–  Une prĂ©sentation en français sur le site du Journal du net dans la section dĂ©veloppeurs.
À noter : Les utilisateurs d’Internet Explorer peuvent aussi utiliser les user scripts à l’aide de l’extension turnabout. La version 8 du navigateur Opera semble aussi pourvoir supporter les scripts utilisateurs.
À noter encore : Utiliser GreaseMonkey peut causer quelques soucis avec les pages utilisant dĂ©jĂ  du javascript, voir ce tĂ©moignage [1].

Principes

Une fois la page d’un article de LinuxFR chargĂ©e, le script va s’éxĂ©cuter. Il va ainsi parcourir l’arbre DOM de cette page et modifier le bloc contenant le titre de chaque commentaire en ajoutant un lien “Masquer“. Ceci ne sera fait que pour les commentaires qui ne sont pas le premier fils d’un commentaire de niveau supĂ©rieur [2]. Quand on cliquera sur ce lien, tous les commentaires prĂ©cĂ©dents de mĂȘme niveau seront masquĂ©s. On pourra donc facilement accĂ©der au commentaire pĂšre pour suivre le fil de discussion.
Donc en images, voici ce que cela donne. On lit le fil d’un commentaire et on arrive au bout d’une branche. Le commentaire suivant est donc une rĂ©ponse Ă  un texte qui apparait bien plus haut dans l’arborescence. Il n’est pas toujours facile Ă  retrouver, surtout dans un arbre Ă  trolls.

Avant masquage

En cliquant sur le lien Masquer que l’on apercoit en bas de la page je vais me retrouver positionnĂ© sur le commentaire pĂšre – pour ainsi savoir sur quoi porte la rĂ©ponse suivante – et les Ă©lĂ©ments intermĂ©diaires seront masquĂ©s, comme ceci :

Aprés masquage

En cliquant sur Afficher on revient Ă  la normal.

Installation du user script PAPA

Si vous voulez l’utiliser, il suffit d’installer l’extension Greasemonkey, de redĂ©marrer Mozilla Firefox [3] et de “cliquer droit” sur ce lien. Dans le menu contextuelle qui apparait, il faut choisir « Install User Script ».

Menu contextuel sur un lien {.user.js}

Le code du script

Ci-dessous le code du script que j’ai rĂ©alisĂ©.

// ==UserScript==
// @name          LinuxFR papa
// @namespace     /papa
// @description          [en] : This user script adds action links to each comment in comments tree
//                of Linuxfr.org website in order to improve navigability. With this
//                script you are able to find easily the parent of a comment and
//                hide (or display) a part of this tree.
//
//                [fr] : Ce "user script" ajoute des liens actifs Ă  chaque commentaire dans
//                l'arbre des commentaires du site Linuxfr.org dans le but d'améliorer l'expérience
//                de navigation. Avec ce script vous ĂȘtes capable de trouver facilement le pĂšre d'un
//                commentaire et de cacher (ou d'afficher) une partie de cet arbre.
// @include       http://linuxfr.org/*
// @exclude       http://linuxfr.org/my/
// ==/UserScript==
// Notes:
//   version 0.4 - 02/12/2005 - correction suite a modification dans le code html de LinuxFR : Le script ne
//                              s'exécutait plus. Apparement il y a eu des changements dans les pages, et le
//                              onload ne s'exécutait pas, donc le script ne pouvait pas se dérouler. J'ai donc
//                              supprimer l'attachement du script Ă  onload.
//   version 0.3 - 17/08/2005 - ajout licence GPL
//                            - modification de la description
//                            - ajout d'une traduction en anglais
//
//   version 0.2 - 05/06/2005 - quand on clique sur "Masquer" on est positionné sur le commentaire parent
//                            - un seul lien "Masquer" ou "Afficher" est visible. En fonction de ce qui est
//                              possible pour un commentaire, soit l'un soit l'autre est visible.
//
//   version 0.1 - 04/06/2005 - premiere version.
//
//   auteur  : Bruno ARLIGUY
//
//   licence : GPL license - http://www.gnu.org/copyleft/gpl.html

(function()
{
        //Listener positionné sur chaque lien "Masquer" quand on le "clique".
        // On va masquer le lien "Masquer", afficher le lien "Afficher" et ensuite
        // parcourir tous les commentaires précédents (ie previousSibling) et les masquer
        //
        // param e : l'évÚnement reçu par l'objet auquel est associé ce listener
        function hideSibling(e)
        {
                //masquer le lien "masquer"
                e.target.style.display = 'none';
                //afficher le lien "afficher"
                e.target.nextSibling.style.display = 'block';
                //masquer les commentaires précédents
                var currentComment = e.target.parentNode.parentNode.parentNode.parentNode;
                if (currentComment)
                {
                        for (var sibling = currentComment.previousSibling; sibling.nodeName == 'UL'; sibling = sibling.previousSibling)
                        {
                                sibling.style.display = 'none';
                        }
                }
        }

        //Listener positionné sur chaque lien "Afficher" quand on le "clique".
        // On va masquer le lien "Afficher", afficher le lien "Masquer" et ensuite
        // parcourir tous les commentaires précédents (ie previousSibling) et les afficher
        //
        // Attention : ceci va re-afficher tous les commentaires prĂ©cĂ©dents de mĂȘme niveau,
        // mĂȘme si ils n'ont pas Ă©tĂ© cachĂ©s en activant le lien "cacher" correspondant au lien
        // "afficher" actuellement actif. Il faut donc repositionner les liens "Afficher" et "Masquer"
        // de ces commentaires, car certains pourraient ĂȘtre innapropriĂ©s.
        //
        // param e : l'évÚnement reçu par l'objet auquel est associé ce listener
        function showSibling(e)
        {
                //masquer le lien "afficher"
                e.target.style.display = 'none';
                //afficher le lien "masquer"
                e.target.previousSibling.style.display = 'block';
                //afficher les commentaires précédents
                var currentComment = e.target.parentNode.parentNode.parentNode.parentNode;
                var papaBlock      = null;
                if (currentComment)
                {
                        for (var sibling = currentComment.previousSibling; sibling.nodeName == 'UL'; sibling = sibling.previousSibling)
                        {
                                sibling.style.display = 'block';
                                papaBlock = document.evaluate("./li/h1/div", sibling, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
                                if (papaBlock != null)
                                {
                                        papaBlock.childNodes[0].style.display = 'block';
                                        papaBlock.childNodes[1].style.display = 'none';
                                }
                        }
                }
        }

        //Construit un block (div) qui contient les liens "Masquer" et "Afficher" pour l'UL passé en paramÚtre.
        //
        // param ul : un objet qui doit représenter un UL correspondant à
        //            un commentaire (ie répond au xpath //ul[@class='commentsul'])
        function getPapaBlock(ul)
        {
                var namedLink  = ul.firstChild.childNodes[1];
                var parentLink = ul.parentNode.childNodes[1];
                var id         = namedLink.name;
                var div        = document.createElement("div");
                var aHide      = document.createElement("a");
                var aShow      = document.createElement("a");

                //
                div.setAttribute("id", "pn" + namedLink.name);
                div.setAttribute("class", "pn");
                div.setAttribute("style", "float: right;");

                //Faire pointer le lien masquant sur le commentaire parent.
                aHide.setAttribute("href", "#" + parentLink.name);
                aHide.setAttribute("id", "hide" + namedLink.name);
                aHide.setAttribute("class", "pn");
                aHide.addEventListener("click", hideSibling, false);

                aShow.setAttribute("href", "#" + namedLink.name);
                aShow.setAttribute("id", "show" + namedLink.name);
                aShow.setAttribute("class", "pn");
                aShow.setAttribute("style", "display: none");
                aShow.addEventListener("click", showSibling, false);

                div.appendChild(aHide);
                div.appendChild(aShow);

                aHide.appendChild(document.createTextNode("- Masquer"));
                aShow.appendChild(document.createTextNode("+ Afficher"));

                return div;
        }

                try
                {
                        // Recupérer tous les UL de classe "commentsul". Pour chacun, ajouter un bloc dans sa barre de titre.
                        // Ce bloc contiendra deux liens : "Masquer" et "Afficher". Chaque lien appellera un script
                        // qui appliquera l'action correspondante (masquer ou afficher) sur tous les "previousSibling" du
                        // commentaire associĂ©. Le lien en lui mĂȘme consistera Ă  appeler la mĂȘme page en la positionnant sur :
                        //    - le lien nommé correspondant au commentaire parent si l'utilisateur a cliqué sur "Masquer"
                        //    - le lien nommé correspondant au commentaire si l'utilisateur a cliqué sur "Afficher".
                        // les liens nommés sont ceux de la forme <a name="580185"></a> et qui sont les "childNodes[1]" de chaque //ul[@class='commentsul'].
                        var elements = document.evaluate("//ul[@class='commentsul']", document, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
                        var uls = new Array();
                        var ul  = null;
                        //tranferer les éléments trouvés dans un tableau.
                        for (var i = 0; ul = elements.iterateNext(); i++)
                        {
                                uls[i] = ul;
                        }

                        var before = null;
                        var previous = null;
                        for (var i = 0; i < uls.length; i++)
                        {
                                previous = uls[i].previousSibling;
                                while (previous.nodeName == "#text")
                                {
                                        previous = previous.previousSibling;
                                }

                                if (previous.nodeName == "UL")
                                {
                                        //Selectionner le premier H1 Ă  partir du premier enfant de cet UL. J'utilise une expression xPath car
                                        // apparement le Html de LinuxFR a tendance à évoluer. Donc un accés relatif comme avant (avec des numéros
                                        // d'index dans les enfants, par exemple uls[i].firstChild.childNodes[5]) rendait le code trop dépendant des
                                        // modifications du code.
                                        before = document.evaluate("./h1", uls[i].firstChild, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue.firstChild;
                                        before.parentNode.insertBefore(getPapaBlock(uls[i]), before);
                                }
                        }
                }
                catch (ex)
                {
                        GM_log(ex);
                }
})();
[1] Ce n’est pas un avis nĂ©gatif sur l’utilisation de GreaseMonkey, juste qu’il faut faire attention Ă  ce que l’on fait avec
[2] dĂ©solĂ©, je n’ai pas rĂ©ussi Ă  expliquer ceci plus simplement
[3] Oui oui, il faut arrĂȘter FireFox - toutes les instances lancĂ©es sous le mĂȘme profil - et le relancer

Cartes de références pour développeurs

Voici quelques sites qui proposent des fiches de référence pour différents outils/langages. Toujours utile à avoir sous la main :

  • Quick References Cards propose « JSP Syntax », « XSLT and XPath Quick Reference », « XSL Transformations (XSLT) 1.0 », « Apache Quick Reference Card », etc…
  • RefCards propose « Apache », « CVS », « MySQL », « HTML DOM », « CSS level 2 », « XPath », etc…
  • Peter Dickman propose sa carte de rĂ©fĂ©rence Java 5 et 6.

Tunneling SSH – transfert de ports

Le but de ce document est d’expliquer les tunnels SSH. C’est Ă  dire comment utiliser SSH pour faire passer diffĂ©rents protocoles, ce qui permet de sĂ©curiser la communication (une sorte de VPN software). Si vous souhaitez plus de dĂ©tails sur les diffĂ©rentes possibilitĂ©s, cet article de Buddhika Chamith vous Ă©clairera : SSH Tunneling Explained.

Quand on se connecte Ă  Internet depuis un lieu public et si ce lieu de connexion ne permet pas d’accĂ©der Ă  des ports particuliers d’un serveur (rĂšgles de firewall restrictives), il est possible d’utiliser un serveur intermĂ©diaire sur lequel on a un compte utilisateur et qui fait tourner un serveur ssh. C’est ce serveur qui se connectera au serveur dĂ©sirĂ©. Cette solution va aussi permettre de chiffrer la communication entre le point d’accĂšs et le serveur intermĂ©diaire.

Pour rĂ©aliser cela, on va utiliser un tunnel SSH. Il faut donc que l’on ai accĂšs au port 22 du serveur intermĂ©diaire, mais dans 90% des cas les firewalls laissent sortir le trafic sur ce port.

Le principe

Il faut crĂ©er une connexion ssh entre le pc client et le serveur intermĂ©diaire. Cette connexion (le tunnel donc) connectera un port du pc client au serveur intermĂ©diaire. Celui-ci va lire tout ce qu’il reçoit depuis cette connexion et re-expĂ©dier le tout vers le serveur destinataire.

attention : sous Linux, on ne peut pas connecter le tunnel sur un port local privilĂ©giĂ© si on n’est pas root. Il faut donc prendre un port au dessus de 2000.

Exemple

Je veux lire mes mails par un accĂ©s imap. Mon serveur imap est imap.mail.com et je l’interroge sur le port 143 (le porte par dĂ©faut IMAP).  Mais le firewall ne laisse pas sortir les connexions vers le port 143.

Je vais donc Ă©tablir un tunnel SSH entre le pc que j’utilise et un serveur sur lequel j’ai un accĂ©s ssh. Ce serveur s’appelle monserveurssh.com et j’ai un compte utilisateur de login moncompte. Je vais connecter le tunnel sur le port 2000 de mon pc client, comme suit :

ssh -2NfC -L2000:imap.mail.com:143 moncompte@monserveurssh.com

Cette commande ne me connecte pas sur le serveur intermĂ©diaire, mais me rend la main de suite grĂące a l’option -f combinĂ©e avec l’option -N. L’option -2 c’est pour demander Ă  ssh d’utiliser le protocole v2 et l’option -C c’est pour demander de compresser le tunnel.

Il ne me reste plus qu’à brancher mon client mail sur le port 2000 de localhost, et je pourrai lire mes mails, comme si j’étais connectĂ© directement au serveur de mails.

Un détail sécurité

Quand je créé des comptes utilisateurs sur mon serveur juste pour permettre du port forwarding je ne donne pas le droit de connexion au serveur. Pour cela, dans le fichier /etc/passwd je remplace le shell du compte par /sbin/nologin. Ainsi la personne qui a ce compte peut créer des tunnels SSH mais elle ne peut pas se connecter au serveur.

Sous Windows

En utilisant Cygwin et le client ssh fourni avec, cela fonctionne trĂšs bien. Putty permet aussi d’établir des tunnels pour ceux qui sont rĂ©fractaires Ă  la ligne de commande.

Quelques liens sur le sujet

Faire un backup avec rsync

On peut utiliser ssh pour faire un backup d’une machine distante (pratique pour conserver une copie d’un site web, en ne tĂ©lĂ©chargeant que ce qui a changĂ© depuis le dernier backup) avec rsync

rsync -v -u -a --rsh=ssh --stats user@serveur.net:/chemin/dossier/distant/a/sauver /chemin/dossier/local

Commandes diff, patch mode d’emploi

Quelques tips pour bien utiliser la commande patch.

La commande diff

Cette commande permet de trouver les differences entre 2 fichiers. Elle vous retourne la ligne du fichier original et la ligne modifiée. Elle va nous permettre de créer le patch que nous pourrons ensuite appliquer. Il existe plusieurs types de patch. Celui qui est le plus répandu est le patch unifié car il apporte de la souplesse dans son application en permettant une certaine variation du fichier à patcher.

La commande patch

La commande patch va prendre en entrĂ© le resultat de la commande diff et va appliquer les changements sur le fichier dĂ©signĂ©. Le fait d’avoir dans le patch la version originale et la version modifiĂ©e permet d’éviter de patcher un fichier qui n’est pas le bon, ou mĂȘme de patcher un fichier dĂ©jĂ  Ă  jour.

Exemple :

diff -aburN --exclude=CVS* repertoire/reference/ repertoire/modifie/ > patch.diff

Cette commande crĂ©e un patch unifiĂ©. InterĂȘt des options passĂ©es :

  • -a : traiter tout les fichiers comme du texte
  • -b : permet de ne pas tenir compte des diffĂ©rences sur les espaces
  • -u : faire un patch unifiĂ©
  • -r : parcourrir les sous rĂ©pertoires
  • -N : permet de gĂ©rer les fichiers nouveaux
  • —exclude=CVS : permet d’exclure des fichiers ou rĂ©pertoire de l’analyse.

Le patch ainsi fabriquĂ© contient des Ă©lĂ©ments qui vont permettre Ă  la commande patch de retrouver les fichiers Ă  modifier Ă  travers l’arborescense, puis de trouver les bonnes lignes, mĂȘme si celles-ci ont lĂ©gĂšrement Ă©tĂ© dĂ©placĂ©es.

patch -p 1 < patch.diff

L’option -p N permet d’adapter l’aborescence d’origine du patch à l’arborescence que l’on est en train de traiter.