Wikini

SvgHandler

PagePrincipale :: DerniersChangements :: DerniersCommentaires :: ParametresUtilisateur :: Vous êtes ec2-18-119-131-178.us-east-2.compute.amazonaws.com
L'objectif général est de proposer des interfaces de visualisations globales d'un wikini qui peuvent répondre aux questions de PourquoiCartographier

Le Handler


Le handler sert simplement a appeler d'autres scripts rangés dans un dossier /svg placé dans le dossier /page. Il s'agit en fait d'une sorte de principe de sous-handler qui permet d'en rajouter selon les besoins sans modifer l'existant.

<?php
/*
Description: Handlers pour affichages SVG 
auteurs: Yann Le Guennec - Charles Nepote
version 0.2
22.02.2005
*/
header("Content-type: image/svg+xml");
$a['reseaupagecourante'] = 1;
$a['touteslespages'] = 1;
$b $_GET['svg'];
if(isset(
$a[$b])) {
    
$url $this->config["handler_path"]."/page/svg/".$b.".php";
    if(
is_file($url)) {
        include(
$url);
    } 
}
?>


Les sous-handlers sont donc rangés dans le dossier /svg et leur nom est simplement passé en paramètre du handler principal.
Les sous-handlers sont actuellement :
demo: http://www.x-arn.org/w3/systeme/svg&svg=touteslespages
demo: http://www.x-arn.org/w3/systeme/svg&svg=reseaupagecourante

La version de demo (qui me sert de version de developpement) est accessible à partir de toutes les pages du wiki ARN
(suivre le lien SVG)
http://www.x-arn.org/w3/

Les graphes commencent à être pertinents :

function TrackLinkTo($tag) { $_SESSION["linktable"][] = $tag; }


function TrackLinkTo($tag) { if($_SESSION["linktracking"] == 1) $_SESSION["linktable"][] = $tag; }

ce qui me semble un peu étrange...


touteslespages.php



<?php
/*
Visualisation de toutes les pages
chaque page est représentée par une ellipse
sa hauteur est proportionnelle au nombre liens entrants dans la page (i)
sa largeur est proportionnelle au nombre liens sortants de la page (o)
sa couleur est fonction du nombre de modifications enregistrées (tend vers le rouge)
*/

$prefix $this->config["table_prefix"];

if(isset(
$_GET['type']) && $_GET['type'] == 'soc')
{
  
//mesure le nombre d'intervenants différents sur une page
  
$query "SELECT tag, COUNT(user) as nb_modif FROM ".$prefix."pages GROUP BY tag";
}
else
{
  
//mesure le nombre de versions de la page
  
$query "SELECT tag, COUNT(id) as nb_modif FROM ".$prefix."pages GROUP BY tag";
}

if (
$pagesM $this->LoadAll($query))
{
    foreach (
$pagesM as $page)
    {
        
$id strtolower($page['tag']); 
        
//if($id != '')
        //{
          
$p[$id] = array();
          
$p[$id]['n'] = $page['tag'];
          
$p[$id]['nbin'] = 0;
          
$p[$id]['nbout'] = 0;
          
$p[$id]['nbm'] = $page['nb_modif']; 
          
$col $p[$id]['nbm'] * 4// couleur proportionnelle, a ajuster en fonction de l'activité globale
          
if($col 255) { $col 255 ;}   
          
$p[$id]['col'] = "rgb(".$col.",0,0)"// couleur  ~ nombre de versions dans la BDD
        //}
    
}
}

$query "SELECT from_tag, to_tag, COUNT(from_tag) as nb_from_tag FROM ".$prefix."links GROUP BY to_tag";
if (
$pagesF $this->LoadAll($query))
{
    foreach (
$pagesF as $page)
    {
        
$id strtolower($page['to_tag']); 
        if(!
is_array($p[$id])) // variable page non encore initialisée = page non enregistrée 
        

          
$p[$id] = array();
          
$p[$id]['n'] = $page['to_tag'];
          
$p[$id]['nbin'] = 0;
          
$p[$id]['nbout'] = 0;
          
$p[$id]['nbm'] = 0;
          
$p[$id]['col'] = "rgb(0,0,255)"// + page sans lien sortant
        
}
               
        
$p[$id]['nbin'] = $page['nb_from_tag'];  // nombre de liens entrants
    
}
}


$query "SELECT from_tag, to_tag, COUNT(to_tag) as nb_to_tag FROM ".$prefix."links GROUP BY from_tag";
if (
$pagesT $this->LoadAll($query))
{
    foreach (
$pagesT as $page)
    {
        
$id strtolower($page['from_tag']);
        if(!
is_array($p[$id]))
        { 
          
$p[$id] = array();
          
$p[$id]['n'] = $page['from_tag'];
          
$p[$id]['nbin'] = 0;
          
$p[$id]['nbout'] = 0;
          
$p[$id]['nbm'] = 0;
          
$p[$id]['col'] = "rgb(0,255,0)"// page pas encore enregistrée sans lien entrant
        
}
        
$p[$id]['nbout'] = $page['nb_to_tag']; //nombre de liens sortants
    
}
}

$svg_body_rect "";
$svg_body_el "";
$svg_body_txt "";
foreach (
$p as $paf)
{
    
$xr rand(0,5000);
    
$yr rand(0,2000);
    
$wr = (1+$paf['nbout']) * 10// largeur ~ liens sortants
    
$hr = (1+$paf['nbin']) * 10// hauteur ~ liens entrants
    
$svg_body_rect .= "<rect x=\"$xr\" y=\"$yr\" width=\"$wr\" height=\"$hr\"/>\n";
    
$svg_body_el   .= "<ellipse fill=\"".$paf['col']."\" cx=\"$xr\" cy=\"$yr\" rx=\"$wr\" ry=\"$hr\"/>\n";
    
$svg_body_txt  .= "<a xlink:href=\"".$this->config["base_url"].$paf['n']."\"><text onmouseover=\"selection(evt)\" onmouseout=\"deselection(evt)\" x=\"$xr\" y=\"$yr\">".$paf['n']." : i" .$paf['nbin']. " : o"$paf['nbout'] . "</text></a>\n";
}
    
//preserveAspectRatio=\"none\"
$svg_head =  "<?xml version=\"1.0\"  encoding=\"iso-8859-1\" ?> \r\n";
$svg_head .= "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\" \n     \"http://www.w3.org/TR/2001/PR-SVG-20010719/DTD/svg10.dtd\">\n";
$svg_head .= "<svg width=\"100%\" height=\"100%\"  viewBox=\"0,0,5000,2000\"  
     xml:base=\"http://x-arn.org/y/\"
     xmlns=\"http://www.w3.org/2000/svg\" 
     xmlns:xlink=\"http://www.w3.org/1999/xlink\"> \n"
;
$svg_head .= "<style type=\"text/css\"> \n";
$svg_head .= "   <![CDATA[ \n";
$svg_head .= "          #fond { fill:#fff }\n";
$svg_head .= "          text { fill:#000; font-family:arial; font-size: 2em; }\n";
//$svg_head .= "          rect { fill:#fff; fill-opacity: 0.2; stroke: #000; stroke-width:1; }\n";
$svg_head .= "          ellipse {  fill-opacity: 0.2; stroke: #000; stroke-width:1; }\n";
$svg_head .= "   ]]> \n";
$svg_head .= " </style> \n";

$svg_head .= "<rect id=\"fond\" x=\"0\" y=\"0\" width=\"100%\" height=\"100%\" />\n";

$svg_foot .= "</svg>";

$svg $svg_head $svg_body_el $svg_body_txt $svg_foot;
print(
$svg);
?>



reseaupagecourante.php


<?php
/*
Description: Handler pour l'affichage SVG du réseau de liens d'une page wikini
auteurs: Yann Le Guennec - Charles Nepote
version : 0.0.5

Paramètres utilisateurs:
script = on : active le script de déplacement des mots
subnet = off : desactive le réseau de liens secondaires
center = off : ne centre pas le rectangle de la page courante
style = dark | white (defaut) : styles de couleurs  
*/



$styles = array("white"=>"""dark"=>"");
$affich_param ""// pour affichage dans le commentaire du source SVG 
$svg_uri "/svg&amp;svg=reseaupagecourante";
if(isset(
$_GET['script']) && $_GET['script'] == 'on') {
  
$script true;
  
$svg_uri .= "&amp;script=on";
  
$affich_param .= "    script : on\n";
} else {
  
$script false;
  
$affich_param .= "    script : off\n";
}
if(isset(
$_GET['subnet']) && $_GET['subnet'] == 'off') {
  
$subnet false;
  
$svg_uri .= "&amp;subnet=off";
  
$affich_param .= "    subnet : off\n";
} else {
  
$subnet true;
  
$affich_param .= "    subnet : on\n";
}
if(isset(
$_GET['center']) && $_GET['center'] == 'off') {
  
$center false;
  
$svg_uri .= "&amp;center=off";
  
$affich_param .= "    center : off\n";
} else {
  
$center true;
  
$affich_param .= "    center : on\n";
}
if(isset(
$_GET['style'])) {
  
$style $_GET['style'];
  if(isset(
$styles[$style])) {
    
$svg_uri .= "&amp;style=$style";
  } else {
    
$style "white";
  }
} else {
  
$style "white";
}
$affich_param .= "    style : $style\n";

$n 0// nombre de pages liées à la page courante
$p = array();

//page courante
$id $this->getPageTag();
$p[$id]['n'] = $id;         // nom de la page
$p[$id]['c'] = 'cur';       // classe css
$p[$id]['w'] = 10;          // largeur de zone par defaut


//Backlinks
if ($pagesFrom $this->LoadPagesLinkingTo($this->getPageTag()))
{    
    foreach (
$pagesFrom as $pageFrom)
    {
        
$id $pageFrom["tag"];
        if(
$id != $this->getPageTag())// exclusion des liens de la page vers elle même
        
{
            if(!
is_array($p[$id])) // si le neud n'est pas deja enregistré
            
{
                
$p[$id]['n'] = $id;
                
$p[$id]['c'] = 'in';
                
$p[$id]['w'] = 10;
                
$n++; // incremente le nombre de noeuds
            
}
            
// le noeud existe deja ou pas : on incremente la taille du rectangle
            
$p[$id]['w']++;
            
$p[$this->getPageTag()]['w']++;
        }
    }
}
//Liens sortants
$query "select to_tag as tag from ".$this->config["table_prefix"]."links where from_tag = '".mysql_escape_string($this->getPageTag())."' order by tag";
if (
$pagesTo $this->LoadAll($query))
{
    foreach (
$pagesTo as $pageTo)
    {
        
$id $pageTo["tag"];
        if(
$id != $this->getPageTag()) //exclusion des liens de la page vers elle même
        
{
            if(!
is_array($p[$id])) // si le neud n'est pas deja enregistré
            
{
                
$p[$id]['n'] = $pageTo["tag"];
                
$p[$id]['c'] = 'out';
                
$p[$id]['w'] = 10;
                
$n++;
            }
            else
            {
                
$p[$id]['c'] = 'inout'// lien entrant et sortant
            
}
            
$p[$id]['w']++;
            
$p[$this->getPageTag()]['w']++;
        }
    }
}



// taille de police
// la taille de police augmente de 1 em à chaque 30 noeuds supplémentaires dans le graphe
$fontsize ceil($n/30); 

$styles["white"] = 
    #fond         { fill:#fff; }  
    text          { fill:#808080; font-family:arial; font-size:"
.$fontsize."em;} 
    rect.cur      { fill:#ffffff; fill-opacity:0.7; stroke:#ff0000; stroke-width:1;} 
    rect.in       { fill:#ffff00; fill-opacity:0.5; stroke:#ffff00; stroke-width:1; }
    rect.out      { fill:#ffcccc; fill-opacity:0.5; stroke:#ff0000; stroke-width:1; } 
    rect.inout    { fill:#ff0000; fill-opacity:0.5; stroke:#ff0000; stroke-width:1; } 
    line          { stroke:#808080; opacity:0.1; stroke-width:1;}  
    line.in       { stroke:#ffff00; opacity:0.5 }
    line.out      { stroke:#ffcccc; opacity:0.5 } 
    line.inout    { stroke:#ff0000; opacity:0.5; stroke-width:3; } 
"
;

$styles["dark"] = 
    #fond         { fill:#000; }  
    text          { fill:#ccc; font-family:arial; font-size:"
.$fontsize."em;} 
    rect.cur      { fill:#ff0000; fill-opacity:1; } 
    rect.in       { fill:#00ff00; fill-opacity:0.5; stroke:#00ff00; stroke-width:1; }
    rect.out      { fill:#0000ff; fill-opacity:0.5; stroke:#0000ff; stroke-width:1; } 
    rect.inout    { fill:#ff00ff; fill-opacity:0.5; stroke:#ff00ff; stroke-width:1; } 
    line          { stroke:#808080; opacity:0.1; stroke-width:1;}  
    line.in       { stroke:#00ff00; opacity:0.5 }
    line.out      { stroke:#0000ff; opacity:0.5 } 
    line.inout    { stroke:#ff00ff; opacity:0.5; stroke-width:3; } 
"
;


// calcul de la viewbox
if($n 3) { $n 3; }
$vw $n 50;
$vh round($n*100/3);

//agrandissement pour limiter les debordements
//largeur de la viewbox
$vxw round($vw 1000/$n); 
//hauteur de la viewbox
$vxh round($vh 1000/$n);
//$vxw = $vw+10;
//$vxh = $vh+10;

$viewbox "0 0 $vxw $vxh";

// attribution de coordonnées aléatoires
while(list($k,$v) = each($p))
{
    
$p[$k]['x'] = rand(0$vw);
    
$p[$k]['y'] = rand(0$vh);
}


if(
$center) {
    
$p[$this->getPageTag()]['x'] = $vxw 2;
    
$p[$this->getPageTag()]['y'] = $vxh 2;
}


// coordonnées du centre du rectangle de la page courante
//$p[$this->getPageTag()]['w'] = $n;
$cur_w $p[$this->getPageTag()]['w'];
$cur_x $p[$this->getPageTag()]['x'];
$cur_y $p[$this->getPageTag()]['y'];
$x1 = ($cur_w/2) + $cur_x;
$y1 = ($cur_w/2) + $cur_y;


$svg_head "";     // début du fichier svg
$svg_links "";    // couche de carrés cliquables
$svg_txt "";      // nom des pages
$svg_lines "";    // liaisons avec la page courante
$svg_rs "";       // reseau de liens secondaires
$svg_foot "";     // fin de fichier

//ecriture du SVG
$svg_head =  "<?xml version=\"1.0\"  encoding=\"iso-8859-1\" ?> \r\n";
$svg_head .= "<!-- 
    Cartographie des "
.$n." pages liées à la page ".$this->getPageTag().". 
    Généré par svg.php - version 0.0.4. 
    Le "
.date("Y-m-d H:i:s").
$affich_param 
--> \n"
;
    
$svg_head .= "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\" \n     \"http://www.w3.org/TR/2001/PR-SVG-20010719/DTD/svg10.dtd\">\n";
$svg_head .= "<svg width=\"100%\" height=\"100%\"  viewBox=\"$viewbox\" preserveAspectRatio=\"none\" 
     xml:base=\"http://x-arn.org/y/\"
     xmlns=\"http://www.w3.org/2000/svg\" 
     xmlns:xlink=\"http://www.w3.org/1999/xlink\"> \n"
;
$svg_head .= "<style type=\"text/css\"> \n";
$svg_head .= "   <![CDATA[ \n";
$svg_head .= $styles[$style];
$svg_head .= "   ]]> \n";
$svg_head .= " </style> \n";

$svg_head .= "<rect id=\"fond\" x=\"0\" y=\"0\" width=\"100%\" height=\"100%\" />\n";

if(
$script)
{
$svg_head .= " <script type=\"text/ecmascript\"><![CDATA[  
function a(evt,i) {
    //doc = evt.target.ownerDocument;
    doc =  evt.getTarget().getOwnerDocument();
    text_id = 't[' + i + ']';
    text_element = doc.getElementById(text_id);
    x= text_element.getAttribute('x');
    if(x==10) {
        b(evt,i);
    } else {
        text_element.setAttribute('x', 10);
        text_element.setAttribute('style', 'fill:#ccc');
    }
}
function b(evt,i) {
    doc =  evt.getTarget().getOwnerDocument();
    text_id = 't[' + i + ']';
    rect_id = 'r[' + i + ']';
    text_element = doc.getElementById(text_id);
    rect_element = doc.getElementById(rect_id);
    x= rect_element.getAttribute('x');
    text_element.setAttribute('x', x);
    text_element.setAttribute('style', 'fill:#000');
}
function c(evt,i) {
    doc =  evt.getTarget().getOwnerDocument();
    text_id = 't[' + i + ']';
    text_element = doc.getElementById(text_id);
    text_element.setAttribute('style', 'fill:#ff0000');
}
function d(evt,i) {
    doc =  evt.getTarget().getOwnerDocument();
    text_id = 't[' + i + ']';
    text_element = doc.getElementById(text_id);
    x = text_element.getAttribute('x');
    if(x==10) {
        text_element.setAttribute('style', 'fill:#ccc');
    } else {
        text_element.setAttribute('style', 'fill:#000');
    }
}
]]> 
</script>\n"
;
}


//variables pour les identifiants des éléments
$i 0;    
$j 0;  

//valeurs par defaut : pas de script
$mouseEvent1 "";
$mouseEvent2 "";
$mouseEvent3 "";

foreach (
$p as $page)
{
    
// réseau de liens secondaires
    
if($subnet)
    {
        
$nompage $page['n'];
        if(
$nompage != $this->getPageTag()) // exclusion de la recherche de backlinks sur la page courante
        
{
            if (
$retroLiens $this->LoadPagesLinkingTo($nompage)) //backlinks
            
{
                foreach (
$retroLiens as $retroLien)
                {
                    
$id $retroLien["tag"]; //$p[$id]['n'] est donc une page qui pointe vers p[$nompage]
                    
if(is_array($p[$id]) && $p[$id]['n'] != $this->getPageTag())
                    {
                        
$svg_rs .= "<line id=\"l[$i]\" x1=\"".$p[$id]['x']."\" y1=\"".$p[$id]['y']."\" x2=\"".$page['x']."\" y2=\"".$page['y']."\"/>\n";
                        
$page['w']++; //incrementation de la taille de la page liée
                        
$i++;
                    }
                }
            }
        }
    }
    
    if(
$script)
    {
      
$mouseEvent1 " onmouseover=\"b(evt,$j)\" ";
      
$mouseEvent2 " onmouseover=\"c(evt,$j)\" onmouseout=\"d(evt,$j)\"  ";
      
$mouseEvent3 " onmouseover=\"a(evt,$j)\" ";
    }
    
    
//ajuste les coords de ligne au centre des carrés
    
$page['cx'] =  ($page['w']/2) + $page['x'];
    
$page['cy'] =  ($page['w']/2) + $page['y'];

    
//rectangle de page en lien vers le SVG correspondant
    
$svg_links .= "<a id=\"ar[$j]\" $mouseEvent1 xlink:href=\"".$this->config["base_url"].$page['n']."$svg_uri\"><rect id=\"r[$j]\" x=\"".$page['x']."\" y=\"".$page['y']."\" width=\"".$page['w']."\" height=\"".$page['w']."\" class=\"".$page['c']."\"/></a>\n";

    
//rectangle equivalent sous le premier pour lien vers page dans wiki
    
$y2 $page['y'] + $page['w'];
    
$svg_links .= "<a id=\"ar2[$j]\" $mouseEvent2 xlink:href=\"".$this->config["base_url"].$page['n']."\"><rect id=\"r2[$j]\" x=\"".$page['x']."\" y=\"$y2\" width=\"".$page['w']."\" height=\"".$page['w']."\" class=\"".$page['c']."\"/></a>\n";
    
    
//texte : nom de la page 
    
$script ?  $x 10 $x $page['x'];
    
$script ?  $svg_txt .= "" $svg_txt .= "<a xlink:href=\"".$this->config["base_url"].$page['n']."$svg_uri\">";
    
$svg_txt .= "<text id=\"t[$j]\" $mouseEvent3  x=\"$x\"  y=\"".$page['y']."\">".$page['n'];
    
$svg_txt .= "</text>";
    
$script ?  $svg_txt .= "" $svg_txt .= "</a>"
    
$svg_txt .= "\n";
    
    
//ligne sur la page courante
    
$svg_lines .= "<line id=\"l[$i]\" class=\"".$page['c']."\" x1=\"$x1\" y1=\"$y1\" x2=\"".$page['cx']."\" y2=\"".$page['cy']."\"/>\n";

    
$i++;
    
$j++;
}

$svg_foot .= "</svg>";

$svg $svg_head $svg_rs $svg_lines $svg_txt $svg_links $svg_foot;
print(
$svg);
?>



Installation

case "svg":
                header("Content-type: image/svg+xml");
                print($this->Method($this->method));
                break;


DEMO


Sur wikini.net (version 0.0.1)







Liste des changements effectués

TODO



Remarques / Options



+ Lorsque deux noms se chevauchent et pour améliorer globalement l'interactivité, il est possible de colorer un titre au passage de la souris :
-- CharlesNepote

Après quelques essais pour placer un fond sous un texte, le tout au premier plan dans l'arbre XML du SVG, et le tout manipulé par le DOM, il s'avère que le plug in a du mal à suivre sur les gros graphes même si ça semble correct dans le principe... la version 0.0.3 prend une autre option et propose une solution globale qui me semble assez ludique et exploratoire, voire utilisable :) .... à tester...
--YannLeGuennec

détails de prog

Pour la taille des titres il suffit d'ajouter un compteur $nb dans ton calcul des backlinks puis :
$size = round((1/$nb)*10, 1);
if ($size<"1") $size = "1";

et enfin
$svg_head .= " text { fill:#000; font-family:arial; font-size:".$size."em; } \n";

si on fait ça, la taille de police est à 1 dès que l'on a 10 noeuds ? la solution retenue pour le moment est :
$fontsize = ceil($n/30);
la taille de police augmente de 1 em à chaque 30 noeuds supplémentaires dans le graphe


Commentaires pour la version 0.0.3

Version très surprenante mais en définitive très séduisante :

A revoir ?

J'ai eu cette impression aussi. D'un autre coté ce type de représentation pose des questions sur qui me semble avoir du sens sur la structure du wiki visualisé. Cette disproportion vient en partie du fait que la taille de chaque rectangle est dans cette version proportionnelle à son poids relatif sur l'ensemble du wiki et non plus seulement dans le réseau de liens de la page courante. Ainsi PagePrincipale par exemple pourra apparaître énorme par rapport à la page courante parcequ'elle fait partie du menu qui se trouve sur toutes les pages. On peut donc équilibrer la taille des rectangles en jouant sur les paramètres de la visualisation, mais on peut aussi s'interroger sur la relation qui unit la page courante avec la PagePrincipale, et s'il ne serait pas judicieux d'exclure les liens de menu de la représentation. En travaillant uniquement sur les liens de 'contenu' de la page, on avancerait peut-être finalement vers des représentations proches des réseaux sémantiques ou cartes de concepts.

Questions :

Personnellement je préfère l'option vision graphique au chargement du SVG, ceci dit c'est une modification très simple à réaliser qui pourrait peut-être être paramétrée par l'utilisateur


> désactivé par défaut, activable en passant script=on en parametre. Comme ça on peut récupérer quelquechose d'exploitable dans la version de mozilla qui ne gèrent pas le script par exemple


Utilisation des liens relatifs

Pour utiliser des liens relatifs, d'après http://www.w3.org/TR/2001/REC-xmlbase-20010627/, le code devrait être (noter le xml:base) :
<svg xml:base="http://www.x-arn.org/y/" width="100%" height="100%"  viewBox="0 0 1500 1000" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg" > 
<!-- ...... -->
<a xlink:href="wakka.php?wiki=ToutesLesActions"><text x="1169" y="349">ToutesLesActions</text></a>
<!-- ...... -->

mais ça ne fonctionne pas en local chez moi... il y a pourtant une substantielle économie de code à faire...
Je vais creuser ça.
-- CharlesNepote

Bugs


Argh, merci LordFarquaad! (la v0.2 devrait régler le problème). tu as récupéré le login/pass MySQL ? normalement non, il n'était possible que d'executer d'autres fichiers PHP de la distrib ? --yann
En fait ce que je te conseille de faire pour assurer la sécurité tout en permettant la modularité, c'est de n'autoriser que des modules svg dont le nom n'est composé que de chiffres et de lettres. Comme ça, impossible de remonter dans les répertoires. (interdire simplement les slash/antislash pourrait aussi faire l'affaire mais bon, on sait jamais...) -- LordFarquaad
Il n'y a pas de commentaire sur cette page. [Afficher commentaires/formulaire]