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

Langage Delphi Discussion :

variable et absolute sur Sydney


Sujet :

Langage Delphi

  1. #1
    Membre expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2007
    Messages
    3 502
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 63
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2007
    Messages : 3 502
    Points : 3 133
    Points
    3 133
    Par défaut variable et absolute sur Sydney
    Bonjour

    Je dois lire un fichier genre format EDI avec des valeurs sur longueurs fixes.
    La façon la plus basique qui soit consiste à faire de multiples copy(chaine, P1, P2) pour récupérer chaque valeur dans un membre d'un record.

    Et j'ai pensé à faire le travail en une seule fois avec absolute.
    Problème, si je fais :

    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
     
    type
      TSr = record
        P1: string[7];
        P2: string [10];
      end;
     
    procedure TForm3.Button3Click(Sender: TObject);
    var
      S: string;
      Sr: TSr absolute S;
    begin
      S := '11111113333333333';
      ShowMessage(Sr.P2);
    end;
    Je m'attend à récupérer tous les 3.
    Bien sûr, si ça fonctionnait, je ne serais pas là à demander où est mon erreur

    Elle est où l'astuce pour faire ça ?
    Ou plutôt, est-ce possible ?

    Précision: Si je définis S en string[17], il y a du mieux mais je récupère

    333333333Àô

  2. #2
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 457
    Points
    28 457
    Par défaut
    string[x] est une ShortString, donc un tableau de X + 1 octets
    string est une UnicodeString, donc un pointeur managé alloué automatiquement selon les besoins

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    type
      TSr = record
        P1: string[7];
        P2: string [10];
      end;
    c'est l'équivalent de

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    type
      TStr = record
       P1_Len: Byte;
       P1_Chars: array[1..7] of AnsiChar;
       P2_Len: Byte;
       P2_Chars: array[1..10] of AnsiChar;
     end;
    tu peux donc difficilement le mapper en string (short ou pas)

  3. #3
    Modérateur
    Avatar de tourlourou
    Homme Profil pro
    Biologiste ; Progr(amateur)
    Inscrit en
    Mars 2005
    Messages
    3 885
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Biologiste ; Progr(amateur)

    Informations forums :
    Inscription : Mars 2005
    Messages : 3 885
    Points : 11 403
    Points
    11 403
    Billets dans le blog
    6
    Par défaut
    Bonjour,
    Problème d'alignement ? Utiliser Packed Record ?

  4. #4
    Membre expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2007
    Messages
    3 502
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 63
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2007
    Messages : 3 502
    Points : 3 133
    Points
    3 133
    Par défaut
    J'ai testé le packed record mais ça ne change rien.

    Merci Paul pour le détail.
    Je pense que je vais rester sur les copy(...) successifs, ça sera plus simple

  5. #5
    Membre éprouvé
    Avatar de Cirec
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    467
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 467
    Points : 1 073
    Points
    1 073
    Par défaut
    Bonjour,

    peut être comme ceci ?:
    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
    type
      TSr2 = record
        p: Byte;
        P1: array[1..7] of AnsiChar;
        P2: array[1..10] of AnsiChar;
        end;
     
    procedure TForm29.Button2Click(Sender: TObject);
    var
      S: string[17];
      Sr: TSr2 absolute S;
    begin
      S := '11111113333333333';
      ShowMessage(Sr.P2);
    end;
    Cordialement,

    @+

  6. #6
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 457
    Points
    28 457
    Par défaut
    Citation Envoyé par Cirec Voir le message
    Bonjour,

    peut être comme ceci ?:
    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
    type
      TSr2 = record
        p: Byte;
        P1: array[1..7] of AnsiChar;
        P2: array[1..10] of AnsiChar;
        end;
     
    procedure TForm29.Button2Click(Sender: TObject);
    var
      S: string[17];
      Sr: TSr2 absolute S;
    begin
      S := '11111113333333333';
      ShowMessage(Sr.P2);
    end;
    Cordialement,

    @+
    oui mais P2 n'est plus un string[10] c'est un array of char

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    procedure TForm29.Button2Click(Sender: TObject);
    var
      S: string[17];
      Sr: TSr2 absolute S;
    begin
      S := '123';
      ShowMessage(Sr.P2); // ???
    end;

  7. #7
    Membre éprouvé
    Avatar de Cirec
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    467
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 467
    Points : 1 073
    Points
    1 073
    Par défaut
    @Paul TOTH,

    oui mais comme Papy214 l'a précisé dans sa demande
    Citation Envoyé par Papy214 Voir le message
    Bonjour

    Je dois lire un fichier genre format EDI avec des valeurs sur longueurs fixes.
    La façon la plus basique qui soit consiste à faire de multiples copy(chaine, P1, P2) pour récupérer chaque valeur dans un membre d'un record.
    ...
    c'est un cas précis pour une chaine de longueur fixe
    il est supposé lire le fichier par bloc de 17 caractères donc
    ça ne devrait pas poser de problème ici.

    [EDIT]
    si on veut conserver le coté string[10] on pourrait aussi faire ceci (c'est du vite fait) :
    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
    type
      TSr = record
        P1: string[7];
        P2: string[10];
      public
        class operator Implicit(a: string): Tsr;
        class operator Implicit(a: Tsr): string;
      end;
     
    class operator TSr.Implicit(a: string): Tsr;
    begin
      Result.P1 := copy(a, 1, 7);
      Result.P2 := copy(a, 8, 10);
    end;
     
    class operator TSr.Implicit(a: Tsr): string;
    begin
      Result := a.P1+a.P2;
    end;
     
    procedure TForm29.Button1Click(Sender: TObject);
    var
      S: string;
      Sr: TSr {absolute S};
    begin
      S := '11111113333333333';
      Sr := S;
      ShowMessage(Sr.P2);
    end;
    Cordialement,

    @+

  8. #8
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 710
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 710
    Points : 25 593
    Points
    25 593
    Par défaut
    Absolute n'est pas la bonne piste, certes on pourrait le penser mais il y a tout simplement plus simple avec le TStream

    une fichier ANSI contenant
    Code txt : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    11111113333333333
    22222224444444444
    777    55555

    Je pratique énormément cette méthode pour éviter justement les copies, dès que le fichier évolue, faut refaire tous les offsets, tout décalé, c'est pénible
    On doit pouvoir trouver des sujets où j'ai déjà écrit la même chose

    Evidemment certains blocs de code répétitifs peuvent être mis en commun, je fais généralement une classe utilitaire TxxxTypeConverter avec xxx correspond à une origine de fichier
    On peut aussi conserver plusieurs versions de packed record, ainsi on peut avoir la classe d'encapsulation qui gère les différentes versions de façon transparente

    Enfin, le code ci-dessous a été simplifié pour utiliser AnsiString mais l'on peut ajouter aussi du passage du Ansi à l'unicode


    Je n'ai pas poussé plus loin mais en général, je fais plusieurs classes TxxFile, qui contient des TxxFileItem qui gère la boucle des lignes, en plus, cela peut contenir des TxxFileHeader et TxxFileFooter

    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
    unit StreamRecord_MainForm;
     
    interface
     
    uses
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
      Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
     
    type
      TForm1 = class(TForm)
        Button1: TButton;
        Memo1: TMemo;
        procedure Button1Click(Sender: TObject);
      private
        { Déclarations privées }
      public
        { Déclarations publiques }
      end;
     
    var
      Form1: TForm1;
     
    implementation
     
    {$R *.dfm}
     
    type
      TSrData = packed record
        P1: array[1..7] of AnsiChar;
        P2: array[1..10] of AnsiChar;
        EOL: array[1..2] of AnsiChar;
      end;
     
     
      TSr = class(TObject)
      private
        FData: TSrData;
        function GetP1(): AnsiString;
        function GetP2(): AnsiString;
        procedure SetP1(const Value: AnsiString);
        procedure SetP2(const Value: AnsiString);
      public
        function LoadFromStream(AStream: TStream): Boolean;
        procedure SaveToStream(AStream: TStream);
     
        property P1: AnsiString read GetP1 write SetP1;
        property P2: AnsiString read GetP2 write SetP2;
      end;
     
    procedure TForm1.Button1Click(Sender: TObject);
    var
      SrW, SrR: TSr;
      FS: TFileStream;
    begin
      FS := TFileStream.Create('SR.txt', fmCreate);
      try
        SrW := TSr.Create();
        try
          SrW.P1 := '1111111';
          SrW.P2 := '3333333333';
          SrW.SaveToStream(FS);
          SrW.P1 := '2222222';
          SrW.P2 := '4444444444';
          SrW.SaveToStream(FS);
          SrW.P1 := '777';
          SrW.P2 := '55555';
          SrW.SaveToStream(FS);
        finally
          SrW.Free();
        end;
      finally
        FS.Free();
      end;
     
      FS := TFileStream.Create('SR.txt', fmOpenRead);
      try
        SrR := TSr.Create();
        try
          while SrR.LoadFromStream(FS) do
            Memo1.Lines.Add(Format('P1: %s, P2: %s', [SrW.P1, SrW.P2]))
        finally
          SrR.Free();
        end;
      finally
        FS.Free();
      end;
    end;
     
     
    { TSr }
     
    function TSr.GetP1(): AnsiString;
    begin
      Result := FData.P1; // Conversion implicité d'un Array of Char en AnsiString
    end;
     
    function TSr.GetP2(): AnsiString;
    begin
      Result := FData.P2; // Conversion implicité d'un Array of Char en AnsiString
    end;
     
    function TSr.LoadFromStream(AStream: TStream): Boolean;
    const
      Delimiter: array[0..1] of AnsiChar = #13#10; // On peut aussi utiliser sLineBreak
    var
      LineLen: Integer;
    begin
      LineLen := SizeOf(FData);
      Result := AStream.Position + LineLen <= AStream.Size;
      // Version détaillée
      (*
      if Result then
      begin
        if AStream.Read(FData.P1[1], Length(FData.P1)) <> Length(FData.P1) then
          Exit(False);
     
        if AStream.Read(FData.P2[1], Length(FData.P2)) <> Length(FData.P2) then
          Exit(False);
     
        if (AStream.Read(FData.EOL[1], Length(Delimiter)) <> Length(Delimiter)) and or CompareMem(@FData.EOL[1], @Delimiter[0], Length(Delimiter)) then
          Exit(False);
      end;
      *)
     
      // Version One Shot
      if Result then
        if (AStream.Read(FData, LineLen) <> LineLen) or not CompareMem(@FData.EOL[1], @Delimiter[0], Length(Delimiter)) then
          Exit(False);
    end;
     
    procedure TSr.SaveToStream(AStream: TStream);
    const
      Delimiter: array[0..1] of AnsiChar = #13#10; // On peut aussi utiliser sLineBreak
    begin
      // Version détaillée
      (*
      AStream.Write(FData.P1[1], Length(FData.P1));
      AStream.Write(FData.P2[1], Length(FData.P2));
      AStream.Write(Delimiter[0], Length(Delimiter));
      *)
     
      // Version One Shot
      CopyMemory(@FData.EOL[1], @Delimiter[0], Length(Delimiter));
      AStream.Write(FData, SizeOf(FData));
    end;
     
    procedure TSr.SetP1(const Value: AnsiString);
    var
      ValueLen, RawLen: Integer;
    begin
      ValueLen := Length(Value);
      RawLen := Length(FData.P1);
      // FillChar s'attend à un nombre d'octets !
      if RawLen > ValueLen then
        FillChar(FData.P1[ValueLen], RawLen - ValueLen + 1, ' ');
      // Copie de la valeur
      CopyMemory(@FData.P1[1], @Value[1], ValueLen);
    end;
     
    procedure TSr.SetP2(const Value: AnsiString);
    var
      ValueLen, RawLen: Integer;
    begin
      ValueLen := Length(Value);
      RawLen := Length(FData.P2);
      // FillChar s'attend à un nombre d'octets !
      if RawLen > ValueLen then
        FillChar(FData.P2[ValueLen], RawLen - ValueLen + 1, ' ');
      // Copie de la valeur
      CopyMemory(@FData.P2[1], @Value[1], ValueLen);
    end;
     
     
    end.

    Exemple de converter commun

    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
    //------------------------------------------------------------------------------
    class procedure TxxxTypeConverter.CopyStringIntoRaw(const Value: string; var Raw: array of AnsiChar);
    var
      PreRaw: AnsiString; 
      PreRawLen, RawLen: Integer;
    begin
      // Conversion forcée Unicode vers Ansi
      PreRaw := AnsiString(Value);
      PreRawLen := Length(PreRaw);
      RawLen := Length(Raw);
      // FillChar s'attend à un nombre d'octets !
      if RawLen > PreRawLen then
        FillChar(Raw[PreRawLen], RawLen - PreRawLen, SPARE_ALPHA);
      // Copie de la valeur
      CopyMemory(@Raw[0], @PreRaw[1], PreRawLen);
    end;
     
    //------------------------------------------------------------------------------
    class function TxxxTypeConverter.RawToString(const Raw: array of AnsiChar): string;
    begin
      Result := string(Copy(Raw, 1, Length(Raw)));
    end;

  9. #9
    Membre expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2007
    Messages
    3 502
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 63
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2007
    Messages : 3 502
    Points : 3 133
    Points
    3 133
    Par défaut

    TSr = record
    P1: string[7];
    P2: string[10];
    public
    class operator Implicit(a: string): Tsr;
    class operator Implicit(a: Tsr): string;
    end;
    Je n'avais pas oublié le sujet mais j'étais parti sur des choses urgentes.

    Je n'avais utilisé les "operator" qu'une fois d'une façon très simple mais jamais comme ça.
    Il faut que j'étudie ça qui me semble très intéressant.

    Merci Paul

  10. #10
    Membre expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2007
    Messages
    3 502
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 63
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2007
    Messages : 3 502
    Points : 3 133
    Points
    3 133
    Par défaut
    @ShaiLeTroll

    J'aime aussi beaucoup cette solution mais dans mon cas, j'ai peur quelle ne soit pas applicable. (Je la retiens toutefois pour un autre projet où elle sera là très utile)

    Pourquoi cette solution ne conviendra pas ?
    Les fichiers que je dois lire ne sont pas composés d'éléments identiques répétés plusieurs fois mais plutôt de pseudo XML.
    Des sections sont délimités par des balises, et chaque ligne de la section par contre est une ligne de valeurs sur longueurs fixes.
    Par exemple:
    <Lieu>
    numéro sur 9 caractères, rue sur 80 caractères, etc.
    numéro sur 9 caractères, rue sur 80 caractères, etc.
    numéro sur 9 caractères, rue sur 80 caractères, etc.
    </Lieu>

    Une autre section sera différente dans sa composition.

    Mon code lit chaque ligne de la section et fait le découpage avec des copy successifs.
    Et dans certaines sections, on peut avoir une trentaine de valeurs à récupérer.

    C'est pour ça que je cherchais un moyen simple pour transférer chaque valeur individuelle au bon endroit sans faire des copy en pagaille.

    Par contre, en écrivant tout ça, je me dis que pourrait être possible quand même puisque ce que tu décris fonctionne sur un système de stream.
    Je pourrais charger chaque section dans un TMemoryStream et utiliser ce que tu proposes.
    Cela demanderait autant de types que de sections mais ça doit être jouable.

    Je vais réfléchir à tout ça maintenant que j'ai un peu plus de temps.

    Merci en tous cas pour cet exemple très complet.

  11. #11
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 710
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 710
    Points : 25 593
    Points
    25 593
    Par défaut
    Citation Envoyé par Papy214 Voir le message
    Cela demanderait autant de types que de sections mais ça doit être jouable.
    .
    C'est ce que fait le Wrapper XML de Delphi, lorsqu'il scanne un XML pour générer un DOM spécifique, tu as autant de classe que de type de noeud

    J'ai eu aussi des fichiers avec des champs de taille variable, j'ai aussi fait autant de type que nécessaire pour stocker/parser les données, le code principal de lecteur devient assez simple et lisible
    Et effectivement recopier dans un Stream un bloc entre <Tag> et </Tag> serait possible

    D'ailleurs, même si j'aurais des difficultés à expliquer ma façon de procéder, je verrais bien une Registry qui recensent toutes les classes gérant un bloc Tag (voir même une hiérarchie si elle existe) et dans le code principal, tu ne codes rien en dur, lorsque tu rencontres <[Tag]>, tu vérifies si Tag est présent dans la Registry, si oui, tu cherches </[Tag]> et via un petit jeu de MetaClass, instanciation dynamique avec constructeur virtuelle, cela instancie la bonne Classe de TTag, la lecture de fichier peut être un vrai plaisir car il y a plein de Pattern POO à exploiter et des mécanismes du langage Pascal Delphi qui sont super chiadés.

    Comme ça, si un nouveau Tag apparait, tu n'as pas à modifier le code de lecture, juste une nouvelle classe qui s'ajoutent à la Registry (comme le RegisterClasses pour les DFM, je te laisse étudier ça, très inspirant pour nos propres codes)

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

Discussions similaires

  1. changer la valeur d'une variable en cliquant sur un lien
    Par nintendoplayer dans le forum Langage
    Réponses: 2
    Dernier message: 05/08/2007, 20h09
  2. Variable d'environnement sur un domaine
    Par matthieuw dans le forum Windows XP
    Réponses: 1
    Dernier message: 27/07/2007, 11h18
  3. [8i] Les variables Boolean, AutoNumber sur oracle
    Par aliwassem dans le forum SQL
    Réponses: 7
    Dernier message: 13/04/2007, 18h12
  4. Réponses: 2
    Dernier message: 15/11/2006, 11h42
  5. Réponses: 6
    Dernier message: 08/11/2005, 16h30

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