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

EDT/SwingWorker Java Discussion :

Enchainer plusieurs Threads "graphique"


Sujet :

EDT/SwingWorker Java

  1. #1
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    260
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2005
    Messages : 260
    Par défaut Enchainer plusieurs Threads "graphique"
    Bonjour,

    J'ai un problème que je n'arrive pas à résoudre, j'avais déjà posté le sujet mais je n'arrive pas à le retrouver alors j'en poste un nouveau (désolé)...

    En fait, j'ai un fonction de qui lit un fichier, et insère les données dans un base ce qui prend plusieurs secondes... Pour que l'utilisateur sache ou le processus en est, j'ai donc mis une progressBar pour suivre l'avancement, seulement, pour que cela marche, je suis donc obligé de mettre ce traitement dans un nouveau Thread que je lance en parallèle de l'application principale.

    Seulement voilà, j'aimerais que l'utilisateur puisse saisir plusieurs fichiers en même temps, et que la lecture s'enchaine, chaque fichiers doit être lu un par un...

    Si je fait une boucle, il me lance les traitements en même temps et donc les progressBar en même temps, et on n'y comprend plus grand chose...

    Donc je voudrais faire en sorte que le programme principal attende la fin du traitement d'un fichier pour passer à l'autre...

    En gros, je veux :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Début T1 => Fin T1 => Début T2 => Fin T2 etc...
    Et pas

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Début T1 => Début T2 => Fin T1 => Fin T2 ...
    J'ai essayé Mais je ne voit pas le défilement de la progressBar...

    Quelqu'un aurait une idée pour m'aider ?

    Merci de votre aide.

  2. #2
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Salut,


    Qu'est-ce que tu utilises pour lancer tes traitements ?

    Tu pourrais te tourner vers les Executors

    a++

  3. #3
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    260
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2005
    Messages : 260
    Par défaut
    Pour lancer le traitement dans un nouveau thread j'utilise simplement

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Traitement t1 = new Traitement();
    t1.start();
    Et ma classe Traitement :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    class Traitement extends Thread {
     public void run() {
      try {
       traiterFichier();
       JOptionPane.showMessageDialog(null, "Traitement effectué, "Succès", JOptionPane.INFORMATION_MESSAGE);
      } catch (Exception e) {
       e.printStackTrace();
      }
     }
    	}
    Je vais jeter un coup d'oeil aux Executors pour voir.

    Merci pour l'info.

  4. #4
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Avec les exécutors tu peux directement implémenter Runnable à la place d'étendre Thread (le thread est géré tout seule).
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    class Traitement implements Runnable {
    Ensuite tu te crées un instance d'Executors de type single-thread :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public static final Executor EXECUTOR = Executors.newSingleThreadExecutor();
    C'est à dire que tu auras un seul thread qui traitera les demandes les unes à la suite des autres...

    Ensuite, au lieu de lancer le thread, tu demande simplement à l'exécutor de l'exécuter, ce qu'il fera dès que c'est possible :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Traitement t1 = new Traitement();
    EXECUTOR.execute(t1);

    Il existe plusieurs types d'executors en standard, qui permettent diverses choses (utiliser un cache de thread, ou un certain nombre de thread...)

    a++

  5. #5
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    260
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2005
    Messages : 260
    Par défaut
    Merci pour ces précisions, je pense par contre avoir un soucis au niveau de la structure de mon code...

    En fait j'ai une classe qui demande les fichiers à l'utilisateur, et qui s'occupe de les lire.

    Seulement, pour chaque fichiers, j'initialise plusieurs variables, et il est possible que l'utilisateur doivent saisir des infos. A la suite de quoi, je lance le thread qui permet d'afficher la barre de progression...

    Pour faire simple :

    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
    public Principal(BddTransport bdd, File [] toRead) {
    		getFile();
    		lireFichier();
    	}
    private void getFile() {
    		try {
    			JFileChooser choix = new 
    			choix.setFileSelectionMode(JFileChooser.FILES_ONLY);
    			choix.setMultiSelectionEnabled(true);
    			choix.setDialogTitle("Selectionner les fichiers à lire");
    			choix.setApproveButtonText("Lire");
    			if (choix.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
    				filesToRead = choix.getSelectedFiles();
    			}
    		} catch (Exception ex) {
    		}
    	}
    public void lireFichier() {
    		for (int x=0; x<filesToRead.length;x++) {
    			if (filesToRead[x] == null) return;
    			currentFile = filesToRead[x];
    			int offset = offsetEF(idInformation);
    			if (offset == -1) {
    				JOptionPane.showMessageDialog(null,
    						"Pas d'information");
    return;
     
    			}
    			readInformation(offset);
    			verifInformation();
    		}
    }
     
    void verifInformation() {
    		if (!personne.load(idPersonne)) {
    			creer();
    		} else {
    			stock();
    		}
    	}
    void stock() {
     Traitement t1 = new Traitement();
     t1.start();
    }
    Donc, si j'essaie de lancer les Thread via la classe Executor, même si ca fonctionne comme je l'ai compris, il va recommencer le traitement du second fichier, avant de s'arrêter de nouveau au lancement du second Thread de traitement...

    Si tu pouvais me donner une confirmation avant que je me lance dans la restructuration total du processus...

    Je vais faire des tests pour voir si ca pourrait fonctionner...

    Merci pour ton aide.

  6. #6
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par RR instinct Voir le message
    Donc, si j'essaie de lancer les Thread via la classe Executor, même si ca fonctionne comme je l'ai compris, il va recommencer le traitement du second fichier, avant de s'arrêter de nouveau au lancement du second Thread de traitement...
    Oui... si j'ai bien compris ton code...

    Pourquoi tous ces traitements ne font pas partis du thread ???

    a++


    PS : Attention aux catchs vide... c'est assez vicieux comme piège !

  7. #7
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    260
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2005
    Messages : 260
    Par défaut
    Ahah !! Ca c'est une bonne question !!

    J'ai une réponse, qui n'est certes pas la bonne mais c'est la seule que j'ai :

    En fait j'ai repris un code qui avait été fait plusieurs mois aupravant et, comme on n'avait pas vraiment le temps de refaire proprement le code, j'ai laissé en l'état les partie qui marchait "à peu près" et j'ai continuer ce qui marchait moins bien ou pas du tout (contre mon gré d'ailleurs...)... Enfin sans vouloir raconter ma vie puisqu'il faut le dire franchement : ce n'est pas la question (et poliment du coup ).

    Enfin bref, en ressort ce code illisible (la j'ai quand même enormément simplifié), complétement pas optimisé, et assez lourd...

    Bref, revenons à nos moutons pour dire que j'ai réussi à mettre en place un test qui montre que la solutions que tu m'as proposé à l'air de fonctionner à merveille :

    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
     
    import java.io.File;
    import java.util.concurrent.Executor;
    import java.util.concurrent.Executors;
    import javax.swing.JOptionPane;
    import transpo.system.ui.MainFrameTransport;
    import transpo.system.ui.views.ProgressBar;
     
    public class LecturePrincipale {
    	File[]filesToRead = { new File("c:\\test.txt"),
    			new File("c:\\test2.txt")};
     
    	public LecturePrincipale() {
    		Executor executor = Executors.newSingleThreadExecutor();
     
        	for (int x=0; x<filesToRead.length;x++) {
        		Lecture t1 = new Lecture(filesToRead[x]);
        		executor.execute(t1);
        	}
    	}
     
    	public class Lecture implements Runnable {
    		File toRead;
    		public Lecture(File toRead) {
    			this.toRead = toRead;
    		}
    		public void run() {
    			System.out.println(toRead.getAbsolutePath());
    			ProgressBar av = new ProgressBar(MainFrame.getInstance(),"Lecture");
    			int max = (int)(Math.random()*15);
    			av.jBar.setMinimum(0);
    			av.jBar.setMaximum(max);
    			for (int x = 0 ; x<max ; x++) {
    				av.getBar().setValue(x);
    				try {
    					Thread.sleep(200);
    				}
    				catch (Exception ex) {
    					ex.printStackTrace();
    				}
    			}
    			av.dispose();
    			JOptionPane.showMessageDialog(null,"OK");
    		}
    	}
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    new LecturePrincipale();
    Et voilà qui nous donne donc, la première lecture, la progression parfaite, le message de confirmation "ok", puis la deuxième lecture, la progression et le message de confirmation...

    Reste plus qu'à modifier mon code et à l'integrer la dessus

    Merci beaucoup adiGuba, comme d'habitude ton aide m'a été très précieuse ! (ca fait quand même plusieurs mois que je cherchais une solution qui fonctionne !)

    Je ne met pas résolu tant que je n'ai pas tout fait, on sait jamais si je rencontre un problème pendant les modifications

  8. #8
    Expert confirmé
    Avatar de sinok
    Profil pro
    Inscrit en
    Août 2004
    Messages
    8 765
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2004
    Messages : 8 765
    Par défaut
    Attention tout de même les objets Swing ne doivent pas être directement manipulé dans les Threads. Il doivent être obligatoirement manipulés au iveau de l'EDT.
    Donc toute manipulation d'objet Swing depuis un Thread doit se faire de la façon suivante:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    SwingUtilities.invokeLater(new Runnable () {
       public void run() {
     
           maProgressBar.setValue(10);
       }
    });
    ++

  9. #9
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 914
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 914
    Billets dans le blog
    54
    Par défaut
    Houla, Swing + Thread = bobo ! Va plutot voir du cote de SwingUtilities.invokeLater() et de SwingWorker.

    EDIT - Zut ! Grilled by Sinok
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  10. #10
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    260
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2005
    Messages : 260
    Par défaut
    Citation Envoyé par bouye Voir le message
    Houla, Swing + Thread = bobo ! Va plutot voir du cote de SwingUtilities.invokeLater() et de SwingWorker.

    EDIT - Zut ! Grilled by Sinok
    Bon je veux bien accepter l'idée, encore faudrait-il en comprendre la cause, et surtout savoir pourquoi, si les Thread et SWING font si mauvais ménage, il est conseillé d'utiliser un autre Thread pour une barre de progression dans la FAQ

    http://java.developpez.com/faq/gui/?...E_progress_bar

    En tout cas il semblerait que l'enchainement ne me permettent pas d'utiliser la méthode ci dessus, je vais essayer de faire des modifications pour voir si ca marche mieux.

    Merci pour vos eclaircissements.

  11. #11
    Expert confirmé
    Avatar de sinok
    Profil pro
    Inscrit en
    Août 2004
    Messages
    8 765
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2004
    Messages : 8 765

  12. #12
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par RR instinct Voir le message
    Bon je veux bien accepter l'idée, encore faudrait-il en comprendre la cause, et surtout savoir pourquoi, si les Thread et SWING font si mauvais ménage, il est conseillé d'utiliser un autre Thread pour une barre de progression dans la FAQ
    La règle est simple :
    • Tout ce qui touche à l'interface graphique DOIT être exécuté dans l'EDT, c'est à dire le thread chargé de l'interface. C'est ce que permet de faire invokeLater()...
    • Tout ce qui ne touche pas à l'interface graphique devrait être exécuté en dehors de l'EDT, afin de ne pas trop le charger pour qu'il puisse continuer à s'occuper de l'interface graphique. Pour info tout les méthodes des listeners (actionPerformed(), mouseMoved(), etc...) sont exécuté dans l'EDT.



    Si tu ne respectes pas cela tu peux avoir des problèmes variés :
    • Si tu n'utilises pas l'EDT pour interagir avec l'interface graphique, tu risques d'avoir des comportements aléatoires assez difficile à cerner (car il dépendent de l'ordonnancement des threads et peuvent ainsi varié d'une exécution à l'autre).
    • Si tu utilises l'EDT pour des traitements "lourds" qui ne touche pas à l'interface, tu empêche l'EDT de s'occuper de ses tâches habituelles. Ceci est nettement plus visible car cela se traduit par un gel de l'interface (un exemple via Java Web Start : http://blog.developpez.com/index.php...er_a_l_affiche )


    Donc lorsque tu as un traitement long, tu dois l'exécuter dans un thread à part, et utiliser l'EDT pour mettre à jour la JProgressBar...

    A noter que SwingWorker permet de simplifier ces traitements...

    Plus d'info : http://rom.developpez.com/java-swingworker/

    a++

  13. #13
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    260
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2005
    Messages : 260
    Par défaut
    Alors, une chose que je ne comprend pas comment faire :

    - pendant le traitement, au début pour être précis, je vérifie si certaines infos sont présentes dans la base (infos que je récupère dans le fichier), si elle ne le sont pas, je demande à l'utilisateur de créer ces infos ou bien de les affecter à une infos du même type déjà renseignée. Le problème, c'est que si j'utilise un autre Thread, je ne serai en mesure d'afficher cette fenêtre que par le méthode invokeLater() d'après vos conseils, seulement j'ai besoin que cette saisie soit finie et validée pour commencer le reste du traitement...

    en gros :

    Lecture des infos principale
    => vérfication de la présence en base
    ==>si présent, lancement du traitement
    ===> message d'erreur ou de confirmation
    ==>si non présent, demande de saisie manuelle par l'utilisateur
    ===> si saisie valide, lancement du traitement
    ====> message d'erreur ou de confirmation

    J'espère que c'est clair avec les couleurs.

    Je vais essayer de trouver un début de solution seul après cette question.

    Merci pour vos réponses.

  14. #14
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 914
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 914
    Billets dans le blog
    54
    Par défaut
    Tu as egalement SwingUtilities.invokeAndWait() qui bloque tant que l'action effectuee durant l'EDT n'est pas terminee ; mais Gfx a indique dans son livre que l'utilisation de cette methode peut parfois mener a des deadlocks.

    Si le pre-traitement est leger, tu peux eventuellement t'en charger durant l'EDT en reponse au click. Meme ainsi, plutot que d'executer l'action immediatement dans le listener, c'est mieux d'utiliser SwingUtilities.invokeLater() ou un Timer Swing pour :
    - desactiver les elements de la GUI en reaction a l'evenement dans le listener.
    - puis executer l'action reelle plus tard.

    Mais bon, dans la pratique l'acces a une base ou un fichier peut se reveler etre plus long que prevu ou que ce que tu as experimente sur la machine de test, donc ce la peut mener au gel de l'interface (base qui met du temps a repondre, etc...). Donc un SwingWorker ou une Thread peut se reveler etre utile ici pour ce pretraitement.

    Sinon : ce n'est pas parce qu'une interraction directe entre Swing et ta Thread fonctionne bien dans ton cas sur ta machine de test avec ta JVM actuelle qu'il en sera de meme sur d'autres OS/Systemes avec une JVM d'une autre version/fournie par un autre vendeur (me suis fais avoir plein de fois au debut).
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  15. #15
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    260
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2005
    Messages : 260
    Par défaut
    Bonjour,

    Je viens vous compter mes aventures :

    - J'ai donc décidé de tout reprendre le traitement pour le faire à ma manière, ce fut très galère, mais j'ai réussi à le faire, j'ai pas enormément changé le déroulement du traitement, mais j'ai quand même gagné quasiment 1 000 lignes de codes (sur 1 500 ca fait un bon ratio !! Et ca vous laisse une idée de l'état de la chose...).
    - J'ai ensuite essayé de tout mettre dans un thread (c'est à dire de la selection des fichiers jusqu'à la fin de l'enregistrement, et la ca marche comme je veux...

    Seulement voilà, j'ai un JFileChooser des JOptionPane, et aussi ma JProgressBar qui sont affichés et manipulés dans ce Thread et non pas dans l'EDT, ce qui n'est pas bien !

    Quand j'essaie d'utiliser

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SwingUtilities.invokeLater()
    J'ai, déjà, des problèmes de variables "final", et en plus, j'obtiens le même résultat que si tout était dans le Thread de l'EDT (c'est à dire freeze sur la barre de progression par exemple).

    Mais je chercher encore car je veux faire quelque chose de propre quand même !! Si vous avez des idées à me proposer je prend

    Merci pour votre aide déjà en tout cas.

  16. #16
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 914
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 914
    Billets dans le blog
    54
    Par défaut
    Il est difficile de pouvoir en dire plus sans avoir quelques bouts de code, pas l'integralite de ton traitement (surtout s'il y en a pour 1.000+ lignes) mais au moins comment tu demarres ta tache/Thread et comment tu fais tes maj des composants apres.

    PS : si tu crees ta Thread durant l'EDT (ce qui est fort probable) pense a lui mettre une priorite plus normale...

    Citation Envoyé par javadoc
    When code running in some thread creates a new Thread object, the new thread has its priority initially set equal to the priority of the creating thread, [...]
    L'EDT a une haute priorite (normal), a moins de faire du temps-reel, ton traitement a besoin d'un priorite comprise entre Thread.MIN_PRIORITY et Thread.NORM_PRIORITY. Mais bon ca ne changera rien si ton architecture ou tes interractions ont des problemes de conception.
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

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