IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

JavaScript Discussion :

Animation et ordre d'exécution [API HTML5]


Sujet :

JavaScript

  1. #1
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2014
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Février 2014
    Messages : 3
    Points : 3
    Points
    3
    Par défaut Animation et ordre d'exécution
    Bonjour à tous,

    Je ne sais pas vraiment si mon problème est un problème d'ordre d'exécution et suis débutant en javascript.
    J'ai codé une petite animation (apparition d'hexagones façon ruche) sur un canvas et j'ai besoin de votre aide pour le corriger.
    L'animation est visible ici : http://codepen.io/anon/pen/HjCGp

    Le problème est que certains hexagones se superposent. On le voit dans la démo car certains sont noirs (deux noirs opacité 0.5 superposés) et d'autres gris (un seul noir opacité 0.5, comme désiré partout).
    Je veux éviter ce problème en enregistrant, dans un tableau posTable, l'origine de l'hexagone (le coin supérieure gauche).
    A chaque fois que je veux dessiner un hexagone je vérifie que son origine n'est pas présente dans le tableau.

    Le script que je poste ci-dessous est long (je m'en excuse) mais les quelques lignes d'explications qui le suivent devraient lever le voile sur ce qui ne va pas.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    document.addEventListener('DOMContentLoaded', function(){
     
      var canvas = document.getElementById('bgCanvas');
      var context = canvas.getContext('2d');
      canvas.width = document.body.clientWidth;
      canvas.height = Math.max( window.innerHeight, document.body.clientHeight );
     
      function initPosTable( nbTot ){
        posTable = new Array(nbTot);
        for (var i = nbTot - 1; i >= 0; i--) {
          posTable[i] = new Array(2);
        }; 
      }
     
      function drawHexagon( x, y, unit ){
     
        var sin_unit = unit * Math.sin(Math.PI/6); 
        var cos_unit = unit * Math.cos(Math.PI/6);
     
        context.strokeStyle = 'rgba(150,150,150,1)';//+ (0.8 - nbDrawn/nbTot )+')';
        context.shadowBlur = 10;
        context.shadowColor = 'rgba(150, 150, 150, 0.2 )';
        context.lineWidth = 2;
        context.beginPath();
        context.moveTo(x                  , y);
        context.lineTo(x + unit           , y);
        context.lineTo(x + unit + sin_unit, y + cos_unit);
        context.lineTo(x + unit           , y + 2 * cos_unit);
        context.lineTo(x                  , y + 2 * cos_unit);
        context.lineTo(x - sin_unit       , y + cos_unit);
        context.lineTo(x                  , y);
        context.stroke();
        context.fillStyle = 'rgba(0,0,0,0.5)';//+ (0.4 - nbDrawn/nbTot )+')';
        context.fill();
     
     
      }
     
      function drawBrother( x, y, unit ){
     
        //Don't draw what we can't see.
        //Maybe useless. Just to be sure it stops process out of canvas boundaries.
        if ( x < 0 || y < 0 || x > canvas.width || y > canvas.height ) return;
     
        drawHexagon(x,y,unit);
        posTable[nbDrawn][0] = Math.floor(x);
        posTable[nbDrawn][1] = Math.floor(y);
        ++nbDrawn;
     
        setTimeout(function() {
     
          drawSomeBrothers(x, y, unit );
        }, 30);
      }
     
      function checkExist(x, y){
        for ( var i = 0; i < nbDrawn; ++i){
          //Strict position equality not match very well
          if ( ( Math.abs(posTable[i][0] - Math.floor(x)) < 10) 
            && ( Math.abs(posTable[i][1] - Math.floor(y)) < 10) ) {
            return true;
          }
        }
        return false;
      }
     
      function drawSomeBrothers(x, y, unit){
     
        if (nbDrawn < nbTot -1){
          /*At least 2 (direct) brothers per hexagon. More compact. More beautiful.*/
          for (var i = 0; i < 2; ++i ){
            var nextCoo = chooseRandomBrotherToDraw(x,y,unit);
            if (nextCoo[0] || nextCoo[1])
              drawBrother(nextCoo[0], nextCoo[1], unit);
          }
        }
        return;
      }
     
      function shuffle(o){
        for(var j, x, i = o.length; i; j = Math.floor(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
        return o;
      }
     
      function chooseRandomBrotherToDraw(x,y,unit){
     
        var randomIds = [1,2,3,4,5,6];
        randomIds = shuffle(randomIds);
     
        var sin_unit = unit * Math.sin(Math.PI/6); 
        var cos_unit = unit * Math.cos(Math.PI/6);
     
        var newX = x;
        var newY = y;
     
     
        for ( var i = 0; 
              i < 6 && checkExist(newX, newY); 
              ++i) 
        {
          switch(randomIds[i]){
          case 1: //top left
            newX = x - sin_unit - unit;
            newY = y - cos_unit ;
            break;
          case 2: //top
            newX = x;
            newY = y - 2 * cos_unit;
            break;
          case 3: //top right
            newX = x + sin_unit + unit ;
            newY =  y - cos_unit ;
            break;
          case 4: //bottom right
            newX = x + sin_unit + unit ;
            newY = y + cos_unit ;
            break;
          case 5://bottom
            newX = x;
            newY = y + 2*cos_unit;
            break;
          case 6://bottom left
            newX = x - sin_unit - unit;
            newY = y + cos_unit;
            break;
          default:
            newX = 0;
            newY = 0;
            return;
          }
        };
     
        nextPositionToDraw = new Array(2);
        nextPositionToDraw[0] = newX;
        nextPositionToDraw[1] = newY;
     
        return nextPositionToDraw;
     
      }
     
      function printPos(x,y){
        console.log(Math.floor(x)+","+Math.floor(y)+" n'est pas dans :");
        for(var i = 0; i < nbDrawn; ++i){
          console.log(posTable[i][0]+","+posTable[i][1]);
        }
      }
     
      function main(){
        var nbMin = 50;
        var nbMax = 200;
        nbTot = nbMin + (nbMax - nbMin) * Math.random();
        nbTot = 100//Math.round(nbTot);
        initPosTable(nbTot);
     
        var xFirst = Math.random() * canvas.width;
        var yFirst = Math.random() * canvas.height;    
        var unit = 20 + 40 * Math.random();
     
        nbDrawn = 0;
        drawBrother(xFirst, yFirst, unit);
      }
     
      document.getElementById("trigger").addEventListener( 'mouseover', function(){
        context.clearRect(0, 0, canvas.width, canvas.height);
        main();
      });
    });
    Un premier hexagone est dessiné, puis je calcule les coordonnées de 2 voisins que je dessine s'ils n'existent pas (et c'est là le problème, ma vérification ne marche pas comme elle devrait), et ainsi de suite jusqu'à ce qu'il y en ait assez. Je pense que le problème peut se situer au moment de l'incrémentation de nbDrawn, comme 2 écritures dans la même case du tableau posTable.

    Merci de m'avoir lu,
    Coridalement

  2. #2
    Rédacteur/Modérateur

    Avatar de SylvainPV
    Profil pro
    Inscrit en
    Novembre 2012
    Messages
    3 375
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2012
    Messages : 3 375
    Points : 9 944
    Points
    9 944
    Par défaut
    J'ai bricolé autour de ton code pendant un quart d'heure sans trouver d'où pouvait venir le bogue. Le point délicat c'est cette approximation sur les coordonnées de chaque hexagone. Ce n'est pas très rigoureux et source potentielle de bogues.

    Ce que je peux te suggérer, c'est de considérer que ta grille hexagonale est en fait un tableau en deux dimensions dont une ligne sur deux est décalée d'un demi-cran vers la droite. De la sorte, les coordonnées se résument à un couple d'entier (x,y) et la fonction de dessin se charge de les transformer en coordonnées réelles avec les calculs d'angle. Le code et son débogage en devrait être nettement facilités.

    C'est l'approche que j'avais choisi pour un de mes essais : http://syllab.fr/projets/games/warchess/

  3. #3
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2014
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Février 2014
    Messages : 3
    Points : 3
    Points
    3
    Par défaut
    Merci de vous être penché sur mon soucis .
    Oui en effet la solution du tableau de coordonnées n'est pas très rigoureuse, mais ça devrait marcher même sans l'approximation en théorie. J'ai ajouté l'approximation suite au constat que ça ne marchait pas en enregistrant les coordonnées exactes (int). Mais même prenant cette marge de sécurité (une approximation de 10x10 pixel sur l'emplacement de l'origine) il y a superposition (semble-t'il exacte). Je pense donc que le problème n'est pas là, d'ou mon interrogation quand à l'ordre d'exécution.

    Votre suggestion de placer les hexagones dans un tableau est judicieuse mais "l'objectif" du script est de choisir une position aléatoire est de générer les voisins aléatoirement pour créer un pattern aléatoire... La taille aussi est aléatoire... Il est bien sur possible de calculer une grille suite à l'établissement de ces paramètres mais le script passerait de récursif à itératif. Je vais surement réussir à obtenir un résultat sans superposition avec votre solution, mais je n'aurai pas comrpris ce qui ne vas pas avec la mienne .

    Merci !

  4. #4
    Expert éminent
    Avatar de Watilin
    Homme Profil pro
    En recherche d'emploi
    Inscrit en
    Juin 2010
    Messages
    3 094
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : En recherche d'emploi

    Informations forums :
    Inscription : Juin 2010
    Messages : 3 094
    Points : 6 755
    Points
    6 755
    Par défaut
    Hover me !
    Come together
    Right nooow…




    Edit: Bon soyons sérieux. J'ai concentré mon attention sur cette boucle :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    for ( var i = 0; 
              i < 6 && checkExist(newX, newY); 
              ++i) 
        {
          switch(randomIds[i]){
          case 1: //top left
            newX = x - sin_unit - unit;
            newY = y - cos_unit ;
            break;
          case 2: //top
            newX = x;
            newY = y - 2 * cos_unit;
            break;
          case 3: //top right
            newX = x + sin_unit + unit ;
            newY =  y - cos_unit ;
            break;
          case 4: //bottom right
            newX = x + sin_unit + unit ;
            newY = y + cos_unit ;
            break;
          case 5://bottom
            newX = x;
            newY = y + 2*cos_unit;
            break;
          case 6://bottom left
            newX = x - sin_unit - unit;
            newY = y + cos_unit;
            break;
          default:
            newX = 0;
            newY = 0;
            return;
          }
        };
    Et je me suis posé la question : que se passe-t-il quand les six voisins existent déjà ? À la fin de la boucle (quand i == 6) on a des valeurs newX et newY qui ne sont pas contrôlées. Corrige ça, et je pense que ton problème sera résolu

    Edit2: Un dernier conseil car tu as quelques variables non déclarées : utilise le mode strict et tu les verras tout de suite. Pour passer en mode strict, ajoute simplement la chaîne "use strict"; au début de ton code.

  5. #5
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2014
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Février 2014
    Messages : 3
    Points : 3
    Points
    3
    Par défaut
    Ooooh oui !!! C'etait en effet cette grossière erreur de programmation à l'origine du problème. Je suis navré . Moi qui avait peur de ne pas pouvoir utiliser la récursivité comme ceci à cause de l'aspect non-bloquant de javascript ! N'importe quoi, ça marche super bien. J'ai corrigé le script qui tourne maintenant comme je l'ai toujours voulu. Merci pour votre aide.

    Je poste ci dessous le script corrigé, ainsi qu'un nouveau lien le mettant en scène (j'ai ajouté un numérotage pour le fun héhé).
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    document.addEventListener('DOMContentLoaded', function(){
     
      var canvas = document.getElementById('bgCanvas');
      var context = canvas.getContext('2d');
      var posTable;
     
      var nbTot = 100;
      var nbDrawn = 0;
     
      canvas.width = document.body.clientWidth;
      canvas.height = Math.max( window.innerHeight, document.body.clientHeight );
     
      function initPosTable( nbTot ){
        posTable = new Array(nbTot);
        for (var i = nbTot - 1; i >= 0; i--) {
          posTable[i] = new Array(2);
        }; 
      }
     
      function drawHexagon( x, y, unit ){
     
        var sin_unit = unit * Math.sin(Math.PI/6); 
        var cos_unit = unit * Math.cos(Math.PI/6);
     
        context.strokeStyle = 'rgba(150,150,150,'+ (0.8 - nbDrawn/nbTot )+')';
        context.shadowBlur = 10;
        context.shadowColor = 'rgba(150, 150, 150, 0.2 )';
        context.lineWidth = 2;
        context.beginPath();
        context.moveTo(x                  , y);
        context.lineTo(x + unit           , y);
        context.lineTo(x + unit + sin_unit, y + cos_unit);
        context.lineTo(x + unit           , y + 2 * cos_unit);
        context.lineTo(x                  , y + 2 * cos_unit);
        context.lineTo(x - sin_unit       , y + cos_unit);
        context.lineTo(x                  , y);
        context.stroke();
        context.fillStyle = 'rgba(200,0,0,'+(1 - nbDrawn/(nbTot*1.2) )+')';
        context.fill();
     
        context.font = "12pt Calibri,Geneva,Arial";
        context.fillStyle = 'rgba(0,20,20,1)';
        context.fillText(""+nbDrawn, x+15, y+30);
     
     
      }
     
      function drawBrother( x, y, unit ){
     
        //Don't draw what we can't see.
        //Maybe useless. Just to be sure it stops process out of canvas boundaries.
        if ( x < 0 || y < 0 || x > canvas.width || y > canvas.height ) return;
     
        drawHexagon(x,y,unit);
     
     
        posTable[nbDrawn][0] = Math.floor(x);
        posTable[nbDrawn][1] = Math.floor(y);
        ++nbDrawn;
     
        setTimeout(function() {
          drawSomeBrothers(x, y, unit );
        }, 30);
      }
     
      function checkExist(x, y){
     
        for ( var i = 0; i < posTable.length; ++i){
          //Strict position equality not match very well
          if ( ( Math.abs(posTable[i][0] == Math.floor(x))) 
            && ( Math.abs(posTable[i][1] == Math.floor(y))) ) {
            return true;
          }
        }
        return false;
      }
     
      function checkVisible(x, y){
        return !( x < 0 || y < 0 || x > canvas.width || y > canvas.height );
      }
     
      function drawSomeBrothers(x, y, unit){
     
        if (nbDrawn >= nbTot-1 ) return;
     
          /*At least 2 (direct) brothers per hexagon. More compact. More beautiful.*/
        for (var i = 0; i < 2; ++i ){
     
          var nextCoo = chooseRandomBrotherToDraw(x,y,unit);
          if (nextCoo[0] || nextCoo[1])
            drawBrother(nextCoo[0], nextCoo[1], unit);
     
        }
        return;
      }
     
      function shuffle(o){
        for(var j, x, i = o.length; i; j = Math.floor(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
        return o;
      }
     
      function chooseRandomBrotherToDraw(x,y,unit){
     
        var randomIds = [1,2,3,4,5,6];
        randomIds = shuffle(randomIds);
     
        var sin_unit = unit * Math.sin(Math.PI/6); 
        var cos_unit = unit * Math.cos(Math.PI/6);
     
        var newX = x;
        var newY = y;
     
     
        for ( var i = 0; 
              i < 6 && checkExist(newX, newY); 
              ++i) 
        {
          switch(randomIds[i]){
          case 1: //top left
            newX = x - sin_unit - unit;
            newY = y - cos_unit ;
            break;
          case 2: //top
            newX = x;
            newY = y - 2 * cos_unit;
            break;
          case 3: //top right
            newX = x + sin_unit + unit ;
            newY =  y - cos_unit ;
            break;
          case 4: //bottom right
            newX = x + sin_unit + unit ;
            newY = y + cos_unit ;
            break;
          case 5://bottom
            newX = x;
            newY = y + 2*cos_unit;
            break;
          case 6://bottom left
            newX = x - sin_unit - unit;
            newY = y + cos_unit;
            break;
          default:
            newX = 0;
            newY = 0;
            break;
          }
     
          if (!checkVisible(newX, newY)) {newX = x; newY = y;}
        };
     
        if (checkExist(newX, newY)) {newX = 0; newY = 0;}
     
        var nextPositionToDraw = new Array(2);
        nextPositionToDraw[0] = newX;
        nextPositionToDraw[1] = newY;
     
        return nextPositionToDraw;
     
      }
     
      function printPos(){
        for(var i = 0; i < posTable.length; ++i){
          console.log(posTable[i]);
        }
      }
     
      function main(){
        initPosTable(nbTot);
        nbDrawn = 0;
     
        var xFirst = Math.random() * canvas.width;
        var yFirst = Math.random() * canvas.height;    
        var unit = 40;
     
        drawBrother(xFirst, yFirst, unit);
      }
     
      document.getElementById("trigger").addEventListener( 'mouseover', function(){
        context.clearRect(0, 0, canvas.width, canvas.height);
        main();
      });
    });
    Et le lien de démo : http://codepen.io/anon/pen/Adsox

    EDIT : Les différentes nuances de rouge ne sont cette fois-ci pas dues à une superposition mais à un dégradé volontaire montrant la progression du pattern (au même titre que la numérotation...).

    Pour ce qui est de la déclaration des variables, est-ce vraiment un problème ? Je ne vois pas d'erreur dans les logs d'exécution du script. J'ai justement essayé de tirer profit de ce que je crois savoir : si je ne mets pas le mot clé var en déclarant une variable alors celle-ci pourra être visible dans les blocs parents. Il vaut mieux éviter ce type de variable à grande portée c'est ça ?
    Toujours est-il que j'ai modifié le script pour qu'il s'exécute même avec la ligne "use strict" ; merci du conseil.

    Je passe en résolu ; ce n'était pas un problème d'ordre d'exécution.

  6. #6
    Expert éminent
    Avatar de Watilin
    Homme Profil pro
    En recherche d'emploi
    Inscrit en
    Juin 2010
    Messages
    3 094
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : En recherche d'emploi

    Informations forums :
    Inscription : Juin 2010
    Messages : 3 094
    Points : 6 755
    Points
    6 755
    Par défaut
    Les numéros ça aurait pû t'aider si tu les avais mis plus tôt

    Le problème des variables sans var, pour moi c'est surtout un problème de maintenance. En mettant var, même au niveau global, tu expliques au lecteur du code (potentiellement toi dans le futur, après plusieurs semaines sans toucher au projet) que ce n'est pas un oubli, que c'est ben ça que tu as voulu faire.

    Sinon tu as raison, les variables à grande portée, il vaut mieux éviter car si ton script est inclus dans une page avec d'autres scripts qui déclarent aussi des globales, il peut y a voir conflit de nom. Il y a aussi une question de performance (même si personnellement, je pense que c'est négligeable) : depuis une fonction, aller chercher une variable « loin » dans le scope demandera plus d'efforts. C'est une histoire de lookup : l'interpréteur regarde d'abord dans le scope courant, puis dans le scope parent, et ainsi de suite jusqu'au niveau global.

    C'est bien comme tu as fait : au niveau de la fonction du "DOMContentLoaded", c'est le niveau le plus général, sans être global. Au passage, note que ça repose sur le principe des closures.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [JSTL] taglibs imbriqués : ordre d'exécution
    Par cedricmenou dans le forum Taglibs
    Réponses: 6
    Dernier message: 27/04/2007, 15h20
  2. [URL Rewriting] ordre d'exécution des règles
    Par safisafi dans le forum Apache
    Réponses: 1
    Dernier message: 21/11/2006, 18h52
  3. ordre d'exécution des événements onblur et onfocus
    Par letycaf dans le forum Général JavaScript
    Réponses: 5
    Dernier message: 23/05/2006, 15h30
  4. Ordre d'exécution de la requête
    Par raf_gug dans le forum Requêtes
    Réponses: 4
    Dernier message: 19/04/2006, 10h30
  5. Ordre d'exécution dans une jointure externe
    Par Pero dans le forum Langage SQL
    Réponses: 17
    Dernier message: 20/09/2005, 12h22

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo