4
28 juin 2010

Introduction


Cette présentation est une version dérivée de la documentation officielle en anglais sur le site du projet. Elle a d'abord été faite pour TinyOWS 0.8.0. Entre temps, la version 0.9.0 est sortie et le tutoriel a aussi été testé pour la 0.9.0.

La principale différence entre cette documentation et celle du site officiel reste le niveau de détail sur l'environnement nécessaire à l'installation.
Sur les parties "Installation de TinyOWS et fonctionnement basique en WFS" ainsi que "Utiliser TinyOWS avec du WFS-T", il ne s'agit que d'une version francisée et adaptée à des tests "en local" de documents, par ailleurs, disponibles en anglais sur http://tinyows.org/trac/wiki/OpenLayersHowToBasic et http://tinyows.org/trac/wiki/OpenLayersHowToTransactional
Nous souhaitons ainsi que TinyOWS ne devienne plus seulement adopté par les "early adopters" (précurseurs) du SIG.

Intérêts de l'outil

Pour citer le développeur principal, Olivier Courtin lors de sa présentation à OSGIS UK 2010

"Pourquoi TinyOWS ?

  • Parce que Mapserver ne fait pas de WFS-T (et il n'est pas prévu qu'il en fasse)
  • Parce que vous ne souhaitez peut-être pas installer et maintenir un serveur Tomcat seulement pour Geoserver
  • Parce que le standard WFS-T est proche des concepts des bases de données spatiales, et que Postgis est un bon choix
  • Parce que les échanges WFS nécessitent vraiment des hautes performances"

Des informations détaillées sur les performances de TinyOWS sont disponibles sur http://tinyows.org/trac/wiki/ConferenceSlide

Dépendance technique pour le fonctionnement de TinyOWS

TinyOWS nécessite d'avoir installé les librairies/applications suivantes :

  • libxml2 (version 2.6.20 ou supérieure)
  • PostGIS (version 1.5.x ou supérieure)
  • PostgreSQL (avec les entêtes libpq, donc les paquets de développement)
  • Un serveur web avec le support cgi-bin

Installation préalable des librairies/applications nécessaires au fonctionnement


Commencons par le plus facile : libxml2


sudo apt-get install libxml2 libxml2-dev

Mise en place de la base de données avec la cartouche spatiale

Actuellement sous Ubuntu, il n'existe pas de paquets (en simplifiant, l'équivalent d'un fichier exe ou msi sous Windows) pour Postgis 1.5
Nous allons devoir compiler Postgis 1.5 pour résoudre ce problème (plus d'informations sur la compilation)
Pour cela, nous allons reprendre un tutoriel "pompé" sur Georezo et ForumSIG (tuto dont je suis l'auteur ;))

Installation des paquets depuis les dépôts

Installation des paquets nécessaires à la compilation, de PostgreSQL avec les entêtes libpq et installation de proj, une librairie, gérant les référentiels spatiaux c'est à dire les projections cartographiques.

sudo apt-get install build-essential automake autoconf m4 autotools-dev
sudo apt-get install postgresql-8.4 libpq-dev postgresql-server-dev-8.4
sudo apt-get install proj libproj-dev

Installation de GEOS (Il faut pour postgis 1.5, geos >= à la version 3.1.1 et celle de Lucid est la 3.1.0 )

GEOS (Geometry Engine - Open Source) est une librairie qui apporte des fonctionnalités de constructions d'objets géométriques et de traitements spatiaux. Elle est un portage en C++ de la JTS (Java Topology Suite), une librairie Java ayant les mêmes fonctionnalités.

Nettoyage du paquet GEOS (si nécessaire) :


sudo apt-get --purge libgeos-3.1.0

Installation de Geos en manuel :

Récupération des sources et décompression des fichiers :

wget http://download.osgeo.org/geos/geos-3.2.2.tar.bz2
tar -xvjf geos-3.2.2.tar.bz2
cd geos-3.2.2

Installation de quelques paquets supplémentaires pour disposer de SWIG (Simplified Wrapper and Interface Generator) qui permet de connecter des logiciels ou bibliothèques logicielles écrites en C/C++ avec des langages de scripts comme Ruby ou Python pour Geos (optionnelle) :

sudo apt-get install python-dev swig libtool

Vérification des dépendances, compilation, installation des binaires et mise à jour des chemins vers les librairies partagées

Si vous avez installé SWIG :


./configure --enable-python

Sinon :

./configure

Ensuite quel que soit le choix effectué :

make
sudo make install
sudo ldconfig


cd ..


Installation de Postgis

Comme précédemment pour Geos mais avec Postgis maintenant :)


wget http://postgis.refractions.net/download/postgis-1.5.1.tar.gz
tar -xvzf postgis-1.5.1.tar.gz
cd postgis-1.5.1/
./configure
make
sudo make install
sudo ldconfig

Test de chargement d'une base de données :


sudo -s -u postgres

#changer le mot de passe de postgres à "atlas" pour pouvoir se connecter ultérieurement
psql -c"ALTER user postgres WITH PASSWORD 'atlas'"

createdb geodb # (avec le mot de passe atlas)
createlang -dgeodb plpgsql
psql -dgeodb -f /usr/share/postgresql/8.4/contrib/postgis-1.5/postgis.sql
psql -dgeodb -f /usr/share/postgresql/8.4/contrib/postgis-1.5/spatial_ref_sys.sql
psql -dgeodb -c"select postgis_full_version();"

La dernière ligne devrait vous renvoyer si tout va bien :


postgis_full_version
-------------------------------------------------------------------------------------------------------
POSTGIS="1.5.1" GEOS="3.2.2-CAPI-1.6.2" PROJ="Rel. 4.7.1, 23 September 2009" LIBXML="2.7.6" USE_STATS
(1 ligne)

(END)

Installation de Pgadmin III

C'est une interface graphique de connexion plus agréable pour commencer sous PostgreSQL/PostGIS
Installer-la avec après être sorti de l'authentification postgres :

exit
sudo apt-get install pgadmin3

Installation du serveur web

Un serveur Web est un ordinateur central qui fait en sorte que vous puissiez voir avec votre navigateur les sites Web se trouvant sur ce serveur. Il permet aussi de mettre à disposition des services à destination d'autres utilisateurs et permettant d'échanger avec eux (exemple : webservices de l'OGC).

Nous avons fait le choix d'installer plus que le nécessaire pour ce tutoriel :
En plus de Apache, nous avons rajouté le support de MySQL et PostgreSQL dans PHP 5 si vous souhaitiez développer en vous connectant sur ces bases.

Installer Apache et PHP 5


sudo apt-get install libapr1 apache2 apache2-utils apache2.2-common apache2-mpm-prefork libapache2-mod-chroot libapache2-mod-auth-pam libapache2-mod-auth-sys-group
sudo apt-get install php5 php5-cgi php5-common php5 php5-gd libapache2-mod-php5 php5-pgsql php5-mysql php5-xsl

Tester Apache avec :

sudo service apache2 restart

Une erreur est retournée. Nous allons pour le moment l'ignorer pour revenir ultérieurement dessus.

Installer et configurer MySQL serveur ainsi que les module MySQL et PostgreSQL pour Apache

On passe encore par le gestionnaire de paquets (pour ceux, qui n'ont pas compris ce que c'est -> http://doc.ubuntu-fr.org/gestionnaire_de_paquets) :

sudo apt-get install libapache2-mod-auth-pgsql # module Apache 2 pour l'authentification POSTGRESQL
sudo apt-get install mysql-server libapache2-mod-auth-mysql # MySQL server et module Apache 2 pour l'authentification MySQL

Cela retourne :


Outil de configuration des paquets

+----------------¦ Configuration de mysql-server-5.1 +-----------------+
¦ Il est très fortement recommandé d'établir un mot de passe pour le ¦
¦ compte d'administration de MySQL (« root »). ¦
¦ ¦
¦ Si ce champ est laissé vide, le mot de passe ne sera pas changé. ¦
¦ ¦
¦ Nouveau mot de passe du superutilisateur de MySQL : ¦
¦ ¦
¦ ____________________________________________________________________ ¦
¦ ¦
¦ ¦
¦ ¦
+----------------------------------------------------------------------+

Saisir votre mot de passe et le noter pour ne pas l'oublier.
Le-ressaisir pour confirmation.

Editer le fichier suivant qui joue sur la configuration Apache et sur le fonctionnement cgi avec :

sudo nano /etc/apache2/apache2.conf

Ecrire à la fin du fichier :

ServerName localhost

Ecrire à la suite pour utiliser cgi-bin :

ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/

Options ExecCGI
AddHandler cgi-script cgi pl py


Enregistrer puis relancer Apache avec :

sudo service apache2 restart

Normalement le retour doit être :

* Restarting web server apache2 ...
waiting [ OK ]

L'erreur signalée antérieurement a été réglée ;)

Installation de TinyOWS et fonctionnement basique en WFS


Compilation et installation depuis les sources stables de TinyOWS


wget http://tinyows.org/tracdocs/release/tinyows-0.9.0.tar.bz2
tar xvjf tinyows-0.9.0.tar.bz2
cd tinyows
./configure
make
sudo make install
sudo make install-demo

Copier le binaire obtenu dans le répertoire cgi-bin après avoir changé quelques droits :

sudo chmod 777 /usr/lib/cgi-bin/
cp tinyows /usr/lib/cgi-bin/

Tester et utiliser TinyOWS

C'est bien, vous avez un binaire installé mais comment on se sert de ce binaire ?

Précédemment, nous sommes passés rapidement dessus la ligne de commande :

sudo make install-demo

Celle-ci a créée une base de données explorable via pgadmin III .

Editer le fichier de configuration de tinyows :

sudo nano /usr/local/tinyows/config.xml

Inspecter le code, comparer-le avec ci-dessous pour le comprendre et seulement ensuite le changer (sinon ça n'a pas d'intérêt qu'on vous fasse un tutoriel ;) )
Regardez également du côté de la documentation officielle du site et plus précisément http://tinyows.org/trac/wiki/ConfigFile pour comprendre certains paramètres.


schema_dir="/usr/local/tinyows/schema/">

title="TinyOWS Server - Demo Service" />

site="http://www.tinyows.org/"
email="

" />

writable="1"
prefix="tows"
server="localhost"
name="world"
title="World Administrative Boundaries" />

writable="1"
prefix="tows"
server="localhost"
name="france"
title="French Administrative Sub Boundaries (IGN - GeoFLA Departements)" />



cd /usr/lib/cgi-bin
sudo ./tinyows --check


cd ~
wget http://openlayers.org/download/OpenLayers-2.9.tar.gz
tar xvzf OpenLayers-2.9.tar.gz

Créer et changer les droits du répertoire qui recevra les fichiers visibles sur le serveur :

sudo mkdir /var/www/tinyows
sudo chmod -R 777 /var/www/tinyows


mv OpenLayers-2.9 /var/www/tinyows/Openlayers-2.9
cd /var/www/tinyows/
cp Openlayers-2.9/examples/proxy.cgi /usr/lib/cgi-bin/
nano /usr/lib/cgi-bin/proxy.cgi

Rajouter "localhost" et "127.0.0.1" ( pour limiter le risque d'erreur entre l'alias et l'IP) comme ci-dessous
allowedHosts = ['127.0.0.1','localhost', 'www.openlayers.org', 'openlayers.org', ... ]

Faire ensuite :

nano Openlayers-2.9/examples/tinyows.html

et coller :



WFS Basic with TinyOWS and GeoJSON


WFS Basic example with TinyOWS, using GeoJSON.

Shows the use of the WFS Basic with TinyOWS Server, using GeoJSON.

WMS base layer is GeoSignal one.
Vector datas are GeoFLA Departements (IGN).
Size of datas are about 800 Ko (either Shapefile or GeoJSON).
Right now it's the top limit that OpenLayers can decently handle.

See the tinyows.js
source
to see how this is done.




Créer un fichier javascript avec :

nano Openlayers-2.9/examples/tinyows.js

et insérer :

var map;
OpenLayers.ProxyHost = "/cgi-bin/proxy.cgi?url=";

function init() {
map = new OpenLayers.Map('map', {
projection: new OpenLayers.Projection("EPSG:27582"),
units: "m",
maxResolution: "auto",
maxExtent: new OpenLayers.Bounds(5000,1620000,1198000,2678000),
controls: [
new OpenLayers.Control.PanZoom()
]
});

var base = new OpenLayers.Layer.WMS("OpenLayers WMS",
"http://www.geosignal.org/cgi-bin/wmsmap?",
{layers: "Regions,Departements",
projection:"EPSG:27582",
units: "m",
maxResolution: "auto",
maxExtent: new OpenLayers.Bounds(5000,1620000,1198000,2678000),
sld: "http://www.tinyows.org/tracdocs/demo/OpenLayers-2.9/examples/sld.xml"
}
);
map.addLayer(base);

var wfs = new OpenLayers.Layer.Vector("Countries", {
strategies: [new OpenLayers.Strategy.BBOX()],
projection:"EPSG:27582",
protocol: new OpenLayers.Protocol.WFS({
url: "http://localhost/cgi-bin/tinyows?",
featureType: "france",
featureNS: "http://localhost/",
outputFormat: "application/json",
readFormat: new OpenLayers.Format.GeoJSON()
})
});
map.addLayer(wfs);

map.zoomToExtent(new OpenLayers.Bounds(5000,1620000,1198000,2678000));
}

Tester que cela fonctionne en allant sur http://localhost/tinyows/Openlayers-2.9/examples/tinyows.html

TinyOWS_Basic.jpg

Jusqu'à maintenant, nous parlions d'utiliser TinyOWS comme serveur WFS-T, pour le moment, nous nous sommes contentés de faire la démonstration de TinyOWS comme serveur WFS, nous allons donc passer à l'étape suivante.

Utiliser TinyOWS avec du WFS-T


Comme précédemment, nous allons créer une base de données :


createdb -h localhost -p 5432 -U postgres -W tinyows
createlang -h localhost -p 5432 -U postgres -W plpgsql tinyows
psql -h localhost -p 5432 -U postgres -W -d tinyows < `pg_config --sharedir`/contrib/postgis-1.5/postgis.sql
psql -h localhost -p 5432 -U postgres -W -d tinyows < `pg_config --sharedir`/contrib/postgis-1.5/spatial_ref_sys.sql

Nous allons charger les fichiers de démonstration :

wget ftp://ftp.intevation.de/freegis/frida/frida-1.0.1-shp.tar.gz
tar xvzf frida-1.0.1-shp.tar.gz
cd frida-1.0.1-shp
shp2pgsql -s 31467 -I gruenflaechen.shp frida | psql -h localhost -p 5432 -U postgres -d tinyows

Une erreur se produit. Le cas n'est rencontré que maintenant car via le "make install-demo" du précédent cas, le chemin vers shp2pgsql était renseigné dans le script appelé par make install-demo.
Vous pouvez tenter de taper shp2pgsql, vous aurez une erreur. Il faut si l'on veut accéder à shp2pgsql dans la ligne de commande, on doit rajouter le chemin du binaire shp2pgsql dans la variable d'environnement PATH.
Pour en savoir plus sur les variables d'environnement, allez sur http://www.commentcamarche.net/faq/3585-bash-la-variable-d-environnement... .

Faites :

export PATH=$PATH:/usr/lib/postgresql/8.4/bin

puis tester avec :

shp2pgsql

C'est bon !!! Vous pouvez relancer l'import du shp dans PostgreSQL :

shp2pgsql -s 31467 -I gruenflaechen.shp frida | psql -h localhost -p 5432 -U postgres -d tinyows

Sauvegarder le xml de la première partie puis créer le nouveau fichier avec :

sudo cp /usr/local/tinyows/config.xml /usr/local/tinyows/config_install_demo.xml
sudo vim /usr/local/tinyows/config.xml

Puis remplacer le contenu par le code ci-dessous :

schema_dir="/usr/local/tinyows/schema/">

title="TinyOWS Server - WFS-T Frida Service" />

site="http://www.tinyows.org/"
email="

" />

writable="1"
prefix="frida"
server="localhost"
name="frida"
title="Frida Parks" />



Ne pas oublier d'enregistrer ;)

Comme pour le premier cas, on va vérifier la configuration en faisant :

cd /usr/lib/cgi-bin

puis :

./tinyows --check

qui renvoie :

Config File: OK
PG Connection: OK
Available layers:
- public.frida -> 31467 RW

Après cette étape, nous allons admettre que vous êtes parti du début du tutoriel et ne pas réexpliquer comment récupérer Openlayers et configurer le proxy.cgi.
Nous allons donc créer le fichier html "qui va bien" avec son fichier javascript associé.
Faire pour cela :

cd /var/www/tinyows/

puis :

vim Openlayers-2.9/examples/tinyows_wfs-t.html

Coller :



WFS Transaction Example, (TinyOWS ans OpenLayers)

Shows the use of the WFS Transactions (WFS-T).
Parks of Osnabruck (Frida).

Base layers is OpenStreetMap from Omniscale WMS Server.

The WFS protocol allows for creation of new features and
reading, updating, or deleting of existing features.

Use the tools to create, modify, and delete (in order from left
to right) features. Use the save tool (picture of a disk) to
save your changes. Use the navigation tool (hand) to stop
editing and use the mouse for map navigation.

See the

wfs-protocol-transactions.js source to see how this is done.



Ensuite créer un fichier avec :

vim Openlayers-2.9/examples/tinyows_wfs-t.js

et contenant :


var map, wfs;
OpenLayers.ProxyHost = "/cgi-bin/proxy.cgi?url=";

var DeleteFeature = OpenLayers.Class(OpenLayers.Control, {
initialize: function(layer, options) {
OpenLayers.Control.prototype.initialize.apply(this, [options]);
this.layer = layer;
this.handler = new OpenLayers.Handler.Feature(
this, layer, {click: this.clickFeature}
);
},
clickFeature: function(feature) {
// if feature doesn't have a fid, destroy it
if(feature.fid == undefined) {
this.layer.destroyFeatures([feature]);
} else {
feature.state = OpenLayers.State.DELETE;
this.layer.events.triggerEvent("afterfeaturemodified",
{feature: feature});
feature.renderIntent = "select";
this.layer.drawFeature(feature);
}
},
setMap: function(map) {
this.handler.setMap(map);
OpenLayers.Control.prototype.setMap.apply(this, arguments);
},
CLASS_NAME: "OpenLayers.Control.DeleteFeature"
});

function showMsg(szMessage) {
document.getElementById("message").innerHTML = szMessage;
setTimeout(
"document.getElementById('message').innerHTML = ''",2000);
}

function showSuccessMsg(){
showMsg("Transaction successfully completed");
};

function showFailureMsg(){
showMsg("An error occured while operating the transaction");
};

function init() {
map = new OpenLayers.Map('map', {
projection: new OpenLayers.Projection("EPSG:31467"),
units: "m",
maxResolution: "auto",
maxExtent: new OpenLayers.Bounds(3427000,5788000,3444000,5800000),
controls: [
new OpenLayers.Control.PanZoom()
]
});

var osm = new OpenLayers.Layer.WMS(
"OSM by Omniscale WMS",
"http://osm.omniscale.net/proxy/service",
{layers: 'osm', format: 'image/jpeg'},
{projection:"EPSG:31467", units: "m", maxResolution: "auto", maxExtent: new OpenLayers.Bounds(3427000,5788000,3444000,5800000)}
);

var saveStrategy = new OpenLayers.Strategy.Save();
saveStrategy.events.register("success", '', showSuccessMsg);
saveStrategy.events.register("failure", '', showFailureMsg);

wfs = new OpenLayers.Layer.Vector("Editable Features", {
strategies: [new OpenLayers.Strategy.BBOX(), saveStrategy],
projection: new OpenLayers.Projection("EPSG:31467"),
protocol: new OpenLayers.Protocol.WFS({
version: "1.1.0",
srsName: "EPSG:31467",
url: "http://www.tinyows.org/cgi-bin/tinyows",
featureNS : "http://www.tinyows.org/",
featureType: "frida",
geometryName: "the_geom",
schema: "http://www.tinyows.org/cgi-bin/tinyows?service=wfs&request=DescribeFeatureType&version=1.1.0&typename=tows:frida"
})
});

map.addLayers([osm, wfs]);

var panel = new OpenLayers.Control.Panel(
{'displayClass': 'customEditingToolbar'}
);

var navigate = new OpenLayers.Control.Navigation({
title: "Pan Map"
});

var draw = new OpenLayers.Control.DrawFeature(
wfs, OpenLayers.Handler.Polygon,
{
title: "Draw Feature",
displayClass: "olControlDrawFeaturePolygon",
multi: true
}
);

var edit = new OpenLayers.Control.ModifyFeature(wfs, {
title: "Modify Feature",
displayClass: "olControlModifyFeature"
});

var del = new DeleteFeature(wfs, {title: "Delete Feature"});

var save = new OpenLayers.Control.Button({
title: "Save Changes",
trigger: function() {
if(edit.feature) {
edit.selectControl.unselectAll();
}
saveStrategy.save();
},
displayClass: "olControlSaveFeatures"
});

panel.addControls([navigate, save, del, edit, draw]);
panel.defaultControl = navigate;
map.addControl(panel);
map.zoomToMaxExtent();
}

Vous pouvez tester sur votre serveur en allant http://localhost/tinyows/Openlayers-2.9/examples/tinyows_wfs-t.html .

Vous avez vu comment configurer TinyOWS sur votre propre serveur (à l'exception d'un fichier de style) , à vous de jouer maintenant.

Pour vous motiver, voilà ce que peut donner une version avancée d'usage de TinyOWS :

TinyOWS_Advanced.jpg

Thomas

Crédits


PostgreSQL/PostGIS

L'installation est minimale : nous n'avons pas, par exemple, installé les paquets pour générer la documentation
Merci aux différentes personnes ayant alimentées les sources citées (Javier de la Torre, Regina Obe, Kevin Neufeld ainsi que Yannick, Sparky et Elemmire )

TinyOWS

Sources principales

Page principale du projet TinyOWS

Mailing lists utilisateurs et développeurs

TinyOWS 0.9.0 présenté lors de l’OsGIS UK 2010

Merci aux contributeurs/développeurs du projet

Oslandia

  • Olivier Courtin (développeur principal)

DM Solutions

  • Assefa Yewondwossen (integration windows 32(MS4W))

MapGears

  • Normand Savard (correction de bugs)
  • Alexandre Dube (Integration dans OpenLayers)

Intevation

  • Stephan Holl (Paquets Debian)

Camptocamp

  • Barbara Philippot (développeuse initiale)
A propos de l'auteur: 
Thomas Gratier

A partir du moment où ils permettent de faire de la géomatique/cartographie, l'auteur utilise tous les languages de programmation en particulier ceux dynamiques (JavaScript, PHP, Python, ...)

"Dépendant" au webmapping côté client comme serveur (avec surtout MapServer, PostGIS, OpenLayers et GDAL) et plus généralement à la cartographie, il se soigne en faisant sa veille technologique sur la dataviz, l'opensource et l'opendata.

Sa présence dans l'équipe s'explique par une phrase : "Autant mutualiser notre curiosité!"

Lecteur assidu, il est surtout un fan de pêche à la ligne quand il dispose de suffisamment de temps ;)

Commentaires

Le tuto en lui seul est très fourni. Il me reste de trouver le temps de l’appliquer. Merci.

Le résultat est bon. Merci pour toutes ces instructions. Prestashop

Salut,
Comme TinyOWS fait maintenant partie du projet MapServer Suite, il faudrait mettre à jour les liens vers la doc, qui a changé de place pour intégrer la doc MapServer aussi.

Bonjour,

Tuto très intéressant !

Je me pose une question : D'où vient le prefix tows (ou frida, ici) dans le fichier de configuration ?

Faut-il en mettre un automatiquement ? J'essaie de connecter une table postgis mais je ne vois pas quel prefix mettre :)

Voici mon xml de config :

schema_dir="/usr/local/tinyows/schema/">

title="TinyOWS Server - Demo Service" />

site="http://www.tinyows.org/"
email="

" />

writable="1"
prefix="capv_transport_contribution_arceau"
server="localhost"
name="capv_transport_contribution_arceau"
title="Arceau" />

Et le /usr/lib/cgi-bin/tinyows --check me ressort :

TinyOWS version: 1.0.0
FCGI support: No
Config File Path: /etc/tinyows.xml (TinyOWS XML)
PostGIS Version: 1.5.3
PostGIS dsn: host=127.0.0.1 user=password=_ dbname=port=5432
Output Encoding: UTF-8
Database Encoding: UTF8
Schema dir: /usr/local/tinyows/schema/
Display bbox: Yes
Estimated extent: No
Check schema: Yes
Check valid geoms: Yes
Available layers:
- public.capv_transport_contribution_arceau (3945) -> .capv_transport_contribution_arceau [RW] --> Pas de préfix ici !! Juste un point !!

Si vous pouvez éclairer ma lanterne !!

Merci
Fabien