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

Python Discussion :

Initiation au calcul vectoriel avec NumPy


Sujet :

Python

  1. #1
    Rédacteur/Modérateur

    Avatar de User
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    8 615
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 8 615
    Billets dans le blog
    67
    Par défaut Initiation au calcul vectoriel avec NumPy
    Bonjour à tous,

    Je vous propose dans ce nouvel article de découvrir le calcul vectoriel à l’aide de la bibliothèque NumPy :



    Après avoir donné une rapide présentation des vecteurs et des opérations qui leur sont associées, nous allons montrer comment les définir avec NumPy et les représenter graphiquement à l'aide de Matplotlib.

    Ensuite, nous allons réaliser différentes opérations dans l'environnement Python, comme l'addition de deux vecteurs NumPy, la multiplication par un scalaire, ou encore la transformation d'un vecteur via une fonction mathématique.

    L'objectif est surtout de découvrir le calcul vectoriel avec NumPy à travers des exemples concrets : addition vectorielle, calcul du barycentre de trois points, détermination du centre de masse d'un demi-disque.
    Nom : vecteurs.png
Affichages : 9478
Taille : 3,1 Ko

    Bonne lecture à tous !
    Vous trouverez dans la FAQ, les sources ou les tutoriels, de l'information accessible au plus grand nombre, plein de bonnes choses à consulter sans modération

    Des tutoriels pour apprendre à créer des formulaires de planning dans vos applications Access :
    Gestion sur un planning des présences et des absences des employés
    Gestion des rendez-vous sur un calendrier mensuel


    Importer un fichier JSON dans une base de données Access :
    Import Fichier JSON

  2. #2
    Membre éprouvé
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    150
    Détails du profil
    Informations personnelles :
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 150
    Par défaut Merci beaucoup
    Merci beaucoup pour ce tutoriel !
    Pensez vous à l'étendre jusqu'à l’utilisation des calculs vectoriels dans le machine learning ?
    Au royaume des aveugles, les borgnes sont rois.

  3. #3
    Rédacteur/Modérateur

    Avatar de User
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    8 615
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 8 615
    Billets dans le blog
    67
    Par défaut
    Bonjour,

    Citation Envoyé par Mirmillon Voir le message
    Merci beaucoup pour ce tutoriel !
    Pensez vous à l'étendre jusqu'à l’utilisation des calculs vectoriels dans le machine learning ?
    Oui, c'est une idée que je retiens, merci à vous.
    Vous trouverez dans la FAQ, les sources ou les tutoriels, de l'information accessible au plus grand nombre, plein de bonnes choses à consulter sans modération

    Des tutoriels pour apprendre à créer des formulaires de planning dans vos applications Access :
    Gestion sur un planning des présences et des absences des employés
    Gestion des rendez-vous sur un calendrier mensuel


    Importer un fichier JSON dans une base de données Access :
    Import Fichier JSON

  4. #4
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 078
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 078
    Par défaut
    Hello,

    Désolé pour le temps de réponse, voici quelques suggestions et questionnement, je n'ai pas tout lu !

    Pour visualiser l'isobarycentre de trois points, dans le script global,

    1. Les deux lignes plt.plot(0, 0, "None") et plt.plot(7, 7, "None") servent à délimiter les axes. Ne serait-il pas plus explicite d'utiliser les fonctions dédiées plt.xlim() et plt.ylim() pour définir les limites des axes ?
    2. Je vois que plt.axis('scaled') et plt.axis('equal') sont appelés successivement. As-tu vérifié si l'appel à plt.axis('scaled') est réellement nécessaire ? D'après la documentation officielle de Matplotlib, l'option 'equal' est souvent suffisante pour garantir un repère orthonormé.
    3. Le triangle est tracé en trois appels distincts à plt.plot pour chaque segment (AB, BC, AC). Pourrait-on simplifier ce tracé en un seul appel ?
    Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
    La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

  5. #5
    Rédacteur/Modérateur

    Avatar de User
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    8 615
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 8 615
    Billets dans le blog
    67
    Par défaut
    Bonjour,

    Citation Envoyé par fred1599
    Pour visualiser l'isobarycentre de trois points, dans le script global,

    Les deux lignes plt.plot(0, 0, "None") et plt.plot(7, 7, "None") servent à délimiter les axes. Ne serait-il pas plus explicite d'utiliser les fonctions dédiées plt.xlim() et plt.ylim() pour définir les limites des axes ?
    Oui merci, j'avais repris cet méthode sur un site, mais j'utilise bien plt.xlim() et plt.ylim() dans d'autres exemples et en effet c'est plus explicite, comme quoi..

    Je vois que plt.axis('scaled') et plt.axis('equal') sont appelés successivement. As-tu vérifié si l'appel à plt.axis('scaled') est réellement nécessaire ? D'après la documentation officielle de Matplotlib, l'option 'equal' est souvent suffisante pour garantir un repère orthonormé.
    Oui c'est exact, c'est un oubli de ma part, d'ailleurs pour les autres exemples je n'ai pas mis d'appel à plt.axis('scaled').

    Le triangle est tracé en trois appels distincts à plt.plot pour chaque segment (AB, BC, AC). Pourrait-on simplifier ce tracé en un seul appel ?
    C'est un des avantages de pyplot.quiver() sur pyplot.arrow() que de pouvoir tracer plusieurs vecteurs en un seul appel, on est d'accord.

    J'ai fait ce choix pour le lecteur débutant : trouvant plus clair de faire trois appels avec un tracé de vecteur par appel, plutôt que de constituer des listes pour les origines (X,Y), pour les composantes (U,V), pour les couleurs, etc.

    En gros j'ai trouvé plus lisible :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    # Trace le vecteur OA
    plt.quiver(0, 0, OA[0], OA[1], color='b', angles='xy', scale_units = 'xy', scale = 1)
     
    # Trace le vecteur OB 
    plt.quiver(0, 0, OB[0], OB[1], color='g', angles='xy', scale_units = 'xy', scale = 1)
     
    # Trace le vecteur OC 
    plt.quiver(0, 0, OC[0], OC[1], color='orange', angles='xy', scale_units = 'xy', scale = 1)
    Que :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    plt.quiver([0, 0, 0], [0, 0, 0], [OA[0], OB[0], OC[0]], [OA[1], OB[1], OC[1]], color=['b','g','orange'], angles='xy', scale_units = 'xy', scale = 1)
    Même si un appel c'est plus concis et plus rapide comme tu le suggères.

    Encore merci
    Vous trouverez dans la FAQ, les sources ou les tutoriels, de l'information accessible au plus grand nombre, plein de bonnes choses à consulter sans modération

    Des tutoriels pour apprendre à créer des formulaires de planning dans vos applications Access :
    Gestion sur un planning des présences et des absences des employés
    Gestion des rendez-vous sur un calendrier mensuel


    Importer un fichier JSON dans une base de données Access :
    Import Fichier JSON

  6. #6
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 078
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 078
    Par défaut
    Hello,

    C'est tout de même un excellent travail, je pinaille

    L'idée est de regrouper les informations des points dans une structure de données et d'itérer dessus pour éviter la répétition du code print, scatter et annotate.

    Ne pourrait-on pas remplacer

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    plt.scatter(A[0], A[1], s=20, color = 'b')
    plt.annotate('A', xy=(A[0], A[1]))# Trace le point B en vert
    plt.scatter(B[0], B[1], s=20, color = 'g')
    plt.annotate('B', xy=(B[0], B[1]))# Trace le point C en orange
    plt.scatter(C[0], C[1], s=20, color = 'orange')
    plt.annotate('C', xy=(C[0], C[1]))
    print('Point A{0}'.format(A))
    print('Point B{0}'.format(B))
    print('Point C{0}'.format(C))
    par

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    # Stocke les informations des points et les affiche via une boucle
    points_info = {'A': (A, 'b'), 'B': (B, 'g'), 'C': (C, 'orange')}
     
     
    for name, (coords, color) in points_info.items():
        print('Point {0}{1}'.format(name, coords))
        plt.scatter(coords[0], coords[1], s=20, color=color)
        plt.annotate(name, xy=coords)
    Le code est plus court et plus facile à maintenir, qu'en penses-tu ?

    Pour la simplification du triangle je parlais de l'appel à plot, donc cette ligne

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    plt.plot(x1, y1, x2, y2, x3, y3, color="black")
    J'avais pensé à préférer remplacer ces lignes

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    # Trace le triangle ABC
    x1, y1 = [A[0], B[0]], [A[1], B[1]]
    x2, y2 = [B[0], C[0]], [B[1], C[1]]
    x3, y3 = [A[0], C[0]], [A[1], C[1]]
     
     
    plt.plot(x1, y1, x2, y2, x3, y3, color="black")
    par

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    # Trace le triangle ABC en reliant les sommets dans l'ordre (A -> B -> C -> A)
    triangle_coords_x = [A[0], B[0], C[0], A[0]]
    triangle_coords_y = [A[1], B[1], C[1], A[1]]
    plt.plot(triangle_coords_x, triangle_coords_y, color="black")
    Cette approche est plus idiomatique avec Matplotlib pour tracer des polygones et son intention est immédiatement compréhensible : tracer une forme fermée passant par les points A, B, et C.
    Qu'en penses-tu ?

    Et je suis d'accord avec toi sur le fait de privilégier la clarté et la décomposition des étapes, c'est une excellente approche pédagogique.
    Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
    La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

  7. #7
    Rédacteur/Modérateur

    Avatar de User
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    8 615
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 8 615
    Billets dans le blog
    67
    Par défaut
    Oui la logique Matplotlib : on passe les x et les y en arguments et après on génère les points à partir de leurs coordonnées et on les relie..

    Merci mais je pense que je vais laisser comme ça, tu m'as déjà bien aidé, même si c'est un peu répétitif c'est juste 3 points. Après libre à chacun de choisir
    Vous trouverez dans la FAQ, les sources ou les tutoriels, de l'information accessible au plus grand nombre, plein de bonnes choses à consulter sans modération

    Des tutoriels pour apprendre à créer des formulaires de planning dans vos applications Access :
    Gestion sur un planning des présences et des absences des employés
    Gestion des rendez-vous sur un calendrier mensuel


    Importer un fichier JSON dans une base de données Access :
    Import Fichier JSON

  8. #8
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 078
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 078
    Par défaut
    Hello,

    Ça marche ! Je lis au fur et à mesure... Je vois deux boucles imbriquées dans le code suivant

    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
     
    def generer_vecteurs(ox=0, oy=0, r=1, k=100):
        # ox, oy : coordonnées du centre du disque
        # r : rayon du disque
        # k : nombre de valeurs en x et en y
     
        # initialisation de la liste des vecteurs
        OA=[]
     
        # parcours des valeurs de ux entre -r et +r
        for ux in np.linspace(-r,r,k):
            # parcours des valeurs de uy entre -r et +r
            for uy in np.linspace(-r,r,k):
                # test si le point de coordonnées (ux,uy) est dans le cercle
                if ux*ux + uy*uy <= r*r:
                    # si oui, ajout du vecteur (ux+ox,uy+oy) à la liste
                    OA.append(np.array([ux+ox,uy+oy]))
     
        # renvoie la liste des vecteurs : OA[0], OA[1], ...
        return OA
    On est pas top, et niveau efficacité il y a sans doute mieux avec NumPy (que tu utilises dans tes autres codes).
    Pour une résolution de k=500, la différence de performance n'est plus théorique, elle devient très perceptible.
    Avec k=500, ta list comprehension effectue 500x500=250 000 itérations en Python. C'est précisément le cas de figure où l'approche vectorisée de NumPy montre toute sa puissance.

    Dis moi si je tape à côté...
    Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
    La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

  9. #9
    Rédacteur/Modérateur

    Avatar de User
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    8 615
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 8 615
    Billets dans le blog
    67
    Par défaut
    Salut,

    Dans un sens tu as raison, mais c'est moins intuitif pour un débutant. Là je construis une liste de couples (liste de points) petit-à-petit dans une double boucle. Comme je le mentionne, tu peux aussi utiliser la vectorisation avec numpy.meshgrid() (beaucoup plus rapide, mais moins intuitif).

    Voilà ce que ça donnerai (ce n'est pas de moi) :

    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
    import numpy as np
     
    def generer_vecteurs(ox=0, oy=0, r=1, k=100):
        # Génération de la grille
        ux = np.linspace(-r, r, k)
        uy = np.linspace(-r, r, k)
     
        # transforme deux vecteurs 1D (ux et uy) en deux grilles 2D
        X, Y = np.meshgrid(ux, uy, indexing="xy")
     
        # Test de l'appartenance au disque
        mask = X**2 + Y**2 <= r**2
     
        # Sélection des points valides et translation (ox, oy)
        Xv = X[mask] + ox
        Yv = Y[mask] + oy
     
        # Empilement sous forme de vecteurs [x,y]
        OA = np.stack([Xv, Yv], axis=1)
     
        return OA
    X contient toutes les coordonnées x répétées en colonnes.
    Y contient toutes les coordonnées y répétées en lignes.
    Vous trouverez dans la FAQ, les sources ou les tutoriels, de l'information accessible au plus grand nombre, plein de bonnes choses à consulter sans modération

    Des tutoriels pour apprendre à créer des formulaires de planning dans vos applications Access :
    Gestion sur un planning des présences et des absences des employés
    Gestion des rendez-vous sur un calendrier mensuel


    Importer un fichier JSON dans une base de données Access :
    Import Fichier JSON

  10. #10
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 078
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 078
    Par défaut
    Yes,

    C'est ce que j'attendais, du coup faut faire le test fonctionnel, comparer les performances, et voir si l'intérêt en vaut la peine comme je l'ai prédis dans mon précédent message.

    Citation Envoyé par User
    Dans un sens tu as raison, mais c'est moins intuitif pour un débutant.
    Bah tu peux pas l'utiliser dans ton tuto et me dire que dans ce cas de figure, NumPy est moins intuitif

    Dans ce cas soit on ne fait que pro NumPy, soit on le retire sur l'ensemble du tuto... Perso, débutant ou pas, sur ce genre de travail, on ne peut pas éviter NumPy, ils devront s'y mettre à un moment donné.

    EDIT : J'ajoute que les boucles avec NumPy sont une très mauvaise pratique, ce qui n'est pas ce qu'on veut dans un tuto digne de ce nom.
    Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
    La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

  11. #11
    Rédacteur/Modérateur

    Avatar de User
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    8 615
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 8 615
    Billets dans le blog
    67
    Par défaut
    Je comprends bien mais dans l'exemple en question la performance n'est pas très importante car on suppose que le disque est homogène, donc il suffit de prendre quelques points régulièrement espacés sur le disque pour ensuite vérifier que le centre de masse (évalué avec la formule barycentrique) coïncide bien visuellement avec le centre du disque, même chose pour le demi-disque. J'aurais peut-être dû en choisir moins je suis d'accord (et ça aurait été plus précis).

    Après il y a les différents codes et nos échanges en commentaires.

    Bon we
    Vous trouverez dans la FAQ, les sources ou les tutoriels, de l'information accessible au plus grand nombre, plein de bonnes choses à consulter sans modération

    Des tutoriels pour apprendre à créer des formulaires de planning dans vos applications Access :
    Gestion sur un planning des présences et des absences des employés
    Gestion des rendez-vous sur un calendrier mensuel


    Importer un fichier JSON dans une base de données Access :
    Import Fichier JSON

  12. #12
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 078
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 078
    Par défaut
    Citation Envoyé par User
    J'aurais peut-être dû en choisir moins je suis d'accord (et ça aurait été plus précis).
    Moins de points ?
    Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
    La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

  13. #13
    Rédacteur/Modérateur

    Avatar de User
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    8 615
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 8 615
    Billets dans le blog
    67
    Par défaut
    Je me suis peut-être mal exprimé.

    Si tu prends un disque homogène le centre de masse correspond au centre du disque qui est aussi le centre de symétrie.

    Dans le cas du disque homogène si chaque point M généré dans le disque a son symétrique M' par rapport à O, alors tu gardes la symétrie. Mais tu peux aussi la perdre, en fonction des valeurs données par np.linspace(-r,r,k), mais aussi en fonction du test sur les points avec if ux*ux + uy*uy <= r*r (dans le disque ou pas).

    Il peut aussi y avoir des erreurs dans les résultats des opérations portant sur des float notamment quand tu fais la somme ou la moyenne d'un grand nombre de valeurs.
    Vous trouverez dans la FAQ, les sources ou les tutoriels, de l'information accessible au plus grand nombre, plein de bonnes choses à consulter sans modération

    Des tutoriels pour apprendre à créer des formulaires de planning dans vos applications Access :
    Gestion sur un planning des présences et des absences des employés
    Gestion des rendez-vous sur un calendrier mensuel


    Importer un fichier JSON dans une base de données Access :
    Import Fichier JSON

Discussions similaires

  1. Réponses: 0
    Dernier message: 15/05/2025, 13h54
  2. [Python 3.X] Projet calcul matriciel avec NUMPY : Avis
    Par scrat51 dans le forum Calcul scientifique
    Réponses: 3
    Dernier message: 07/10/2022, 14h13
  3. Calcul vectoriel avec NASM
    Par Chevalier au taureau dans le forum x86 32-bits / 64-bits
    Réponses: 17
    Dernier message: 19/01/2015, 22h23
  4. Mélanger OO et calcul scientifique avec numpy ?
    Par mailaka dans le forum Calcul scientifique
    Réponses: 7
    Dernier message: 12/10/2012, 23h33

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