dadadi blog

To content | To menu | To search

Saturday, September 10 2011

repeat last search in slrn newsreader

This week, I changed my newsreader from tin to slrn. I've not totally finished the switch yet, but I've just implemented a useful functionality.

slrn, like in tin, lacks a repeat last search functionality. When you perform a search, you type your search in a prompt. And when you want to repeat the same search, you are prompted again. Last searched string is proposed as a default choice in the prompt, but you still have to validate it, and in the long run, that's quite inconvenient. Unlike tin, it's possible to write macros for slrn, so I could implement this.

Slrn is built around the S-Lang library. This library can be used as an alternative to ncurses, to build text-based user interfaces. Also, It allows embedding a small scripting language. Thanks to that, it's possible to write macros in slrn.

There are 2 modes in slrn: display groups or display articles. In article mode, there are 3 types of search: search by subject, search by author, and search within an article. Each search can be performed backward or forward. In order to implement repeat last search, I had to override each those 6 methods with methods storing searched string and search method before performing the search. Then, I added a new function which could repeat last search.

Currently, it only works in article mode. In group mode here is an api to search within group (group_search), but backward search is not exposed trough the api. So, it was not possible to implement a coherent repeat last search behavior.

Here is the script. To use it, save it in a file named, for example, .slrn.search.sl and in your .slrnrc add following line:

interpret ".slrn.search.sl"

repeat last search functionality is bound to g key. If that doesn't suit you, edit last line of the script.

%%%
% 
% These script allows to repeat last search in slrn
%
%  In slrn, there is no "repeat last search" function. Moreover, there are
%  three types of search in article mode: 
%    - search an article by subject
%    - search an article by author
%    - search within an article
%  Each of these searchs have two variants: search forward and search backward
%
% So, to implement "repeat last search", I needed to overwrite those 6 native
% search functions with custom macros. Those macros replicate the native
% behavior and store last searched string, and last search action. Then, an
% additional macro can check those informations to perform "repeat last search"
% action.
%
% This script bind "repeat last search" action to "g" key (think, "go on"). If
% you want to change that, edit last line of this file.

variable Search_Method = "";
    % suf: subject forward
    % sub: subject backward
    % auf: author forward
    % aub: author backward
    % arf: article forward
    % arb: article backward

variable Search_Str = "";

define do_search(method) {
    variable dir, ret;

    if (method == "") {
        method = Search_Method;
        if (method == "") { % no search has been done yet
            return;
        }
    } else {
        variable prompt;
        if (method == "suf") {
            prompt = "Search on subject: ";
        } else if (method == "sub") {
            prompt = "Search on subject (backward): ";
        } else if (method == "auf") {
            prompt = "Search on author: ";
        } else if (method == "aub") {
            prompt = "Search on author (backward): ";
        } else if (method == "arf") {
            prompt = "Search: ";
        } else if (method == "arb") {
            prompt = "Search (backward): ";
        } else { % should not happen
            error("unknow method " + method);
        }
        Search_Str =  read_mini(prompt, Search_Method, "");
        Search_Method = method;
    }
    if (Search_Str == "") {
        return;
    }

    if (method == "suf" || method == "auf") {
        dir = 1;
    } else if (method == "sub" || method == "aub") {
        dir = -1;
    } else {
        dir = 0;
    }

    % header search methods search from current position; So, we need first to
    % move to next and previous header, search from here, and move back in case
    % nothing was found
    if (dir == 1) {
        !if (header_down(1)) {
            return;
        }
    } else if (dir == -1) {
        !if (header_up(1)) {
        }
    }

    if (method == "suf") {
        ret = re_fsearch_subject(Search_Str);
    }
    if (method == "sub") {
        ret = re_bsearch_subject(Search_Str);
    }
    if (method == "auf") {
        ret = re_bsearch_author(Search_Str);
    }
    if (method == "aub") {
        ret = re_bsearch_author(Search_Str);
    }
    if (method == "arf") {
        ret = re_search_article(Search_Str);
    }
    if (method == "arb") {
        ret = re_bsearch_article(Search_Str);
    }

    if (not ret) {
        if (dir == 1) {
            header_up(1);
        } else if (dir == -1) {
            header_up(1);
        }
        error("Not found.");
    }
}

define my_search_subject_forward() {
    do_search("suf");
}

define my_search_subject_backward() {
    do_search( "sub");
}

define my_search_author_forward() {
    do_search("auf");
}

define my_search_author_backward() {
    do_search("aub");
}

define my_search_article_forward() {
    do_search("arf");
}

define my_search_article_backward() {
    do_search("arb");
}

define my_search_repeat() {
    do_search("");
}

definekey("my_search_subject_forward", "s", "article");
definekey("my_search_subject_backward", "S", "article");
definekey("my_search_author_forward", "a", "article");
definekey("my_search_author_backward", "A", "article");
definekey("my_search_article_forward", "/", "article");
definekey("my_search_article_backward", "?", "article");

definekey("my_search_repeat", "g", "article");

Friday, August 12 2011

detecting language when replying to an email with vim.

When writing an email, my email client allows me use an external text editor. So, I use vim.

I write emails either in English, either in French, and so, I set the spell check language accordingly each time. I was wondering if it was possible to detect it automatically when vim is launched. Clochix came with a hacky but functional solution. The main idea is to call aspell with your email text, once for each possible language, and count the number of misspelled words. The languages which triggers the lowest number of misspelled word is considered the right one. This can obviously lead to bad results if  email has only a few words, especially if most of them are not written correctly. But mostly, that should work.

In Clochix's implementation, we create a wrapper script around vim. It will call aspell, and call vim with arguments to launch it with the correct spellchecker. While this works, I don't like that idea much. If one day, I wish to change that configuration, I'll probably forget to remove that script. Actually, over the years, my binary folder has become cluttered with two lines scripts such as this one. Half of them could probably be removed, but I'm not totally sure I don't need them for some reason. So, I implemented this as a vim script.

When headers are edited, they contain a lot of words such as: Subject, To, etc. Using them would result in a bias towards English. So, I remove them. I just keep the subject content because it has meaning, and because it is the only information we have when starting a new mail (when replying to an email, we have the previous mail content).

This script is github. I hope you'll find it useful

Thursday, July 28 2011

Screencast de l'utilisation de syj.

Je viens de réaliser une capture vidéo de l'utilisation de Show Your Journey, afin de montrer les possibilités de l'outil: http://syj.renevier.net/screencast.ogv.

Sunday, April 10 2011

More playing with srtm data: altiph

After importing srtm data into postgis, it was time to query and use that data.

route-altitude-profile can do that, but this time, I needed a php tool. So, I wrote altiphp library.

When given longitude and latitude, altiphp queries the database and returns altitude. Actually, it queries the altitude for nearest available points, and performs a bilinear interpolation (I took the idea from route-altitude-profile). When given an array of points, altiphp returns an array of altitude.

altiphp can add points to give a more accurate route profile. For example, if you have two points at the top of two mountains, altiphp knows how to add points between them each one separated of about 90m from the next one (90m is srtm resolution). You get then an accurate route profile going down to the valley and then climbing back to the other mountain. This behavior is of course optional.

Altiphp also integrates with gisconverter.php. When gisconverter is available, altiphp can handle geometries directly.

If you have not imported srtm data in a postgis database, you can use non-postgis mode. In this mode, altiphp downloads data files form usgs server, optionally stores them for future retrieval, and parses them to extracts data. This works fine, gets the same results as postgis mode, but parsing the file is really slow and each file, once parsed, takes about 300Mo in memory. So, using this method is not a good idea for a website, even a small one, but this can be helpful in some cases, for example for a seldom used local application or for testing.

altiphp needs php 5.3, is licensed under modified bsd license and is available at github.

Sunday, April 3 2011

srtm2postgis improved

In 2000, NASA Space Shuttle Endeavour had a 11 days mission named SRTM. It was about acquiring topographic information of earth surface, from 56°S to 60°N. Data has been released in public domain. It's one of the main sources for free global topographic data.

I want to play with these data, and the first part of the game is putting data into a postgis database. Fortunately, this had already been done as part of Route altitude profiles SRTM. It's a 2008 Google Summer of Code project by Sjors Provoost. Srtm2postgis is a small utility that downloads srtm data, and loads it into postgis.

Download urls for SRTM had changed, so original srtm2postgis does not work as-is. Fortunately, a fork with updated urls is available on github.

So, I started tickering with srtm2postgis. I fixed a few minor bugs. For example, srtm data is split into 14546 files. 14540 of them have all upper case name, and 6 have lower letters name. Those 6 files could not be downloaded. I also fixed some typos in the README, and a few failing tests, but overall, the script was running smoothly.

Then I spent some time trying to improve import time. During its summer of code, Sjors Provoost reported importing data at one tile a minute speed. A 75 tiles import (44°N to 50°N and 3°E to 7°W) took me 80 minutes. This about the same as Sjors Provoost result.

To connect to postgres, srtm2postgis uses pygresql, but also uses psycopg because of its copy_from method. But copy_from method was ultimately not used, and a psql subprocess was launched to run the copy instead. A comment explained that psycopg copy_from method was hanging. I tried to use it and it was not hanging. As the comment was nearly 3 years old, I assume this is a now fixed bug. I'm also glad this was clearly documented. Otherwise, this workaround would have been impossible to understand. With this modification, my 75 tiles import was only 49 minutes. I really don't understand why this improves performances so much, but I'm happy about it.

Then, I totally remove pygresql, and only used psycopg. This allows me, first to open only one connection, then, to run everything in a single transaction, and commit everything at the end. Import was now 42 minutes.

After improving database-related performances, I tried to speed up things in other parts of the code. SRTM data is read by gdal library. It returns a 1200 * 1200 arrays of numpy.int16. Converting int16 to string is something really slow. On a 1200 * 1200 grid, many points have the same altitude. So, I use a cache to store string representations of numpy.int16 altitudes. This resulted in a major performance improvement. My 75 tile import is now 28 minutes.

I also use string buffer instead of a temporary file to store data to copy, but this does not improve performance significantly. I also tried to remove table primary key constraint and recreate it after import. I thought it would improve copy speed. But actually, it damaged performances a lot.

Eventually, I run VACUUM ANALYZE after import. This takes 10 minutes, but this will probably improve future performances.

I could improve import time from 80 to 28 minutes (38 minutes with VACUUM ANALYZE), with is nearly 3 times faster!!! My updated srtm2postgis version is available on github.

Friday, January 7 2011

js library to read zip file

I've just finished a JavaScript library to read zip file content. With it it's possible for example to get some zipped content with ajax, and use it in your webpage.

It works in all major browsers: firefox, chromium, opera, and ie7+ (althought it is quite slow in ie). Operations performed by zipfile are quite simple: ZipFile takes a string representing the file content. It extracts files headers as documented here. Decompression (the real work) is performed by deflate library. ZipFile has been heavily influenced by python zipfile module.

In Gecko 2.0, (future firefox 4.0), JavaScript typed arrays are available. They're supposed to be much more efficient than using strings for working with binary data. But I didn't use them: First, they're only available in a firefox nightly (probably soon in webkit trunk, but not yet). Then, when using them, useful string methods such as indexOf are not available.

You can see the online demo. It fetches and extracts the content of the library itself (I could not find a better example). Source code is available at github.

Thursday, November 25 2010

syj is repaired

syj was broken for about ten days. The hardware had multiple failure: RAM wich could not be replaced and hard drive. So, we moved it to another server, still in cr@ns. Backups stopped working a few days before syj stopped working. Then, some paths have been lost (about hundred), a probably a few  accounts also. Sorry for the trouble, and many thanks to Jocelyn from cr@ns for helping me restoring this service.

syj est réparé

syj était cassé depuis une dizaine de jours. En fait, la machine qui l'hébergeait était tombé en panne (RAM irremplaçable plus disque dur). Du coup, il a été déplacé sur une autre machine, toujours au cr@ns. Les sauvegardes sont tombées en panne quelques jours avant le site, ce qui fait que plusieurs chemins ont été perdus (une centaine environ) et probablement des comptes utilisateurs aussi. Désolé pour ce dérangement, et merci à Jocelyn du cr@ns de m'avoir aidé à remettre le site en état.

Tuesday, September 21 2010

import dans OpenStreetMap des points d'eau de la ville de Paris

Ce week-end, en plus de finaliser Show Your Journey, j'ai réalisé pour OpenStreetMap, l'import des points d'eau recensés par Eau de Paris.

Il y a environ un an, j'avais constaté que le site de la régie Eau de Paris fournissait des documents recensant plusieurs centaines de points d'eau. J'avais alors demandé à la régie l'autorisation de les importer dans OpenStreetMap. La régie avait donné son accord, mais ne disposait pas des données brutes, ce qui a empêché l'import. Au cours de l'été dernier, en retournant sur le site, j'ai constaté qu'il y avait maintenant une carte numérique des fontaines de Paris. J'ai alors recontacté la régie qui m'a confirmé que les données pouvaient être importées dans OpenStreetMap.

Je me suis attelé à l'import de ces données. En en discutant sur la mailing liste francophone, nous avons constaté que les données comportaient plusieurs erreurs, et un contributeur a proposé l'algorithme suivant:

Pour chaque point :

  • si il y a un point déjà indiqué à moins de 50 mètres, ne pas importer
  • si il n'y a pas de point à moins de 100 mètres, importer en ajoutant "FIXME=position approximative"
  • si le point d'eau le plus proche est entre 50 et 100 mètres, voir au cas par cas, peut-être grâce à la carte dont j'ai donné le lien

Après plusieurs essais infructueux, j'ai réalisé l'import lors des changeset 5819089, 5821219, et 5819089.

J'ai mis en place une carte des points d'eau qui permet de visualiser les points d'eau potable en France.

Au final, il manque beaucoup de points d'eau sur la carte, et il y en quelques uns qui sont probablement mal placés. Néanmoins, je pense qu'une bonne partie des 320 points d'eau ajoutés est correctement placée.

Cet données sont particulièrement intéressantes pour les randonneurs, les touristes, ou toutes les personnes qui passent plusieurs heures dans Paris en extérieur. J'espère que ces données, aujourd'hui incomplètes et parfois incorrectes, vont être améliorées prochainement, et j'espère aussi que beaucoup d'autres points potables vont être répertoriés en banlieue et dans toute la France.

Monday, September 20 2010

syj: a website to share routes

I spent a lot of times this summer writting a website to share routes. It's now done. That does not mean I won't improve it. That means it's stable, so I can make it public. That also means it has all the functionalities I need for my own usage.

Project name is syj. It means Show Your Journey. With syj, you can create and publish routes. So you can organize hiking, show clever bicycle rides, or any route you want. You can also get your routes as gpx or kml files.You can, if you have created an account, manage routes you have created: modify or delete them. Finally, you can duplicate a route before modifying it. This is really useful when you want many similar routes.

Syj is available at http://osm-syj.crans.org/.

OpenStreetMap is used for background map. Website is hosted by Cr@ns. That organization already hosts many project related to OpenStreetMap.

Website sources are available under AGPL license. For this project, I also wrote many standalone libraries available on github. Those libraries are available under modified bsd license.

I hope you'll find syj as useful as I do.

syj: site de partage d'itinéraire

J'ai passé une partie de l'été à écrire un site de partage d'itinéraires. Il est maintenant fini. Cela ne veut pas dire que je ne vais pas continuer à l'améliorer. Cela veut dire d'une part, qu'il est suffisamment stable pour que je le rende publique. D'autre part, qu'il comporte toutes les fonctionnalités que j'estimais indispensables pour mon usage.

Le projet s'appelle syj, ce qui veut dire: Show Your Journey. Il permet donc de créer et de publier des itinéraires. Cela peut servir à préparer des randonnées, à montrer des itinéraires cyclistes malins, ou n'importe quoi d'autre. On peut également exporter les itinéraires sous forme de fichiers gpx ou kml. On peut aussi, si on crée un compte, gérer les trajets qu'on a créés, c'est à dire en récupérer la liste, les modifier ou les supprimer. Enfin, on peut dupliquer un itinéraire avant de le modifier, ce qui est très utile si l'on veut plusieurs variantes d'un itinéraire.

Syj est disponible à l'adresse http://osm-syj.crans.org/.

Le fond de carte utilisé est celui d'OpenStreetMap. Le site est hébergé par le Cr@ns, qui héberge déjà plusieurs projets liés à OpenStreetMap.

Les sources du site sont disponibles sous licence AGPL. J'ai également écrit, pour ce projet, plusieurs librairies indépendantes qui sont disponibles sur github. Ces librairies sont sous licence bsd modifiée.

J'espère que syj vous sera autant utile qu'à moi.

Thursday, August 26 2010

w3c file api (english version)

Yesterday, I had the opportunity to play with file API. This API, proposed by Mozilla, allows reading a file content directly from a webpage, that is, without sending it to the server first. User must provide a file, either by drag and dropping it on the page, either with a normal input file (<input type="file">). So, a web page cannot read a file on the computer without user consent.

Developer mozilla site has a good tutorial about the subject. This allowed me to quickly set up a small demo. A world map is displayed (thanks to OpenLayers library). When a file with geographic informations is dropped on it, the file is read by the web page, and geometries are automatically drawn on the map.

Currently, demo only works with Firefox 3.6 because it's the only web engine to implement this functionality. A bug is opened on webkit bugtracker, but no real progress has been made yet.

To try the demo, you need to have some KML, GPX or OSM files. If you don't have some, you can download some example files.

Wednesday, August 25 2010

w3c file api (version française)

Aujourd'hui, j'ai joué un peu avec l'api fichier proposée par Mozilla. Elle permet de lire le contenu d'un fichier directement depuis une page web, sans avoir besoin de l'envoyer d'abord sur le serveur. L'utilisateur doit fournir le fichier, soit avec en le glissant sur la page, soit avec un champ de type fichier classique (<input type="file">). Ainsi, cela ne cause pas un trou de sécurité énorme en laissant une page lire n'importe quel fichier sur le disque de l'utilisateur.

Le site developer mozilla a un bon tutoriel sur le sujet. Cela m'a permis de mettre en place rapidement une petite démonstration qui utilise cette fonctionnalité. Une carte du monde est affichée (grâce à la librairie OpenLayers). Et lorsqu'on y fait glisser un fichier contenant des informations géographiques, le fichier est lu par la page web, et les géométries sont automatiquement affichées sur la carte.

À l'heure actuelle, la démonstration ne fonctionne qu'avec Firefox 3.6 car c'est le seul navigateur à implémenter cette fonctionnalité. Du côté de webkit, les discussions ont commencé dans le gestionnaire de bugs, mais n'ont pas encore abouti réellement abouti.

Pour tester la démonstration, vous devez disposer de fichiers KML, GPX ou OSM. Si vous n'en avez pas, vous pouvez télécharger des fichiers d'exemple.

Thursday, July 1 2010

simplebox: a lightbox-like library for prototype

Still as part of my next project, and still wanting to move reusable code into autonomous projects, I wrote simplebox, a lightbox-like library: a javascript library to display modal elements in a web page.

There already exist a lot of modal javascript libraries, but I was looking for one that:

  1. worked with prototype
  2. does not need script.aculo.us
  3. works for random html content (not only images)
  4. was opensource

So, I wrote my own. You can see a basic example or check code at github.

Thursday, June 3 2010

conversion hexadécimal vers décimal en php

L'autre jour, j'avais besoin en php de vérifier qu'une valeur était bien un nombre hexadécimal, puis de le convertir en décimal. Pour convertir un hexadécimal en décimal, on peut utiliser la fonction hexdec. Mais, comme spécifié, elle ignorera tout caractère non-hexadécimal qu'elle rencontrera. Du coup, la chaîne 0xAMB est considérée comme 0xAB, et on ne peut pas savoir, avec hexdec, si la chaîne convertie est valide.

Pour réaliser cette validation, il y a, depuis la version 5.2 de php[1] , la fonction filter_var. Elle filtre une variable avec un filtre spécifique. En l'occurence, on peut utiliser le filtre FILTER_VALIDATE_INT avec le drapeau FILTER_FLAG_ALLOW_HEX. L'instruction suivante:

filter_var($input, FILTER_VALIDATE_INT, array( 'flags'   => FILTER_FLAG_ALLOW_HEX))

renverra false si la chaîne d'entrée n'était pas valide, ou bien, l'entier converti si elle était valide.

La fonction filter_var est très souple : elle permet d'utiliser un grand nombre de filtres. On peut par exemple tester si une chaîne est une adresse ip, une url, ou bien même une adresse email valide. Ainsi, l'instruction suivante :

filter_var($input, FILTER_VALIDATE_EMAIL);

permet de valider une adresse email. Pour les curieux, l'adresse est validée suivant une expression rationnelle inspirée de celle utilisée par HTML_QuickForm.

Notes

[1] Pour les versions antérieures, il semble qu'il existe une extension PECL

Thursday, May 27 2010

gisconverter.php: a kml <-> geojson <-> wkt converter

For my next personal project, I need to convert in php, geographic data between different formats. I need that, among other things to insert those data in postgis. Actually, postgis support a lot of data format as output formats, but quite few as input formats.

Instead of of integrating that to my main project, I decided to create a related autonomous project. So, I had to implement more features than strictly needed. But I think it's more profitable in the middle and long run.

  • This library is separated from my application. So it's more easy to test, debug and extend.
  • That allow other people to reuse it in their application more easily.
  • That allow me to reuse it in my future application with zero reintegration work.

So, here is gisconverter.php

gisconverter.php only work with php 5.3 (and probably higher). php 5.3 has a few nice new features. So, I decided to not care about backward compatibility. I use namespaces so I can include it in my project without having to care about name conflict. I also use late static binding. It allow to use class constants. Prior to php 5.3, it was not possible to use class constants in derived classes. I also use closure quite a lot (along with array_map). It saved me a couple of lines of code, but I could easily have done without.

I also used phpunit to test the library. It allowed me have a really efficient workflow. I first write the tests, then I implement a method, and when all tests pass, I known my method is bug free. The tricky part is to write the tests correctly, to test the code thoroughly without being redundant. Now, I'd like to use phpunit in my main application. It's is a full website with a database, so I've not yet understood how to use it.

Monday, May 17 2010

nouvelle version mineure de prvcat

prvcat, est un plugin dotclear pour avoir des catégories privées. Une nouvelle version vient de sortir. Elle ajoute un champ de confirmation de mot de passe lors de l'enregistrement des catégories privées. Cela permettra d'éviter de se tromper en rentrant le mot de passe.

Si vous avez des remarques ou des suggestions à propos de ce plugin, n'hésitez pas à me laisser m'en faire part dans les commentaires de ce blog, ou par email.

Sunday, May 16 2010

configuration d'une imprimante pixma 610 en réseau.

Nous avons plusieurs ordinateurs sous Ubuntu ou Debian, ainsi qu'un serveur également sous Debian. Nous avons une imprimante/scanner pixma 610, qui était reliée à un des ordinateurs. Nous avons décidé de brancher l'imprimante sur le serveur, et de le configurer en serveur d'impression afin de pouvoir imprimer depuis tous les ordinateurs.

La manipulation, sans être extrêmement complexe, n'est pas triviale. Je la pose donc par écrit, tout d'abord pour m'en souvenir si je dois un jour la refaire, d'autre part, parcequ'elle pourrait être utile à d'autres personne.

configuration de l'imprimante

Installation des drivers sur le serveur

La première étape consiste à branche l'imprimante sur le serveur, et à installer les drivers afin qu'elle soit reconnue par le serveur. Pour cela, il faut se rendre sur le site autrichien de canon. En effet, il semble, d'après plusieurs commentaires lus sur les forums ubuntu que ce soit le seul endroit où tous les paquets nécessaires soient disponibles. On trouve alors la page de téléchargement des drivers. Il faut prendre les 4 paquets: scangearmp-common, scangearmp-mp610series, cnijfilter-common et cnijfilter-mp610series. Par chance, il existe des paquets Debian. Mais malheureusement, à cause de quelques utilitaires, ils dépendent de librairies graphiques que je ne souhaitais pas installer sur mon serveur (libxi6, libxext6, gtk, pango, cairo, etc).

Sous debian, il est possible d'installer un paquet sans tenir compte des dépendances avec l'option --force-depends de dpkg, mais cette solution n'est pas pérenne car apt proposera ensuite systématiquement la désinstallation de ces paquets. Il est également possible, grâce à equivs, de faire croire au système qu'une librairie est installée, sans que ce ne soit le cas. Je ne souhaitais pas non plus utiliser cette solution, car si plus tard, je veux installer un paquet qui dépende d'une de ces librairies, le paquet s'installerait correctement sans me prévenir qu'il y a un problème. J'ai donc extrait les paquets avec dpkg -x et dpkg -e. Puis j'ai édité les fichiers DEBIAN/control pour supprimer les dépendances aux librairies graphiques, et pour finir j'ai reconstruit les paquets avec dpkg -b. Cette étape n'est pas obligatoire, il est possible, pour plus de simplicité, d'installer toutes les dépendances demandées par les paquets des drivers, mais je préférais la réaliser afin de garder mon serveur un peu plus propre.

J'ai ensuite installé les fichiers ppd destinés à améliorer la qualité d'impression sous linux. Une fois téléchargée l'archive, l'installation est simple et bien documentée dans le fichier README. Je n'ai pas testé l'imprimante avant l'installation de ces fichiers; je ne sais donc pas dans quelle mesure ils améliorent l'impression.

Installation et configuration de cups

Il faut maintenant installer le paquet cups sur le serveur. Il faut ensuite modifier la directive Listen du fichier /etc/cups/cupsd.conf afin de rendre accessible cups depuis l'extérieur. La directive correspondant à ma configuration était:

Listen 192.168.1.2:631

192.168.1.2 est l'adresse du serveur sur le réseau local. 631 est le port par défaut d'ipp. J'ai également du modifier le firewall du serveur pour laisser passer le trafic venant du réseau local sur le port 631.

J'ai ensuite défini les droits d'accès et d'administration au serveur. J'ai laissé l'accès normal sans authentification à partir du réseau local. J'ai mis en place l'authentification pour la partie administration. Il y a deux possibilités: soit laisser l'accès à des utilisateurs qui ont un compte unix sur le serveur, soit recourir à des utilisateurs virtuels. J'ai choisi cette dernière solution. J'ai donc installé le paquet cups-client pour pouvoir utiliser la commande lppasswd qui m'a permis de créer ces utilisateurs, et de leur attribuer un mot de passe.

Voici la portion de mon fichier /etc/cups/cupsd.conf qui définit les droits d'accès:


DefaultAuthType BasicDigest

<location>
Order allow,deny
Allow From 127.0.0.1
Allow From @LOCAL
</location>

<location /admin>
AuthType Default
Require valid-user
Order allow,deny
Allow From 127.0.0.1
Allow From @LOCAL
</location>
<location /admin/conf>
AuthType Default
Require valid-user
Order allow,deny
Allow From 127.0.0.1
Allow From @LOCAL
</location>

Maintenant que cups est installé, il faut configurer l'imprimante. J'ai ouvert un navigateur à l'adresse http://192.168.1.2:631/, et j'ai suivi la procédure indiquée pour installer et configurer l'imprimante, il n'y avait aucune difficulté. J'ai lancé une page de test de l'impression pour vérifier que tout fonctionnait correctement.

Il est à noter que l'accès à la partie administration de cups se fait par défaut en https.

configuration des clients

Une fois cups installé, le plus dur est fait, mais il faut encore configurer les clients pour qu'ils utilisent le serveur d'impression. Il m'a fallu ajouter dans le fichier ~/.cups/client.conf, les deux lignes suivantes:

Encryption IfRequested
ServerName 192.168.1.2

Pour l'impression en console, il faut utiliser la commande lpadmin -d pour définir l'imprimante par défaut. On peut alors utiliser la commande lp sans devoir spécifier l'imprimante à chaque fois. Il est également recommandé d'installer le paquet cups-bsd afin de disposer des commandes lpr, lpq, lprm, etc.

configuration du scanner

L'imprimante étant multifonctions, j'ai aussi configuré le scanner. J'ai installé le paquet sane-utils sur le serveur. Le démon saned peut être lancé soit en permanence, soit par inetd (comportement par défaut). Comme je voulais qu'il soit lancé en permanence, j'ai du lancer dpkg-reconfigure sane-utils pour demander ce comportement.

J'ai ensuite édité le fichier /etc/sane.d/saned.conf pour y ajouter la ligne 192.168.1.0/24 afin que saned réponde aux requêtes venant du réseau local. J'ai également dû charger le module nf_conntrack_sane, puis modifier le firewall du serveur pour laisser passer le trafic venant du réseau local sur le port 6566.

Enfin, sur les postes clients, j'ai modifié les fichiers /etc/sane.d/net.conf pour qu'ils contiennent la ligne suivante: 192.168.1.2 (l'adresse du serveur).

L'imprimante/scanner est enfin configurée pour être utilisée en réseau.

conclusion

Je suis assez content d'avoir réalisé cette opération. Auparavant, pour imprimer un fichier, je devais le mettre sur clé usb puis aller l'ouvrir sur l'ordinateur connecté à l'imprimante, ça va être beaucoup plus pratique maintenant.

Cela dit, j'ai trouvé l'installation des drivers laborieuse. Le fait de devoir se rendre sur le site autrichien pour trouver les bons fichiers est complètement ubuesque. Heureusement que j'ai trouvé cette information par hasard sur les forums ubuntu. D'autre part, j'aurais aimé que les utilitaires de canon soient dans des paquets à part, cela m'aurait évité de devoir extraire puis reconstruire les paquets. Je ne sais d'ailleurs pas à quoi servent ces outils, l'impression fonctionne sans que je n'ai eu à les utiliser. Enfin, les paquets ne sont disponibles que pour une architecture 32bits. Si mon serveur avait été en 64bits, l'opération aurait été encore plus compliquée.

Thursday, May 6 2010

OpenLayers class to draw and modify a path

To display a map on a webpage, you can often use directly the api of a commercial provider (such as cloudmade Web Maps Lite or google maps api). The other solution is to use OpenLayers, a free javascript library to display embed maps in a web document.

With OpenLayers, it's quite easy to draw a path on the map. But unfortunately, once a point has been added to the path, it's not possible to modify or delete it. This is possible with web maps lite, as can be seen in this distance calculator. I really like the ergonomy of the web maps lite path creator, and wanted to have something similar for OpenLayers.

So, I wrote ModifiablePath, a class to improve OpenLayers path creator. So, when creating a path with this handler, you can move, delete or even add new points. I've put a demo online, and code is available at github.

Thursday, April 29 2010

prvcat: des catégories privées pour dotclear

Pour un blog dotclear (pas celui-là, un autre), j'avais besoin de restreindre l'accès à certains billets. Dotclear propose cette fonctionnalité: il est possible de définir un mot de passe sur un billet. Néanmoins, c'est d'une part assez contraignant de rentrer le mot de passe pour chaque billet. D'autre part, le billet n'apparaît nulle part, il faut récupérer son url dans l'interface d'administration pour y avoir accès, et fournir les urls une à une aux personnes à qui l'on souhaite donner accès aux billets privés. Il existe aussi Mode privé, un plugin qui permet de rendre le blog complètement privé. Ce n'était pas non plus ce que je cherchais.

J'ai donc fini par écrire un plugin qui correspondait à mes attentes. Je vous présente donc prvcat, un plugin dotclear qui gère les catégories privées. On peut définir une (ou plusieurs) catégorie comme privée, et lui associer un mot de passe. Les billets appartenant à cette catégorie seront automatiquement protégés par le mot de passe. Les catégories privées sont listées sur la page d'accueil du blog, mais on ne peut accèder à leur contenu qu'après avoir renseigné le bon mot de passe. On a alors accès aux billets privés, ainsi qu'au flux rss de la catégorie.

- page 1 of 2