Profitez-en, après celui là c'est fini

Grève de la ligne 13

décembre 8th, 2008 Posted in Études, Personnel | 2 Comments »

Message personnel aux étudiants du cours d’initiation à la programmation multimédia du mardi à Paris 8 : demain, mardi 9 décembre, la CGT a déposé un préavis sur la ligne 13 pour un motif d’indignation difficilement contestable par les utilisateurs, puisque c’est l’accélération de la dégradation de la qualité du service qui justifie cette grève de vingt-quatre heures.


La RATP assure que ce mouvement social n’aura que des effets négligeables (en Australie sans doute), mais sachant les difficultés « normales » de la bétaillère ligne ces dernières semaines (notamment le mardi en fin de matinée), méfiance ! Si le cours s’avère ne pas pouvoir être assuré normalement, je vous invite à lire et à tester chez vous les pages 1 à 6 de ma série d’articles sur Processing.

Processing, treizième cours

décembre 8th, 2008 Posted in Processing | 8 Comments »

La programmation orientée objet est un concept relativement récent dans l’histoire de l’informatique (n’ayant été massivement employé que depuis le début des années 1990, quoique l’idée soit bien plus ancienne) mais il semble à présent impossible de vivre sans. En effet, des applications aussi banales que les interfaces graphiques d’ordinateurs ou la gestion des éléments d’un jeu interactif rendent le recours à ce « paradigme » presque obligatoire. Un grand nombre de langages de programmation courants sont orientés objet.

Pour bien comprendre l’intérêt de la programmation objet, prenons un cas simple et facile. Tout d’abord, imaginons que nous voulions créer un stylo « fou » qui dessine sur notre fenêtre d’affichage.

float x, y; // déclaration des variables décimales x et y

void setup(){
  // au démarrage
  size(180,180); // réglage du format de la fenêtre
  background(0); stroke(255); // réglage des couleurs
  x=90;y=90; //affectation de valeurs à x et y; 
}

void draw(){
  // script exécuté régulièrement 
  float newx = x+random(-5,5);  // création de newx
  float newy = y+random(-5,5);  // création de newy
  // contraintes appliquées à newx et newy
  // afin de les empêcher de sortir de l'écran 
  if(newx<0){newx=0;} if(newx>width){newx=width;}
  if(newy<0){newy=0;} if(newy>height){newy=height;}
  // tracé de la ligne
  line (x, y, newx, newy);
  // enfin, x prend la valeur de newx et y celle de newy
  x = newx; y = newy;
}

Le résultat d’un tel script sera le tracé totalement au hasard d’un trait blanc sur un fond noir. L’image ci-contre montre une capture de l’image de la « scène » à un moment du déroulement du programme. La fenêtre fait 180×180 pixels et le tracé commence en son centre c’est à dire au point (90,90). À chaque cycle, un nouveau point est calculé, qui s’éloigne de la position précédente à une distance variant entre -5 et +5 pixels dans les abscisses et entre -5 et +5 pixels dans les ordonnées.
On note qu’à chaque cycle, une fois que les valeurs newx (x + random(-5,5)) et newy (y + random(-5,5)) ont été calculées, la ligne est tracée avant que x soit remplacé par newx et y par newy.

Ce script très simple ne s’adapte cependant qu’au seul et unique cas où nous n’aurions qu’un seul traceur « fou » à utiliser. Mais comment faire pour tracer plusieurs traits en même temps, de plusieurs couleurs différentes en même temps ? C’est précisément là qu’intervient la programmation objet, elle me permet de décréter l’existence d’un objet nommé « traceur_fou » qui existera simultanément en plusieurs occurrences (ou instances), comme suit :

traceur_fou[] traceurs = new traceur_fou[0]; 
// déclaration d'un tableau de type "traceur_fou"
// ce tableau se nomme traceurs a au départ zéro éléments 

void setup(){
  // démarrage
  size(180,180);  // réglage du format de la fenêtre
  background(0); stroke(255);  // réglage des couleurs
   // création de dix objets de type traceur_fou
   // qui sont ajoutés au tableau traceurs 
  for(int a=0;a<10;a++){
    traceurs = (traceur_fou[]) append(traceurs, new traceur_fou());
  }
}

void draw(){
   // de manière régulière (draw())
   // une boucle permet de donner à chaque objet de type traceur_fou 
   // l'ordre d'activer sa commande dessine() 
  for(int a=0;a<traceurs.length;a++){
   traceurs[a].dessine();
 }
}

class traceur_fou{
  // déclaration des variables dont disposera chaque objet de type
  // traceur_fou
  float x=90;float y=90;color c;
  traceur_fou(){
     // "constructeur" d'objets de type traceur_fou
     // ici, la couleur "c" prend une valeur au hasard 
     c=color(random(255),random(255),random(255));
  }
  void dessine(){
     // dans le script "dessine" nous avons les éléments
     // utilisés dans le précédent programme 
     stroke(c);
     float newx = x+random(-5,5);
     float newy = y+random(-5,5);
     if(newx<0){newx=0;} if(newx>width){newx=width;}
     if(newy<0){newy=0;} if(newy>height){newy=height;}
     line (x, y, newx, newy);
     x = newx; y = newy;
  }
}

J’ai tenté d’écrire un programme très simple mais je m’aperçois que sa lisibilité est assez relative. On peut en voir l’effet sur l’image qui se trouve ci-contre et qui est une capture de l’image de la scène à un moment de l’exécution du programme. Au lieu de tracer un trait au hasard, notre programme en trace dix en même temps. Chacun a sa couleur propre, attribuée au hasard.

Le secret d’un tel programme est l’utilisation des « classes » d’objets. Une classe est un ensemble de propriétés de types disparates (une même classe peut contenir des chiffres, des chaînes de caractères, etc.) et de fonctions qui peuvent être attribuées à plusieurs occurrences indépendantes.
Pour prendre une métaphore assez simple, nous pouvons dire que chacun d’entre nous est une occurrence unique de la classe « être humain ». Nous avons de nombreux points en commun mais nous sommes tous différents par certains aspects : notre nom, notre âge, notre identité sexuelle, notre couleur de cheveux, etc. Nous sommes tous capables d’exécuter certaines fonctions de manière indépendante (marcher, courir, parler, etc.) ou simultanée (vieillir). Si je voulais créer une classe d’être humain disposant des propriétés et des fonctions énumérées ci dessus, je la rédigerais par exemple ainsi :

class etre_humain{
  String nom, sexe, cheveux; int age;
   etre_humain (String n, String s, String c, int a){
      nom = n; sexe = s; cheveux = c; age = a;
   }
  void  vieillis(){
      age = age+1;
  }
  void marche(){
      // ...commandes correspondant au fait de marcher
  }
}

Je peux à présent « créer » des instances de l’objet « etre_humain » de cette manière :

etre_humain  eh1 = new etre_humain("Georges", "homme", "brun", 40);
etre_humain  eh2 = new etre_humain("Charles", "homme", "brun", 50);
etre_humain  eh3 = new etre_humain("Lucille", "femme", "blond", 32);
etre_humain  eh4 = new etre_humain("Charlotte", "femme", "chatain", 36);

Chaque instance est stockée dans une variable. J’ai nommé mes variables eh1, eh2, eh3 et eh4, mais j’aurais pu leur donner d’autres noms bien entendu. À présent, si je désire connaître l’âge de Georges (qui est stocké dans eh1), je n’aurais qu’à demander print(eh1.age);. Si je désire changer la couleur des cheveux de Charlotte je peux écrire : eh4.cheveux = "roux";.
Enfin, si je souhaite faire vieillir Charles d’un an, je peux écrire eh2.vieillis();.
Ce genre d’exemple est un peu abstrait puisque nous ne parlons ici que de valeurs numériques ou de chaînes de caractères. La programmation orientée objet est souvent un peu difficile à comprendre au début.
Voici une dernière démonstration d’utilisation du paradigme « orienté objet ».

// déclaration d'une liste d'objets de type "cercle"
cercle[] TousMesCercles = new cercle[0];

void setup(){
  size(180,180); smooth(); strokeWeight(0.5); background(255);
  fill(255,25); // la couleur de remplissage est du blanc à ~10% d'opacité
  // remplissage du tableau TousMesCercles avec 89 objets de type "cercle"
  for(int a=1;a<90;a++){
    TousMesCercles = (cercle[]) append(TousMesCercles, new cercle(a));
  }
}

void draw(){
  noStroke();
  rect(0,0,180,180);
  stroke(0);
  for(int a=0;a<TousMesCercles.length;a++){
    TousMesCercles[a].dessine();
  }
}
class cercle{
  // déclaration des variables
  float rayon; float vitesse; float angle;
  cercle(float r){
    // initialisation de l'instance
    rayon=r; angle=0; vitesse=radians(random(-3,3));
  }
  void dessine(){
    // fonction "dessine" propre à chaque objet
    angle+=vitesse; // la variable "angle" est incrémentée de "vitesse"
    // petit calcul trigonométrique basique
    line(90,90,90+cos(angle)*rayon, 90+sin(angle)*rayon);
  }
}

Cette fois, nous avons créé une classe nommée « cercle » (nous avons inventé ce nom) qui utilise trois variables (nommées rayon, vitesse et angle, toutes de type « float ») et qui contient deux fonctions, son « constructeur » (sa fonction d’initialisation), nommé cercle()(c'est à dire ayant le même nom que la classe) et une fonction nommée dessine().
Une liste nommée  TousMesCercles est déclarée en tête du script puis remplie de 89 éléments dans la fonction setup(). Chacun de ces éléments s’est fait attribuer une variable nommée rayon et allant de 1 à 90. voit invoquer sa fonction dessine() depuis la fonction draw().
La fonction dessine() incrémente la variable angle en l’additionnant à la variable vitesse. Enfin une ligne est tracée entre le centre (90,90) et un point calculé à partir de l’angle et du rayon (90+cos(angle)*rayon, 90+sin(angle)*rayon). Nous reverrons peut-être cette formule trigonométrique de base ultérieurement.
Au début de la fonction draw(), la scène n’est pas repeinte en blanc mais juste recouverte d’un rectangle blanc à 10% d’opacité, ce qui donne un effet de persistance et d’effacement progressif des traits tracés. L’image qui se trouve ci-contre correspond à une capture de l’écran à un moment donné de l’animation mais vous devez copier-coller l’ensemble du code dans Processing pour en voir l’effet véritable.

Il est en tout cas important de noter que les opérations réalisées sur un tableau d’objets ne peuvent être rédigées comme suit :

monTableau = append (monTableau, monObjet);

mais doivent l’être de cette manière :

monTableau = (classe[]) append(monTableau, monObjet);

il est à noter aussi que le mot-clé this est valide dans Processing. Ce mot-clé sert, pour un objet, à se désigner lui-même. C’est l’équivalent de me dans le logiciel Director. Ainsi un objet pourrait s’ajouter de lui-même à une liste d’objets comme ceci :

bidule[] TousMesTrucs = new bidule[0];

class bidule{
  bidule(){
     TousMesTrucs = (bidule[]) append (TousMesTrucs , this);
  }
}

Si vous n’avez pas compris grand chose à cet article, pas de panique. Ces concepts sont souvent difficiles à assimiler. Le prochain article sera nettement plus accessible.

Processing, douzième cours

décembre 8th, 2008 Posted in Processing | 6 Comments »

Après les variables, les tableaux, parfois appelés listes. Ce sujet n’est pas toujours le plus simple à comprendre ou en tout cas à faire comprendre (peut-être est-ce juste moi qui l’explique mal). Il faut dire que le tableau est un type de donnée dont l’usage est assez abstrait, rien à voir avec les commandes de dessin géométrique de Processing dont l’utilité est immédiate et évidente.
Un tableau est tout bêtement un ensemble de variables (qui doivent impérativement être du même type, dans le cas de Processing). Cet exemple le montre de manière simple :

String[] animaux = {"chat", "chien", "cheval", "lapin", "souris"};
print (animaux[2]);

Si vous lancez ce programme, vous verrez ceci :

Tout d’abord, une fenêtre d’affichage de la taille et de la couleur par défaut s’ouvre, mais elle ne contient rien, puisque nous ne l’utilisons pas.
Dans la zone noire, qui est la zone dite « de texte » et qui permet à Processing de nous adresser des messages sollicités (en gris) ou des messages d’erreur (en orange), on peut voir écrit le mot « cheval ». La commande print() sert en effet à afficher quelque chose dans la zone de texte — si j’écris print(« bonjour ») dans le programme, le mot bonjour s’affichera dans la zone de texte.
Ici nous avons demandé à Processing de nous donner le troisième élément (la numérotation commence à zéro) de la liste animaux, créée sur la ligne du dessus.
Revenons un peu en arrière.
En écrivant String[] animaux, je déclare un « tableau » de chaînes de caractère dont le nom est « animaux ». Ce sont les deux crochets qui suivent le type qui signifient qu’il s’agit d’un tableau et non d’une variable isolée. Tout en déclarant ce tableau, je lui ai attribué un contenu entre accolades, contenu qui est une suite de chaînes de caractères séparées par des virgules. Son premier élément est le mot « chat« , le second est le mot « chien« , et ainsi de suite.
Pour Processing (comme pour de nombreux langages), ma liste contient cinq éléments, numérotés 0, 1, 2, 3 et 4. Si je souhaite accéder au premier élément je demanderais animaux[0].
Si je souhaite remplacer le mot « lapin » par le mot « lièvre » j’écrirais animaux[3]= »lièvre ». Pour ajouter un sixième animal, par exemple l’éléphant, à ma liste, c’est un peu plus compliqué, je dois écrire ceci :

animaux = append (animaux, "éléphant");

(la commande append(tableau, valeur) signifie que l’on ajoute une valeur à la fin d’un tableau).
Pour ajouter une valeur à un emplacement précis du tableau on utilise la commande splice(liste, valeur, position). La ligne qui suit intercalera le mot « toucan » entre les mots « chien » et « cheval », c’est à dire à la place 2.

animaux = splice(animaux , "toucan", 2);

Pour enlever sa dernière valeur à un tableau, la commande est shorten(tableau), comme ceci :

animaux = shorten(animaux);

La syntaxe que j’ai utilisé plus haut pour déclarer mon tableau tout en lui donnant un contenu n’est pas typique. Généralement, on écrit plus laborieusement ceci :

int[] maListeDeChiffres = new int[12];

qui signifie que je déclare un tableau de 12 chiffres entiers, auxquels je pourrais donner des valeurs par la suite, par exemple comme ceci :

maListeDeChiffres[0] = 128;
maListeDeChiffres[1] = 256
maListeDeChiffres[2] = 64;

etc.

ou pourquoi pas à l’aide d’une boucle, de cette manière :

for(int a=0;a<12;a++){
  maListeDeChiffres[a]=a*10;
}

… Dans ce cas, ma liste contiendra les valeurs {0,10,20,30,40,50,60,70,80,90,100,110}

On peut, par ailleurs, créer des tableaux de tableaux, comme ceci :

int[][] monTableauAdeuxDimensions = new int[4][2];
monTableauAdeuxDimensions[0][0]= 10;
monTableauAdeuxDimensions[0][1]= 20;
monTableauAdeuxDimensions[1][0]= 15;
monTableauAdeuxDimensions[1][1]= 25;
monTableauAdeuxDimensions[2][0]= 143;
monTableauAdeuxDimensions[2][1]= 321;
monTableauAdeuxDimensions[3][0]= -10;
monTableauAdeuxDimensions[3][1]= 28;

Ici je dis que je crée un tableau de type entier nommé monTableauAdeuxDimensions qui contient quatre éléments dont chacun est un tableau de deux éléments. Si je demande à savoir quel est l’élément monTableauAdeuxDimensions[2][1], il me sera répondu 321. En revanche, contrairement à Java, C++, Php ou Javascript, Processing ne gère pas les tableaux dits « associatifs » (où chaque valeur du tableau est associée à une clé), sujet sur lequel je ne m’étendrais donc pas bien qu’il était important que je le signale.

Pour connaître le nombre d’éléments d’un tableau, on utilise la propriété length. Ainsi, dans l’exemple qui se trouve ci-dessus, monTableauAdeuxDimensions.length a la valeur de 4 (il y a quatre éléments dans monTableauAdeuxDimensions) et monTableauAdeuxDimensions[0].length a la valeur de 2 car il y a deux éléments dans le premier élémént (numéroté zéro) de monTableauAdeuxDimensions.
Un exemple pratique.:

int[] mesPositions = {1,3,6,11,17,24,32,41,51,62,73,84,95};
for(int i=0;i<mesPositions.length;i++){
  line (0, mesPositions[i],100,mesPositions[i]);
}

Avec ces quelques lignes, nous commençons par déclarer une liste de type entier (int[]), nommée mesPositions et contenant treize éléments numériques : 1, 3, 6, 11, 17, etc.
Nous exécutons ensuite une boucle qui utilise une variable nommée i dont la valeur va passer de 0 (zéro) à mesPositions.length, c’est à dire 13, puisque la liste mesPositions contient treize éléments.
À chaque passe de cette boucle, une ligne est tracée entre les points (0, mesPositions[i]) et (100, mesPositions[i]). Lors du premier passage, i sera égal à 0, donc mesPositions[i] aura la valeur de mesPositions[0] c’est à dire 1. Ma première ligne sera donc tracée entre (0, 1) et (100,1). Au second passage, mesPositions[i] aura la valeur 3, donc la ligne sera tracée entre (0,3) et (100,3). Et ainsi de suite. On peut le voir avec l’illustration qui se trouve à droite et qui est le produit ce programme : treize lignes sont tracées, chacune commence à gauche (abscisse : 0) et se termine à droite (abscisse : 100) et a pour ordonnée les chiffres contenus dans notre liste, à savoir 1, 3, 6, 11, 17, etc.

Très rapidement et à l’attention des programmeurs habitués à manipuler des listes, quelques commandes utiles (cliquer sur leur nom pour obtenir la page correspondante dans la documentation de processing) :

  • arrayCopy() permet de copier un tableau dans un autre ou de copier une partie d’un tableau dans un autre tableau, éventuellement à une position précise.
  • concat() permet de concaténer (d’amalgamer)  deux tableaux.
  • reverse() permet d’inverser l’ordre des éléments d’une liste.
  • sort() permet de classer les éléments d’une liste (par ordre numérique ou alphabétique).
  • splice(), montré plus haut, permet d’ajouter un ou plusieurs éléments à un emplacement précis d’une liste.
  • subset() permet d’enlever un ou plusieurs éléments à un emplacement précis d’une liste.
  • println() permet d’afficher le contenu d’une liste dans la zone de texte de processing.

Signalons à toutes fins utiles qu’il existe une manière alternative pour créer et manipuler des tableaux qui est de recourir directement à la classe Java ArrayList. Cette méthode est assez souple, la classe ArrayList permettant d’utiliser des commandes telles que contains() (pour vérifier si un élément se trouve dans la liste) ou indexOf() pour vérifier à quelle position dans la liste se trouve un élément connu. Le mode d’emploi de ArrayList se trouve dans les pages de documentation de Java.

Dans la programmation orientée objet, la syntaxe des commandes relatives aux listes est la même mais impose une syntaxe redondante. Ainsi, si je veux créer un tableau de valeurs entières nommé liste et contenant les valeurs 0, 1, 2, 3 puis y ajouter la valeur 4, je dois écrire :

int[] liste = {0,1,2,3};
liste = append(liste, 4);

En revanche, si j’utilise une classe d’objet inventée par moi-même, par exemple la classe « bille », je devrais utiliser la commande append() comme suit :

mesBilles = (bille[]) append (mesBilles, new bille());

…Mais nous verrons cela dans le prochain article qui est justement consacré à la programmation orientée objet.

L’âme d’une nouvelle machine

décembre 4th, 2008 Posted in Lecture, Ordinateur célèbre | 2 Comments »

Sorti en 1981, Eagle (The Soul of a new machine — l’âme d’une nouvelle machine) n’est pas un roman banal. Je sais peu de choses sur la manière dont il a été reçu en France1 où il a été publié par Flammarion en 1982, mais aux États-Unis, Eagle a été courronné par le très prestigieux prix Pullitzer dans la catégorie « Non Fiction ».
Bien qu’il s’agisse d’un ouvrage plutôt littéraire, Eagle entend en effet relater des faits réels avec précision, on peut donc le qualifier de roman-témoignage. Son sujet est l’aventure industrielle de la création, à la toute fin des années 1970, d’une nouvelle gamme de mini-ordinateurs, le Eclipse MV/8000 de la société Data General, ordinateur dont le nom provisoire était Eagle2 . Le moral d’une équipe, l’énergie d’un chef de projet, les services concurrents à l’intérieur d’une même société, c’est ce genre de choses que Eagle raconte, sans changer les noms des personnes et sans masquer le moindre détail susceptible de fâcher — quoique à la réflexion je vois peu de détails qui fâchent ici. Malgré l’aspect ultra-spécialisé des enjeux (comment créer une machine 32 bits qui ne concurrence pas de manière stérile un projet plus « sexy » lancé par une autre équipe dans un autre état…), le lecteur peut à mon avis percevoir ce que le processus industriel peut avoir d’épique et d’exaltant. Plus qu’un roman pour « nerds », Eagle parle du métier d’ingénieur et je suppose que l’on aurait presque pu écrire le même genre d’ouvrage en parlant d’aviation ou de réfrigérateurs.

Plus de vingt-cinq ans après sa sortie, Eagle a cependant gagné un supplément de sens car il nous rappelle la vanité de certains combats. La mini-informatique a été supplantée par la micro-informatique et par la domination du software sur le hardware. La société Data General, rachetée par un fabriquant de solutions de stockage informatique, n’a même plus de site internet, et ses concurrents (Honneywell, Dec, Wang, etc.) ont presque tous connu des sorts comparables.
Document de premier plan sur son époque, Eagle est écrit par quelqu’un qui découvre complètement l’univers de l’informatique et qui nous la présente avec les yeux grands ouverts. Les yeux et les oreilles, d’ailleurs : qui penserait à dire aujourd’hui que les disques durs émettent des sons qui rappellent le grignottement ? Le son d’un disque dur, en 2008, nous rappelle surtout le son… d’un disque dur. Au fil des pages on tombe sur des descriptions assez bien vues, telles que cette évocation de l’esthétique des circuits imprimés dont la qualité plastique est évidente (montrez une carte mère à un enfant et observez sa réaction) mais qui a, je pense, rarement fait l’objet de descriptions littéraires :

Certaines des plaquettes sont colorées, au point d’être agréables à l’œil. Il y a quelque chose, dans leur complexité, qui semble chanter le triomphe de l’ordre. Il s’en dégage l’impression qu’elles ont un sens, une signification, mais pas à la manière dont, par exemple, les différentes pièces d’un moteur en mouvement ont une signification, un rôle accessible  à la compréhension immédiate. Le dessin visible de la surface d’une carte ne permet en rien d’en déceler la fonction3 .

Pour qu’un sujet si austère a priori parvienne à captiver ses lecteurs jusqu’à devenir un authentique best-seller, l’auteur s’appuie sur ses personnages et notamment sur celui de Tom West, le chef de projet, rencontré par Tracy Kidder lors d’une croisière de plaisance et dont le sang-froid et même l’enthousiasme à piloter le navire pendant une tempête l’avait stupéfié. C’est, curieusement, en parlant des personnes et de leur parcours que le roman parvient à évoquer réellement ce qu’est la spécificité de l’ingénérie en informatique.
L’auteur a très bien compris l’enthousiasme de l’ingénieur informaticien, les défis que ce dernier aime surmonter, la découverte, l’invention, les éclairs de génie que l’on a au réveil, sous la douche, en marchant ou à l’heure où le dîner refroidit et qui occupent l’esprit tout le week-end. La manière dont les idées ne viennent pas tout de suite, la façon dont il faut parfois laisser mûrir des idées, végéter dans le travail, se mettre en situation de péril professionnel parfois, pour achever véritablement le travail en quelques jours. Il parle aussi très bien des différentes approches ou des différents tempéraments qui s’affrontent et qui se complètent  dans une équipe : ténacité, perfectionnisme, réalisme.

Témoignage précis, Eagle montre en effet qu’il existe des personnalités très diverses d’ingénieurs. Ceux qui aiment concevoir, ceux qui aiment démonter et comprendre, ceux qui aiment faire fonctionner sans comprendre, ceux qui pensent aux applications futures et ceux qui au contraire ne s’intéressent qu’à l’élégance des solutions, les instinctifs, les méthodiques, les planificateurs… Il semble même que sans toutes ces personnes complémentaires, sans cette alchimie humaine, un objet éminemment technique tel que cet ordinateur n’aurait pas pu être fini.
On mesure aussi à quel point il arrive à l’industrie d’abandonner des projets — pour nombre des protagonistes de l’histoire, le projet Eagle est d’ailleurs une revanche prise sur un projet précédent qui avait dû être abandonné. On constate aussi que les batailles techniques remportées (des semaines passées à écumer des kilomètres de listings pour tenter de comprendre une erreur par exemple) ne sont comprises et donc (à peine) célébrées que par ceux qui s’y sont engagés. Au résultat, l’utilisateur d’un ordinateur ou d’un programme ne prendra conscience de l’existence de ses créateurs que si quelque chose ne fonctionne pas bien. Ainsi pour l’ingénieur, faire que « ça fonctionne » est un combat complexe et exaltant tandis que pour l’utilisateur, le bon fonctionnement du système est la normalité.
La fin du livre est intéressante. Voyant que son projet a atteint le stade de la viabilité, et assuré qu’il ne sera pas subitement annulé, le chef de projet West abandonne son Eagle pour partir vivre au Japon où d’autres projets industriels l’attendent. Lors de la présentation à la presse du MV/8000, il reste en retrait et personne ne connaît son rôle en dehors de ceux qui ont travaillé sous son commandement. Une fois la machine sortie, les autres ingénieurs connaissent une « redescente » qui me semble très caractéristique, une sorte de dépression post-partum.

Je note avec intérêt et même  avec une pointe d’étonnement la présence, dans ces bureaux de la fin des années 1970, d’une « culture geek » tout à fait semblable à celle qui a cours aujourd’hui dans les mêmes professions : le Seigneur des Anneaux, James Bond ou encore Star Wars sont des références constantes. Les protagonistes du récit jouent par ailleurs à un jeu de d’aventure médiévales fantastique sur ordinateur. La question de l’âge (que deviennent les informaticiens après 35 ans se demande l’un d’eux) ou du manque de diversité sexuelle (le chef de projet West tente désespérément de trouver des femmes ingénieur à embaucher) font toujours partie des questions qui se posent dans ce domaine professionnel. Découvrira-t-on un jour un gène de l’informaticien ?

Précurseur de d’une pratique aujourd’hui assez répandue — l’histoire des entreprises — Tracy Kidder a fait de la naissance des ordinateurs Eclipse MV/8000 le projet informatique et même le projet industriel le mieux documenté au monde.
C’est sans doute aussi l’unique best-seller, hors mauvaise science-fiction, qui contient des phrases telles que :

il essayait de déterminer lequel, du 21 ou du 45, était le bon numéro de bloc, et pour ce faire il remontait le programme vers l’amont, à partir du point litigieux. Mais il est clair décidément que la réponse se situe plus haut encore, en deça du champ d’exploration des analyseurs […] il va donc faire exécuter le programme jusqu’à la quatrième passe et, chaque fois que Gollum effectuera les instructions JSR et Return, il arrêtera la machine pour prendre un cliché grâce à l’analyseur, et en obtenir une sortie imprimée sur la console.

Malgré ses efforts méritoires et malgré une approche pédagogique affirmée, on perçoit parfois que l’auteur rapporte certains détails techniques sans les comprendre tout à fait. C’est ponctuel, mais illustré par quelques métaphores un peu douteuses. La traduction française, par Rose-Marie Vassallo-Villaneau, me semble tout à fait honorable du pur point de vue technologique.

Columbia pictures a pris à l’époque une option sur les droits du roman dans le but d’en faire un film, mais le projet n’a pas abouti. Il est vrai que tout ça manque un peu de faits-divers et d’histoires d’amour, en dehors du cas d’une secrétaire très jolie et qui est anonymement harcelée par un programmeur-hacker qui se révèlera appartenir à un autre service et qui chaque jour se débrouillait pour faire apparaître des insanités sur l’écran du terminal de la demoiselle.
En France, l’ouvrage a été réédité en 1994, mais apparemment pas depuis.

  1. J’ai retrouvé un article du numéro 7 du journal Telesoft, ou un dénommé Pierre Goujon, professionnel de l’informatique, réagit avec une certaine virulence à ce livre auquel il reproche une approche trop journalistique. [↩]
  2. Le MV/8000, créé pour concurrencer le Vax de Dec, a connu un succès certain à sa sortie. Il valait 1,5 millions de francs, c’est à dire deux-cent mille euros. [↩]
  3. Le visuel choisi pour la couverture, même s’il s’agit plutôt de l’intérieur d’un circuit intégré, semble d’ailleurs précisément inspiré par ces lignes.  On notera au passage l’emploi par Flammarion d’une typographie «cyber».  [↩]

Pinocchio par Winshluss

décembre 1st, 2008 Posted in Bande dessinée | 6 Comments »

Un peu de bande dessinée pour décompresser et pour oublier, provisoirement, les variables dans Processing.

L’an dernier, la scénariste-dessinatrice-autobiographe Marjane Satrapi était sur toutes les chaînes de télévision à chaque grand rendez-vous du cinéma. Cannes, les Césars et surtout les Oscars ont nommé et, pour les deux premiers, couronné de prix prestigieux le long-métrage Persépolis. C’était mérité, le film est réussi, et s’il est réussi, s’il est vif, drôle et cruel, c’est sans doute en grande partie grâce au talent du presque-quarantenaire maigrichon en smoking qui se cachait derrière ses lunettes, sa barbe, et derrière Marjane Satrapi, à chacune de ses apparitions médiatiques.
Pour les présentateurs de télévision, ce jeune homme se nomme Vincent paronnaud et il est réalisateur de dessins animés. Mais pour les amateurs de bande dessinée, il s’appelle Winshluss et il est sans doute l’auteur le plus décapant de sa génération. J’ai pour ma part découvert Winshluss dans les magazines Jade et Ferraille il y a une dizaine d’années et je ne rate pas une de ses (assez rares) publications depuis. Winshluss collabore fréquemment avec Cizo (que le public connaît pour ses publicités très graphiques pour le service téléphonique 118 000), le plus « graphiste » des auteurs de bande dessinée ou le plus « auteur de bande dessinée » des graphistes. À eux deux, ils ont notamment publié l’album Monsieur ferraille. On leur doit bien plus puiqu’ils ont organisé des expositions (Supermarché Ferraille, Monsieur Ferraille), réalisé des dessins animés, fabriqué des objets divers, et, toujours dans cette logique, ils ont transformé le sympathique journal Ferraille en une publication chic et punk. C’est dans les tout derniers numéros de Ferraille qu’a commencé la publication de Pinocchio (ici mis en couleurs par Cizo justement), interrompue par la disparition du magazine.

Ceux qui ont crié au génie subversif en voyant Shrek, le monstre en 3D de Dreamworks, flatuler et éructer et massacrant joyeusement les contes de fées, constateront que nous passons un cran au dessus en voyant le destin que Winshluss offre à Blanche-Neige et à ses sept nains, à Pinocchio et à Gepetto bien entendu, à l’harmoniciste aveugle Wonder, ainsi qu’à mille et un autres personnages.

La marque de fabrique de Winshluss est une forme de confusion maîtrisée. Les époques, les clichés, et même les graphismes se télescopent. Disney (notamment le Disney un peu féroce des premières années) ou les frères Fleischer rencontrent l’endoctrinement fasciste, la perversion sexuelle, les désastres écologiques, les savants apprentis sorciers, la drogue, le suicide, la corruption, les marchands d’armes et les exploiteurs d’enfants. Généralement, il suffit de quelques cases muettes pour convoquer tel ou tel moment historique, tel grand drame, tel roman moral (un peu de Dickens par exemple), tel archétype, etc. On saute constament d’un registre à un autre, d’un personnage à un autre, d’un genre littéraire à un autre. Les existences sont résumées en quelques cases, les motivations des personnages sont à peu près aussi mécaniques que leurs destins.

Utiliser Pinocchio était on ne peut plus logique, car l’ouvrage d’origine (vaguement évoqué), autant que ses nombreuses adaptations (celui de Disney, avec le cricket-conscience, jusqu’au A.I. de Spielberg), est constament à la limite du sordide.  
Le personnage de Pinocchio (ici, un robot à vocation militaire), est plutôt passif, voire impassible, il ne lui arrive jamais rien qu’il ait décidé. Le récit est totalement muet en dehors des pages qui concernent Jiminy Cafard, unique personnage auquel le lecteur peut s’identifier, portrait pathétique de velléitaire qui se rêve écrivain et qui est forcé d’habiter dans la tête de Pinocchio depuis qu’on a coupé ses allocations chômage. 

Je ne vais pas vous raconter le livre, faites-le vous offrir pour noël. Vous ne le regretterez pas, d’autant que l’ouvrage est d’une beauté extraordinaire. Sa couverture, notamment, est extrèmement soignée, à la manière de la reliure « Ferraille illustré » sortie il y a quelques années chez le même éditeur — les Requins Marteaux.
Et aux enfants, on offrira la série Wizz et Buzz (parue dans Picsou Magazine), de Winshluss et Cizo.

Processing, onzième cours

décembre 1st, 2008 Posted in Processing | 5 Comments »

Nous avons déjà rencontré des variables au fil des scripts, il est temps de faire le point à leur sujet. Il s’agit d’un des concepts clé de la programmation.

Une variable est un mot qui est associé à une valeur. Je peux par exemple décréter que j’utilise une variable nommée compteur (c’est moi qui ai choisi le nom) et qui est associée à la valeur 0 (zéro). Puis, au cours de mon animation je peux imaginer d’incrémenter ce compteur en fonction d’un évènement, par exemple à chaque fois qu’un clic de souris est effectué. Au premier clic, la variable compteur sera alors incrémentée de 1 et verra sa valeur passer de zéro à un, puis au second clic elle sera à nouveau incrémentée et prendra donc la valeur de deux, et ainsi de suite.
Les applications pratiques des variables sont infinies, puisqu’elles permettent de faire évoluer une valeur dans le temps. Par exemple si je souhaite faire bouger un objet sur l’écran, il faudra que ses coordonnées soient stockées dans des variables afin que je puisse changer la position de l’objet en tenant compte de son état antérieur. Nous alons voir un cas pratique plus loin.

Le principe de fonctionnement des variables n’est pas très difficile à comprendre mais le débutant peut être dérouté par un certain nombre de pré-requis que je vais énumérer ici :

  • Les variables s’écrivent en un seul mot et ne contiennent donc aucune espace. Elles ne peuvent contenir que des lettres et des chiffres (mais ne peuvent pas commencer par un chiffre) et le caractère underscore (_). Les variables suivantes sont valides : compteur, a, _test. Les variables suivantes ne sont pas valides : mon compteur, 2test, bidule>truc.
  • Les noms des variables sont sensibles à la casse des caractères. Ainsi monCompteur, Moncompteur et moncompteur sont trois variables différentes.
  • Sous Processing, les variables sont soumises à ce que l’on nomme un « typage fort », ce qui signifie que le programme a besoin de savoir quelle type de données contient la variable (nombre entier, nombre décimal, caractère, valeur booléenne,…), et qu’il refuse de modifier ce type en cours d’exécution du programme.
  • Une variable créée par le programmeur ne doit pas avoir le même nom qu’une variable système existante. Par exemple mouseY (l’ordonnée de la souris) est une variable système qui ne peut pas être modifiée.
  • Avant de se voir attribuer une valeur, les variables doivent être déclarées (nous y reviendrons).
  • Sous Processing, l’accès à une variable dépend du niveau auquel elle a été déclarée (nous y reviendrons en pratique).

Voici un exemple très basique de manipulation d’une variable :

float couleur;

void setup(){
  couleur=0;
  background(couleur);
}

void draw(){
  if(mousePressed){
    couleur=couleur+0.5;
    couleur=couleur*1.05;
  } else {
    couleur=couleur*0.9;
  }
  background(couleur);
}

Ici la variable se nomme couleur. On remarque que sur la première ligne de mon programme, en marge (c’est à dire à un niveau supérieur) des gestionnaires d’évènement setup() et draw(), je déclare ma variable en commençant par indiquer son type, suivi de son nom. Ainsi en écrivant float couleur;, j’avertis Processing que je vais manipuler une variable de type nombre décimal (float) nommée couleur et que cette variable pourra potentiellement être manipulée par n’importe quelle fonction du programme (c’est le fait d’être déclarée en dehors des fonctions qui lui donne cette propriété). Sans cette déclaration, Processing refuserait d’utiliser la variable couleur.
Dans notre setup() (fonction lancée une unique fois au début de l’exécution du programme), nous associons une valeur (zéro) à notre variable en écrivant ceci : couleur=0. L’opérateur « = » (égal) sert donc à affecter une valeur à une variable.
A=1 signifie donc : A prend la valeur de 1.
Dans notre fonction draw() (qui est lancée de manière régulière), nous faisons un test (if (mousePressed)) qui, on l’a vu précédemment, permet de vérifier si le bouton de la souris est enfoncé. Dans le cas où le bouton de la souris est effectivement enfoncé, la variable couleur se voit appliquer deux traitements. Tout d’abord elle est incrémentée de 0.5 (zéro virgule cinq). Si par exemple elle vaut 100, après ce premier traitement sa valeur sera de 100.5. Ensuite nous multiplions couleur par 1.05. Multiplier par 1.05 (un virgule zéro-cinq) équivaut à ajouter 5% à une valeur. Ainsi, 100*1.05 = 105 ; 200*1.05 = 210; etc. Cette multiplication permet à ma variable couleur de connaître une accélération. Elle connaîtra ces états successifs (que j’arrondis à trois décimales pour ne pas rendre l’énumération de ces états successifs trop indigeste ou trop illisible) : 0.0 ; 0.525 ; 1.076 ; 1.655 ; 2.262 ; 2.900 ; 3.571 ; 4.274 ; 5.013 ; 5.788 ; 6.603 ; 7.458 ; 8.356 ; 9.299 ; 10.289 ; 11.328 ; 12.420 ; 13.566 ; 14.769 ; 16.032 ; 17.359 ; 18.752 ; 20.215 ; 21.750 ; 23.363 ; 25.056 ; 26.834 ; 28.701 ; 30.661 ; 32.719 ; 34.880 ; 37.149 ; 39.531 ; 42.033 ; 44.660 ; 47.418 ; 50.314 ; 53.354 ; 56.547 ; 59.899 ; 63.419 ; 67.115 ; 70.996 ; 75.071 ; 79.349 ; 83.842 ; 88.559 ; 93.512 ; 98.713 ; 104.173 ; 109.907 ; etc. On peut voir sur l’image reproduite au dessus que notre chiffre augmente avec une accélération et non de manière rectiligne.
La condition if (si…) est ici suivie d’une alternative else (sinon – c’est à dire, dans ce cas, si le bouton de la souris n’est pas enfoncé). Dans cette alternative, je multiplie ma variable couleur par 0.9, c’est à dire que je lui ôte 10% (multiplier par 0.9 revient à enlever dix pour cent).
Enfin, après avoir procédé à tous ces calculs, je « repeins » la fenêtre avec la couleur qui correspond au chiffre contenu dans ma variable couleur. Si couleur a la valeur de 10, écrire background(couleur) revient à écrire background(10).

Au passage, revoyons la structure des conditions if :
if ( condition ) { actions à réaliser si la condition est remplie } else { actions à réaliser si la condition n’est pas remplie }
On peut imbriquer des conditions dans les conditions, comme ceci : if (a<10){ if (a<5){ … }}. Il est à noter que dans Processing, toute accolade, tout crochet, toute parenthèse ou toute guillemet ouvertes ( {[(«  ) doivent finir par être fermés ( }]) » ).

void draw(){
  float x = random(100);float y = random(100);
  float rouge = 0; float vert = 0; float bleu = 0;
  if(x<33)
    {rouge=255;}
  else {
    if(x<66)
      {vert=255;}
    else {
      {bleu=255;}
    }
  }
 fill(rouge, vert, bleu);
 ellipse(x,y,10,10);
}

Dans l’exemple ci-dessus, les variables, toutes de type nombre décimal (float) et nommées x, y, rouge, vert et bleu, sont déclarées à l’intérieur de la fonction draw(), ce qui signifie qu’elles seront oubliées sitôt que la fonction aura été exécutée et ne seront pas lisibles par d’autres fonctions. Les variables x et y se voient chacune attribuer une valeur au hasard entre 0 et 100 (random(100)), et les autres (rouge, vert, bleu) se voient attribuer la valeur 0 (zéro).
Nous effectuons ensuite une batterie de tests disant que si x est inférieur à 33 alors rouge prend la valeur de 255. Sinon, si x est inférieur à 66 alors vert prend la valeur de 255. Dans tous les autres cas, bleu prend la valeur de 255. Afin de ne pas faire un script trop long, je n’ai pas fait d’opérations de ce genre se rapportant à la valeur de la variable y, mais on pourrait tout à fait imaginer une telle chose.
Pour finir, nous décrétons que la couleur de remplissage des formes sera fill(rouge,vert,bleu), c’est à dire que le « canal » RGB des rouges sera égal à la valeur de la variable nommée rouge, que le « canal » des verts sera égal à la valeur de vert et que le canal bleu sera égal à la valeur de la variable bleu. Dans la pratique, la couleur sera donc (255,0,0), (0,255,0) ou (0,0,255).
Pour finir, je dessine une ellipse de 10 pixels de diamètre vertical et autant de diamètre horizontal à la position (x, y) que nous avons obtenue au hasard hasard. Le résultat est l’affichage apparemment anarchique de cercles dont la couleur dépend cependant de la position horizontale.
Cette page est consacrée aux variables et il m’a semblé logique d’en utiliser beaucoup, mais j’aurais pu écrire le script ci-dessus en me passant des variables rouge, vert, bleu, comme ceci :

void draw(){
  float x = random(100);float y = random(100);
  if(x<33)
    {fill(255,0,0);}
  else {
    if(x<66)
      {fill(0,255,0);}
    else {
      {fill(0,0,255);}
    }
  }
 ellipse(x,y,10,10);
}

Finissons avec ce sujet extrêmement abstrait en évoquant les types les plus courants de variables que Processing traite :

  • int : les nombres entiers 32 bits compris entre -2147483647 et +2147483647 (0, 10, 121, -15,…).1
  • float : les nombres décimaux (0.129432, 12.1, 145.9999, -0.1,…)2 .
  • boolean : valeur binaire qui a la valeur true ou la valeur false.
  • char : caractère (‘a’, ‘b’, ‘z’, ‘3’). Les caractères s’écrivent entre des apostrophes droites (‘)
  • String : chaîne de caractères (« bonjour »). Les chaînes de caractères s’écrivent entre des doubles-guillemets (« )
  • color : cet objet assez spécifique à processing (tous les langages de programmation n’ont pas une variable de ce type) permet, comme son nom l’indique, de stocker des couleurs pour y accéder ensuite avec diverses fonctions. Je peux par exemple écrire color c = color (255,0,0) au début d’un programme puis, plus tard décider de peindre la scène avec cette couleur c, comme ceci : background(c).
  • enfin, tout objet créé par le programmeur (nous aborderons la programmation « orientée objet » un peu plus tard) peut être utilisé par Processing.
Note : ainsi qu’on me le fait remarquer en commentaires à cet article, mes indications concernant les guillemets « droits » et apostrophes « droites » ne sont pas très claires car mon gestionnaire de blog convertit autoritairement ces caractères dont il se sert d’une autre manière. Je cherche une solution à ce problème d’affichage.

Nous allons voir dans le prochain article comment on peut stocker des variables sous forme de listes (ou tableaux).

  1. Ceux qui savent quel parti en tirer seront heureux d’apprendre qu’il existe aussi des entiers de type byte, codés sur 8 bits (2 puissance 8, donc entre -127 et 127) et des entiers de type long (64 bits, soit 2 puissance 64 nombres différents) [↩]
  2. Il existe aussi des nombres décimaux de type double, codés sur 64 bits [↩]

Processing, dixième cours

décembre 1st, 2008 Posted in Processing | 6 Comments »

Après la souris, parlons du clavier1 . Processing est capable d’«intercepter» (c’est le terme consacré) les évènements du clavier — ce qui est passablement banal. Tout comme dans le cas de la souris, on distingue la frappe d’une touche (keyReleased) de la demi-frappe (keyPressed).
Néanmoins, le clavier et le bouton de la souris fonctionnent de manière passablement différente car le clavier reconnaît la répétition de la frappe, ce qui signifie que si l’on reste le doigt enfoncé sur la touche « a », l’ordinateur se comportera comme si on avait appuyé plusieurs fois de suite sur la touche. Ce paramètre est totalement impossible à maîtriser car il dépend de chaque système d’exploitation et des réglages effectués par l’utilisateur.
Voici un script tout simple qui utilise les deux fonctions d’évènement (keyPressed() et keyReleased()) ainsi que la propriété keyPressed :

void setup(){
  background(255); stroke(255,0,0);
}
void draw(){
  if (keyPressed ){
    line(50,50, random(100),random(100));
  }
}
void keyPressed(){
  background(0);
} 
void keyReleased(){
  background(255);
}

Au démarrage (setup()), je « peins » la fenêtre en blanc et je règle la couleur des traits sur le rouge (255,0,0)
La fonction d’évènement keyPressed() est invoquée lorsque l’on appuie sur le clavier. Elle a pour effet de « peindre » la fenêtre en noir. La fonction d’évènement keyReleased() est invoquée lorsque l’on lache une touche que l’on a enfoncé, et elle a ici pour effet de « peindre » la fenêtre en blanc. Enfin, avec le gestionnaire draw(), qui s’exécute régulièrement, je dis qu’une ligne doit être tracée au hasard sur l’écran si, et seulement si, une touche du clavier est enfoncée (if (keyPressed )).
Notez que, même si elle ne contient rien, une fonction draw() doit impérativement être rédigée dans le script pour que les fonction de gestion d’évènements du clavier soient pris en compte.

Les touches du clavier

Processing est bien entendu capable de savoir quelle touche a été enfoncée. Le résultat de cet évènement est stocké dans deux variables systèmes, key et keyCode.
Avec key, on peut effectuer une vérification de cette manière :

void draw(){
  // gestionnaire vide mais obligatoire
}

void keyReleased(){
  if(key=='r'){
     background(255,0,0);
  }  
  if(key=='v'){
     background(0,255,0);
  }  
  if(key=='b'){
     background(0,0,255);
  }  
}

Avec ce script une série de tests, appelés lorsque l’on touche au clavier (keyReleased()), sont effectués et sont dans certains cas suivis par un changement de la couleur de la scène. Si la touche enfoncée est ‘r‘, alors l’écran est « peint » en rouge (background(255,0,0)), si la touche est ‘v‘, l’écran est peint en vert et si la touche est ‘b‘, il est « peint » en bleu. Les lettres sont ici écrite en minuscules, car pour key, b et B ou v et V ne sont pas les mêmes lettres.
On remarquera que le caractère s’écrit entre deux apostrophes droites ( ‘ – souvent utilisé en remplacement de l’apostrophe typographique (’) ou de la minute (′)).

keyCode s’utilise de la même manière, mais au lieu de contenir un caractère, cette variable contient un code numérique. Par exemple si je veux connaître le keyCode après que la touche ‘a‘ ait été enfoncée, Processing me renverra le chiffre 65. On peut par ailleurs comparer la variable keyCode à un certain nombre de touches spéciales telles que UP (flèche haut), DOWN (flèche bas), LEFT (flèche gauche), RIGHT (flèche droite), ALT, CONTROL et SHIFT (majuscule).

void draw(){
  // gestionnaire vide mais obligatoire
}
void keyReleased(){
  background(255);
  if(keyCode==UP){
    rect(40,0,20,50); 
  }
  if(keyCode==DOWN){
    rect(40,50,20,50);
  }
  if(keyCode==RIGHT){
    rect(50,40,50,20);
  }
  if(keyCode==LEFT){
    rect(0,40,50,20);
  }
}

Dans cet exemple, lorsque la touche du clavier a été utilisée, la scène est « repeinte » en blanc (background(255)), puis une série de tests sont effectués pour savoir si la flèche haut, la flèche bas, la gauche ou la droite ont été utilisée. Pour chacun de ces cas possibles, un dessin différent apparaît à l’écran.

Encore un article assez austère. Les trois suivants seront, j’en ai peur, encore pires.

  1. Le coin culture : tout le monde sait que la souris d’ordinateur est une conquête assez récente (théorie: 1965, brevet: 1968, application industrielle: 1981), mais il est plus rare qu’on se souvienne que le clavier, du moins le clavier couplé à un ordinateur, est à peine plus ancien, puisque son usage informatique ne remonte qu’au début des années 1960. Auparavant, on communiquait avec les ordinateurs à l’aide de cartes perforées ou simplement (?) par câblage. [↩]

Combien ?

novembre 30th, 2008 Posted in Après-cours, Brève | 1 Comment »

Signalé par Geoffrey Dorne, étudiant à l’Ensad et blogueur émerite, une grille (indicative) des tarifs ayant cours dans le domaine du design graphique print ou écran mise en ligne par Laurent Lacroix, jeune designer belge.

La liste très complète (prestations, salaires, honoraires à la journée,…) peut être consultée au format acrobat/pdf sur son site.

Pour établir ses barèmes, l’auteur effectué une enquête auprès de professionnels et a collecté et analysé les annonces d’emploi du secteur.
On n’est pas forcé d’être d’accord avec tous les tarifs (par exemple le prix du développement d’un site Internet dépend énormément de son usage, un supermarché en ligne ou la page « corporate » d’une usine de dalles en plastique n’impliquent pas vraiment le même genre de travail) mais cela constitue une base de travail et, pourquoi pas, de négociations.

Processing 1.01

novembre 30th, 2008 Posted in Brève | 3 Comments »

Le problème de fonctionnement de Processing 1.0 sur certains systèmes non anglo-saxons semble réglé avec la mise à disposition d’une version numérotée 1.01, spécifiquement dédiée à corriger ce problème et annoncée il y a quelques minutes seulement. Je l’ai téléchargée et installée, cette fois, tout fonctionne bien.

Ils y ont pensé

novembre 29th, 2008 Posted in Brève, Personnel | 16 Comments »

Ce qui est bien avec Internet c’est qu’on s’y fait plein d’amis.