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 :

Utiliser une variable comme un fichier [Python 3.X]


Sujet :

Python

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    19
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2008
    Messages : 19
    Points : 15
    Points
    15
    Par défaut Utiliser une variable comme un fichier
    Bonjour à tous

    Actuellement débutant sur Python, je suis face à un problème dont je ne trouve pas de solution.

    Environnement de travail :
    1)Version de python : 3.7
    2)Base de données : BigQuery
    3)Lieu de stockage de fichier: Google Cloud Storage

    Contraintes techniques :
    Le programme en python est une Cloud Function sur la plateforme Google.
    Il est donc limité au contrainte d'une Cloud Function :
    1) Temps de traitement maximum 9 minutes
    2) Mémoire maximum 2 Go
    3) Mémoire physique 5 Go pour toutes les Cloud Function

    Objectif :
    Le but est de générer 1 fichier structuré quotidiennement.
    1)Les données sources sont dans la base de données BigQuery.
    2)Le programme Python récupère les données source et génère un fichier dans Google Cloud Storage.
    3)La structure du fichier contient un modèle défini ci-dessous :
    COMMANDE(10 caractères, position 1) Numero commande(10 caractères, position 11)
    PRODUIT(10 caractères, position 1) Libellé produit(18 caractères, position 11)

    Exemple de contenu d'un fichier
    COMMANDE**NUMCMD0001
    PRODUIT***AGENDA************
    PRODUIT***GOMME*************
    COMMANDE**NUMCMD0002
    PRODUIT***STYLO*************
    PRODUIT***CAHIER***********
    PRODUIT***CLASSEUR**********
    Actuellement j'arrive à afficher la structure du fichier dans mon terminal en faisant un PRINT pour chaque ligne.
    Je pense également pouvoir créer un fichier et y insérer le contenu en mode "APPEND" dans mon environnement local.
    Pour répondre à mon besoin je pourrais donc créer ce fichier en local et le transférer sur Google Cloud Storage.
    Néanmoins, à cause de la contrainte technique numéro 3, je souhaiterai écrire le fichier directement dans Google Cloud Storage.
    Surtout que pour la 1ère exécution j'ai une phase d'initialisation qui risque de générer une taille importante du fichier.

    Ci-dessous un extrait du programme qui créer un fichier dans Google Cloud Storage avec comme contenu 'coucou toto'.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    def upload_blob(Repertoire_depot, contenu_fichier, libelle_fichier):
        storage_client = storage.Client()
        bucket = storage_client.get_bucket(Repertoire_depot)
        blob = bucket.blob(libelle_fichier)
        blob.upload_from_string(contenu_fichier)
     
    upload_blob('Dossier_test', 'coucou toto' , 'Fichier_01')
    En regardant la documentation de l'API, il ne m'est impossible d'ouvrir le fichier et d'y insérer mes différentes lignes en append.
    L'url de la documentation : https://googleapis.dev/python/storage/latest/blobs.html

    Je souhaite donc insérer le contenu de mon fichier avec sa structure dans une variable var_donnee et ensuite utiliser cette variable pour créer le fichier dans la cible comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    upload_blob('Dossier_test', var_donnee , 'Fichier_01')
    Et c'est là que j'ai besoin de votre aide :
    1) Est-ce que je suis complètement à côté de la plaque, et il faut que je résonne autrement que par cette procédé ?
    2) Est-ce qu'il y a une limite maximale sur le contenu d'une variable ?
    3) Comment puis je affecter plusieurs valeurs dans une même variable sans écraser la valeur déjà insérée ?
    Pour ligne_commande dans commande
    (a)var_donnee = donnee_commande,
    Pour ligne_produit dans produit
    (b)var_donnee = donnee_produit,

    (b)L'affectation de la variable à cette ligne va écraser l'affectation à la variable (a)
    (b)Si il y a plusieurs ligne de produit, la variable var_donnee ne va récupérer que la ligne du dernier produit

    Cette variable serait en fait comme un fichier :
    Ouverture => insertion de plusieurs lignes à des temps différents => Fermeture

    Je ne sais pas si je suis assez claires dans mes explications.

    Je vous remercie par avance pour ceux ou celles qui pourraient m'aiguiller.

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 351
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 351
    Points : 36 875
    Points
    36 875
    Par défaut
    Salut,

    Citation Envoyé par bibi_obs Voir le message
    Actuellement débutant sur Python, je suis face à un problème dont je ne trouve pas de solution.
    variables et chaines de caractères sont des objets de base du langage et les réponses aux questions que vous posez sont dans tous les tutos.

    - W

  3. #3
    Membre émérite

    Homme Profil pro
    Ingénieur calcul scientifique
    Inscrit en
    Mars 2013
    Messages
    1 229
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur calcul scientifique

    Informations forums :
    Inscription : Mars 2013
    Messages : 1 229
    Points : 2 328
    Points
    2 328
    Par défaut
    Ils vous faut un conteneur. Au lieu d'écrire à chaque fois :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    var_donnee = donnee_commande
    et de se dire, mince j'ai perdu les var_donnee d'avant, et bien faites qqch comme ca :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    list_var_donnee = []
    list_var_donnee.append(donnee_commande)
    Bizarre que vous soyez capable d'utiliser l'API Google (ce que je n'ai encore moi meme jamais fait), alors que vous ne sachiez pas manipuler des listes ...

  4. #4
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 721
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 721
    Points : 31 044
    Points
    31 044
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par bibi_obs Voir le message
    Je pense également pouvoir créer un fichier et y insérer le contenu en mode "APPEND" dans mon environnement local.
    Non. Ecrire dans un fichier se fait via la méthode (en admettant que le fichier a été ouvert dans la variable "fp") fp.write(truc_a_ecrire) ou bien par la fonction print(truc_a_ecrire, file=fp) si on a besoin d'écrire une ligne (le '\n' est implicite avec print).
    append() c'est pour les listes.

    Citation Envoyé par bibi_obs Voir le message
    Pour répondre à mon besoin je pourrais donc créer ce fichier en local et le transférer sur Google Cloud Storage.
    Pourquoi pas. Ca devrait effectivement être moins coûteux en temps réseau (un transfert unique ne faisant alors appel qu'une fois aux procédures de connexion réseau alors qu'une écriture à distance faisant alors autant d'appels que d'écritures effectives).

    Citation Envoyé par bibi_obs Voir le message
    Néanmoins, à cause de la contrainte technique numéro 3, je souhaiterai écrire le fichier directement dans Google Cloud Storage.
    La contrainte numéro 3 "Lieu de stockage de fichier: Google Cloud Storage" n'interdit nullement de travailler en local pendant la création. Une contrainte explicite l'état final attendu, non les états intermédiaires pour arriver à ce résultat.

    Citation Envoyé par bibi_obs Voir le message
    Surtout que pour la 1ère exécution j'ai une phase d'initialisation qui risque de générer une taille importante du fichier.
    Moui. Il faudrait préciser ce que tu entends par "importante". Mais quoi qu'il arrive, transférer n fois k octets ne sera pas plus économique que transférer une fois n*k octets.

    Citation Envoyé par bibi_obs Voir le message
    2) Est-ce qu'il y a une limite maximale sur le contenu d'une variable ?
    Non. Sous P3, un int est virtuellement infini et une string peut contenir plusieurs To. Ca ne dépend que de la puissance de ta machine.

    Citation Envoyé par bibi_obs Voir le message
    3) Comment puis je affecter plusieurs valeurs dans une même variable sans écraser la valeur déjà insérée ?
    Impossible. C'est un axiome dans tous les langages qu'écrire var=valeur2 écrase la valeur1 qui y étai précédemment. Et généralement ça convient à tout le monde car quand on écrit valeur2, c'est qu'on a fini de traiter valeur1. Sinon on passe par des tableaux (qui se subdivisent en listes, tuples, ensembles, dictionnaires sous Python) pour pouvoir conserver plusieurs valeurs en même temps (valeurs qui sont de même nature, ça va de soi, car si on doit gérer des valeurs disparates telles que "nom" et "age" on passe alors par des variables distinctes).

    Citation Envoyé par bibi_obs Voir le message
    Je ne sais pas si je suis assez claires dans mes explications.
    Pas tellement non. Et je ne comprends pas non plus pourquoi tu mets l'adjectif "clair" au pluriel (le féminin peut s'expliquer si tu es une fille) tandis que tu mets ton sujet+verbe au singulier.

  5. #5
    Membre à l'essai
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    19
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2008
    Messages : 19
    Points : 15
    Points
    15
    Par défaut
    Bonjour,

    Tout d'abord, merci à vous tous d'avoir pris le temps de me répondre et d'avoir remis en forme mon message initial.
    Je vais donner d'avantage de détails pour mieux expliquer mon point de blocage avec du vrai code, sera peut être plus compréhensible.


    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
     
    #Fonction qui retourne la valeur du champ en la tronquant ou en ajoutant des '*' pour arriver à la taille définie
    def longueur_data(data_in,longueur):
        longueur_data_in=len(data_in)
        if longueur > longueur_data_in:
            n_completion = longueur-longueur_data_in
            completion="*" * n_completion
            return data_in+completion
        else:
            return data_in[0:longueur]
     
    #Récupération des informations des commandes dans le dataframe df_commande
    df_commande = client.query('SELECT * FROM T_COMMANDE',location = Location).to_dataframe()
    #Récupération des informations des produits dans le dataframe df_produit
    df_produit = client.query('SELECT * FROM T_PRODUIT',location = Location).to_dataframe()
     
    list_contenu_fichier = []
    #Boucle principale pour récupérer chaque commande
    for row_commande in df_commande.itertuples(index=True, name='commande'):
        data_commande=longueur_data('COMMANDE',10) #valeur récupérée 'COMMANDE**'
        data_numcmd=longueur_data(getattr(row_commande,"NOCMD"),10) #valeur récupérée 'NUMCMD0001'
        print(data_commande+data_numcmd) # Affichage de ce qui correspond à la 1ère ligne du contenu du fichier : 'COMMANDE**NUMCMD0001'
        #Récupération de la ligne dans une variable
        contenu_fichier=data_CONTR+data_IDDISTRI
        list_contenu_fichier=data_CONTR+data_IDDISTRI    
     
        #Récupération des produits correspondant au 1er numéro de commande de la boucle principale
        df_produit_filt = df_produit.loc[df_produit['NOCMD']==getattr(row_commande,"NOCMD")]
        #Sous boucle pour récupérer chaque produit de chaque commande de la boucle principale
        for row_produit in df_produit_filt.itertuples(index=True, name='produit'):
            data_produit=longueur_data('PRODUIT',10) #valeur récupérée 'PRODUIT***'
            data_libproduit=longueur_data(getattr(row_produit,"libel_pdt"),18)
            print(data_produit+data_libproduit) 
                # Il y aura 2 itérations étant donné qu'il y a 2 produits correspondant à la 1ère commande
                # résultat du print (a chaque itération le print fait un retour chariot
                """
                PRODUIT***AGENDA************
                PRODUIT***GOMME*************
                """
            contenu_fichier=data_produit+data_libproduit #Si je fais cela, cela va écraser le contenu de la variable contenu_fichier de la boucle principale
            contenu_fichier_2=data_produit+data_libproduit #Si je déclare une autre variable, la 2e itération du 2e produit va écraser la valeur du 1er produit
            list_contenu_fichier.append(data_produit+data_libproduit)
                #avec une liste pour la 1ère commande j'aurai 3 éléments dans ma liste :
                #list_contenu_fichier[0:2] : ["COMMANDE**NUMCMD0001","PRODUIT***AGENDA************","PRODUIT***GOMME*************"]
    Dans mon terminal, le résultat des print me donne bien ce que je veux :
    COMMANDE**NUMCMD0001
    PRODUIT***AGENDA************
    PRODUIT***GOMME*************
    COMMANDE**NUMCMD0002
    PRODUIT***STYLO*************
    PRODUIT***CAHIER***********
    PRODUIT***CLASSEUR*******
    Pour créer le fichier en utilisant l'API, j'ai besoin de passer soit par une chaîne de caractères soit par une variable qui contient la chaîne de caractères.
    Je viens d'essayer de passer des liste, dictionnaire et dataframe, mais l'API ne les accepte pas.

    J'ai pensé à mettre une variable différente à chaque itération.
    Chaque variable aurait comme nom l'indice de la liste précédé de 'var_' par exemple pour la 1ère variable "var_0"
    Mais je n'arrive pas à concrétiser, j'ai également essayé avec eval() mais sans succès.

    J'ai essayé quelquechose comme cela :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    for element in list_content_file:    
        "var_"+list_content_file.index() = element
        #var_0 = COMMANDE**NUMCMD0001
        #var_1 = PRODUIT***AGENDA************
        ...
    Ensuite, avec une variable par ligne récupérée je les concatène tous pour les mettre dans une variable, du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    contenu_fichier=var_1+'\n'+var_2'\n'...
    Pour récupérer le nombre de var_x, je voulais faire une autre boucle du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    for i in range(list_content_file(-1])
        ...
    Je reviens au problème initial, si je fais une boucle pour déterminer les indices "i", la variable "contenu_fichier" sera écrasée à chaque itération

    J'essaye de trouver une solution, mais à chaque fois je boucle aussi sur mon problème initial.
    En plus avec cette chaleur, mes neurones sont déjà surchauffent.

    Si je n'arrive pas à résoudre ce problème, je le ferai en local avec un fichier et ensuite je ferai un transfert.
    Le fichier d'initialisation peut prendre 2 Go je pense.

  6. #6
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 721
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 721
    Points : 31 044
    Points
    31 044
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par bibi_obs Voir le message
    J'ai pensé à mettre une variable différente à chaque itération.
    Chaque variable aurait comme nom l'indice de la liste précédé de 'var_' par exemple pour la 1ère variable "var_0"
    Mais je n'arrive pas à concrétiser, j'ai également essayé avec eval() mais sans succès.
    Que c'est compliqué !!! Tu as justement les tableaux (listes/tuples) qui te permettent de faire cela de façon native. Au lieu d'écrire var_0="toto"; var_1="titi" tu écris var=("toto", "titi") puis ensuite tu peux taper à loisir dans var[0] ou var[1] ou même var[i] au choix (i valant 0 ou 1) sans passer par eval() qui n'a pas été faite pour ça. Plus des possibilités de traitements factorisés dans une simple itération.

    Citation Envoyé par bibi_obs Voir le message
    Pour créer le fichier en utilisant l'API, j'ai besoin de passer soit par une chaîne de caractères soit par une variable qui contient la chaîne de caractères.
    Je viens d'essayer de passer des liste, dictionnaire et dataframe, mais l'API ne les accepte pas.
    Ok, c'est donc de cette contrainte qu'il te faut partir. Donc si ton contenu se trouve dans un fichier, il te suffit de copier ce fichier dans une string avant de passer cette string à to API.
    Exemple
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    data=""
    with open(fichier, "r") as fp:
    	for lig in fp: data+=lig
    envoi_api(data)

    Si maintenant tu as le contenu dans une liste/tuple
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    data=(..., ..., ..., ...)      # Tout le contenu à envoyer à l'API
    envoi_api("".join(data))

    Et si les datas ne sont pas composées de strings mais de truc disparate (ex int/float), alors il faut les convertir en string lors du traitement
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    data=(123, 456, 789.05, 144.56)      # Tout le contenu à envoyer à l'API
    envoi_api("".join(str(x) for x in data))

    Bref en résumé il te faut manipuler l'entrée pour la convertir dans ce qui est attendu. Ce qui est en fait le principe général des algos de traitement

  7. #7
    Membre à l'essai
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    19
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2008
    Messages : 19
    Points : 15
    Points
    15
    Par défaut
    Merci beaucoup @Sve@r pour les différentes pistes que tu as ouvertes !
    Je vais les explorer, et je vous tiens au courant.

  8. #8
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 351
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 351
    Points : 36 875
    Points
    36 875
    Par défaut
    Salut,

    Citation Envoyé par Sve@r Voir le message
    Ok, c'est donc de cette contrainte qu'il te faut partir. Donc si ton contenu se trouve dans un fichier, il te suffit de copier ce fichier dans une string avant de passer cette string à to API.
    Exemple
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    data=""
    with open(fichier, "r") as fp:
    	for lig in fp: data+=lig
    envoi_api(data)
    envoi_api(open(fichier).read()) est quand même plus simple.

    Après si on veut jouer avec listes vs chaines de caractères:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    >>> s = '0\n1\n2\n3\n4'
    >>> s.split()
    ['0', '1', '2', '3', '4']
    >>> '*'.join(_)
    '0*1*2*3*4'
    >>>
    Ce qu'on s'attend à faire avec les chaines de caractères et les listes a été traduit sous la forme de méthodes.
    Ouvrir un tuto., lire la documentation, ... peut donner des idées d'utilisation pour réaliser un petit projet spécifique. Il suffit d'avoir pris le temps d'apprendre à jongler avec ces briques de bases.

    Et si on est pressé, écrire quelques lignes de code pour suivre son idée plutôt que de prendre le risque d'ouvrir la documentation et y vagabonder ne devrait pas être si difficile pourvu qu'on ait pris le temps d'apprendre.

    Sinon, on fait avec le pas grand chose qu'on maîtrise et on se retrouve devant des difficultés insurmontables.

    - W

  9. #9
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 721
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 721
    Points : 31 044
    Points
    31 044
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    envoi_api(open(fichier).read()) est quand même plus simple.
    Euh oui j'aurais dû y penser. Toutefois il manque la fermeture non ?

    Citation Envoyé par wiztricks Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    >>> '*'.join(_)
    '0*1*2*3*4'
    Un peu méchant comme exemple. Déjà il fait appel à la variable underscore qui n'est pas souvent expliquée dans les tutos (même le Swinnen n'en fait pas mention) ; et surtout ça ne fonctionne pas en mode script dans lequel la variable underscore ne se comporte pas comme en mode idle (elle ne récupère pas le résultat de l'instruction précédente)

  10. #10
    Membre à l'essai
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    19
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2008
    Messages : 19
    Points : 15
    Points
    15
    Par défaut
    Bonjour

    Mon problème est résolu grâce à vous.

    J'avais effectivement vu ce qu'on pouvait faire avec les méthodes sur les String durant mes recherches, mais j'étais un peu dispersé et je n'ai pas fait le lien avec la solution.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    #data étant ma liste de données
    envoi_api("".join(data))
    Merci beaucoup

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

Discussions similaires

  1. utiliser une variable comme paramètre de l'objet range
    Par stdebordeau dans le forum Macros et VBA Excel
    Réponses: 2
    Dernier message: 25/10/2007, 14h56
  2. javascript : utiliser une variable comme identificateurs
    Par cameleon93 dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 17/03/2007, 12h57
  3. [ProC][SQL] Utiliser une variable comme nom de curseur
    Par adiGuba dans le forum Interfaces de programmation
    Réponses: 1
    Dernier message: 06/12/2006, 11h55
  4. Utiliser une variable comme nom de fichier
    Par lo00_ dans le forum MATLAB
    Réponses: 1
    Dernier message: 28/06/2006, 13h57
  5. [curseurs] utiliser une variable comme nom de champ
    Par Christian31 dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 09/09/2005, 14h12

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