skip to main | skip to sidebar
Code 18
Manuel du savoir-faire à l'usage des geeks et des curieux
RSS
  • Accueil
  • Le web au Québec
  • Liens
  • Twitter
  • Facebook
  • À propos

vendredi 30 avril 2010

Mise à jour Ubuntu 10.04 LTS

Publié par Infinite Loop, à 13 h 49 4 commentaires

Hier, comme beaucoup d'autres, j'ai téléchargé Ubuntu 10.04 LTS (Lucid Lynx) pour mettre à jour mon système. J'ai pris l'ISO plutôt que de faire la mise à jour réseau proposée par le gestionnaire d'updates du système d'exploitation. Comme la dernière fois quand je suis passé de Jaunty Jackalope à Karmic Koala, je me suis trompé et j'ai téléchargé l'image ISO du disque standard plutôt que l'alternate install CD.

J'ai suivi les instructions dans la section Upgrading Using the Alternate CD/DVD pour faire la mise à jour directement à partir de l'ISO téléchargé plutôt que de le graver sur un CD. En premier lieu, il faut monter le fichier comme si c'était un drive (à partir d'un terminal) :

sudo mount -o loop ~/Desktop/ubuntu-10.04-alternate-i386.iso /media/cdrom0

Ensuite, on lance la commande suivante pour démarrer le processus de mise à jour.

gksu "sh /cdrom/cdromupgrade"

Pour un novice, quand on regarde la documentation, on peut généralement transcrire les commandes telles quelles et ça fonctionne. Mais pourquoi ne pas les décortiquer pour mieux comprendre ce qu'on fait ?

Charger l'ISO

  • sudo pour exécuter la commande en se substituant à l'utilisateur
  • mount pour monter un système de fichiers
  • -o pour spécifier la liste des options
  • loop permet de faire en sorte que les fichiers du système de fichiers contenus à l'intérieur de l'image soient accessibles
  • ~ est un alias pour indiquer le répertoire utilisateur (si votre utilisateur courant est code18, ce sera traduit par /home/code18
  • le fichier ISO téléchargé
  • /media/cdrom0 représente le point de montage où les fichiers pourront être accessibles
Démarrer le processus de mise à jour
  • gksu est un programme qui permet d'accéder aux droits administrateurs en mode graphique
  • sh pour lancer l'appel à un script Bourne Shell
  • le script à exécuter qui se trouve dans le point de montage
Depuis un certain temps, chaque fois que je vois une commande que j'utilise, je fais l'exercice de la décortiquer et chaque fois j'apprends quelque chose de nouveau. L'important n'est pas de tout se rappeler mais de comprendre ce que ça fait pour arriver à maîtriser son environnement de travail.


Tags: Linux

jeudi 29 avril 2010

Calculer le temps d'exécution d'un script

Publié par Infinite Loop, à 20 h 00 1 commentaire

Quand on programme un script ou une routine, il est généralement d'usage d'avoir une idée sur le temps nécessaire à son exécution. Dans certains cas, on pourra apporter des modifications pour améliorer significativement la performance.

Plusieurs outils existent pour mesurer le temps d'exécution d'un script. Cependant, avec peu de moyens, on peut se tourner vers la bonne vieille méthode de calcul en effectuant deux lectures successives du temps courant.

L'idée est de noter une première fois l'heure au début du script et une seconde fois à la fin. Comme la durée d'exécution peut varier de quelques millisecondes à quelques minutes, nous avons intérêt à utiliser la plus petite unité de mesure du temps pour s'assurer de la meilleure précision.

Voici deux exemples :

JavaScript

var startTime = new Date().getTime();
var elapsedTime = 0;

// votre code à mesurer ici

elapsedTime = new Date().getTime() - startTime;

console.log(elapsedTime);
PHP
$startTime = microtime(true);

$arr = range(1, 1000000);
foreach($arr as $a){
// votre code ici
}

$endTime = microtime(true);
$elapsed = $endTime - $startTime;

echo "Temps d'exécution : $elapsed secondes";
Pour les autres langages, le principe est le même. Trouvez la fonction ou l'objet qui permet d'obtenir le temps réel courant, faites deux lectures et soustrayez les pour obtenir le temps du script ou d'une portion du script. Vous pouvez même les conserver dans un fichier de log pour créer un jeu de statistiques et découvrir où est le bottleneck dans votre processus.


Tags: JavaScript, PHP

mercredi 28 avril 2010

1816, l'année sans été

Publié par Infinite Loop, à 18 h 48 2 commentaires

Avec la température qu'on a eu au Québec depuis hier, c'est à se demander où est passé le beau temps. De la neige le 27 avril et ce matin à Montréal ! Ok, juste un peu pour créer un mince tapis blanc et cacher la pelouse qui avait pris ses couleurs suite au beau weekend de 20 degrés. Quand même, tout était en place pour croire que le chapitre nommé hiver était bel et bien terminé.

L'humanité a connu pire. Saviez-vous que l'année 1816 est surnommée l'année sans été ? Paraît-il qu'à Québec, trente centimètres de neige furent observés au début du mois de juin. Juste pour dire que les perturbations climatiques ne datent pas nécessairement du 21ème siècle.

Ce qui m'amène à vous inviter à faire l'écoute de la pièce 1816, The Year Without a Summer du groupe américain Rasputina, tiré de l'album Oh Perilous World (2007). Tout ça explique peut-être pourquoi "Mary Shelley had to stay inside and she wrote Frankenstein" ?


Tags: Musique, Saviez-vous que

Chansons à 4 accords

Publié par Infinite Loop, à 08 h 44 0 commentaire

Selon Axis of Awesome, c'est facile de composer une chanson pop : la plupart comprennent uniquement 4 accords. Du moins, c'est ce que "Chicken Little" (à droite) tente de nous démontrer.

Voici une version de la vidéo qui comprend le titre de chaque pièce. C'est étonnant de voir les similitudes. Un numéro très réussi !



Les 4 même accords ? Peut-être un hasard mais comme dirait Perceval dans Kaamelott : c'est pas faux.


Tags: Humour, Musique

mardi 27 avril 2010

Éviter de perdre le contenu rédigé sur le web

Publié par Infinite Loop, à 17 h 47 0 commentaire

Les modules de gestion de contenu pour le web ont toujours été très populaires. Toutes les entreprises de développement web créent leurs propres CMS, d'autres utilisent Joomla et tous les clients veulent en utiliser, surtout pour ne pas avoir à se casser la tête avec le HTML.

Quand certains clients se plaignent qu'ils font de la rédaction par l'interface web et qu'ils perdent leur données non-sauvegardées, je peux comprendre que c'est fâcheux d'avoir à recommencer. Certains s'accrochent dans un lien ou le bouton back du fureteur, d'autres possèdent une souris dont un bouton latéral configurable permet de revenir à la page précédente. Mais le plus souvent, c'est que le curseur est hors focus de la boîte d'édition et que la personne appuie sur la touche backspace du clavier pour retirer un bout de phrase et hop!, il revient à la page précédente et le contenu est perdu.

C'est là qu'on peut intervenir en tant que programmeur. Il est possible de contrôler en partie les actions de navigation sur le fureteur à l'aide de l'événement onBeforeUnload. Du moins, c'est ce que j'ai mis en place et qui fonctionne au moins sur Firefox 3.x et Internet Explorer 8.

Il suffit d'attacher une fonction à l'événement onBeforeUnload que le navigateur pourra interpréter au moment où l'utilisateur changera de page (volontairement ou non).

Avec le framework Prototype (optionnel) :

Event.observe(window, 'beforeunload',
function(event){
event.returnValue = "Le contenu n'est pas enregistré.";
}
);
Tout ce que ça fait ici, c'est de spécifier la raison pour laquelle le popup est affiché en personnalisant le message et d'attacher la fonction à l'événement. Le message retourné sera inséré dans le message par défaut du fureteur qui utilisera la langue d'installation sur le poste du client.

En français, le message se lira comme suit (Firefox) :

Voulez-vous vraiment quitter cette page ?
* VOTRE MESSAGE SERA INSÉRÉ ICI *
Appuyez sur OK pour continuer, ou Annuler pour rester sur la page actuelle.

Une fois cet événement initialisé, la fenêtre de confirmation sera affichée dès qu'on tentera de changer de page, y compris si on tente de soumettre le formulaire pour l'enregistrement. C'est pourquoi on pourra désactiver l'événement au moment de l'envoi pour ne pas qu'il achale l'utilisateur avec le popup.

Avant de soumettre le formulaire, contrôlez l'envoi par JavaScript et ajoutez l'instruction suivante extraite de Prototype avant d'invoquer submit() sur le formulaire :
Event.stopObserving(window, 'beforeunload');
Voici les équivalents en JavaScript pur, au cas où vous n'êtes pas friand de framework JavaScript :
window.onbeforeunload = function(){
return "Le contenu n'est pas enregistré.";
}
Pour désactiver l'événement avant de poster les données, vous pouvez assigner une fonction vide à onbeforeunload;
window.onbeforeunload = function(){}
Pour les blogueurs qui me lisent et qui utilisent Blogspot, c'est exactement cette technique que la plateforme utilise, mis à part qu'ils ont intégré un mécanisme d'enregistrement automatique de brouillon qu'on peut récupérer facilement si un problème survient.


Tags: JavaScript

lundi 26 avril 2010

Épileptique neuf à vendre

Publié par Infinite Loop, à 18 h 52 1 commentaire

Vous savez à quel point je suis fan de Failblog. C'est toujours avec un brin d'humour qu'on découvre des échecs hors-contextes qui nous font sourire pendant les pauses au bureau. Et quand j'ai vu Frédéric Harper sur Twitter dire qu'il avait fait un lapsus comique, je n'ai pas pu m'empêcher de lui envoyer cette annonce Kijiji qui m'a bien fait rire et que j'ai trouvé sur FailQc.com, un penchant francophone de Failblog dédié à ce qu'on trouve au Québec.

Épileptique neuf à vendre pour cause de manque de place dans le condo. Elliptique peut-être ?



Au moment de la publication de ce billet, 681 curieux s'étaient déjà pointés sur la page en question (toujours en ligne ici).

Sinon, d'autres mentions honorables que j'aime bien :

  • En page d'accueil de Tequila Taco House, visite le site en version Françoise
  • La preuve de flaque ami de sport
  • Une pancarte assez incroyable vue sur Google Street View (Montréal)
  • Le vandalisme sur la pancarte du Champ des Buttes me fait penser à mon histoire de Grosses-Roches
Enfin, n'hésitez pas à leur soumettre vos trouvailles.


Tags: Curiosités, Humour

dimanche 25 avril 2010

Formule pour calculer la densité de la bière

Publié par Infinite Loop, à 13 h 03 1 commentaire

Il y a quelques années, ma blonde et moi avons décidé de tenter l'expérience de brasser notre propre bière à la maison. Nous avons acheté l'équipement nécessaire dont une cuve et une tourie d'une capacité de 20 litres, ce qui nous a donné environ 55 ou 66 bouteilles de 330 cl (coût de production d'environ 30 sous par bouteille).

Pour une première expérience, le résultat était surprenant. C'était une bière brune de type ale anglaise qui goûtait un peu comme la Bass. Hier soir, en recevant des amis à souper, nous parlions de la fabrication de vin et de bière et ça m'a donné le goût d'essayer et j'ai ressorti mes notes que j'avais pris à l'époque.

Comme le processus de fabrication est artisanal, on est toujours curieux de connaître le pourcentage d'alcool contenu dans la bière. Pour calculer la densité, il faut utiliser un densimètre.

Sachant qu'un litre d'eau a une masse de 1 kg, la densité de l'eau est de 1,000. Or, l'alcool pur a une densité de 0,792. Ce qui veut dire qu'un mélange d'eau et d'alcool aura une densité se situant entre 0,792 et 1,000. Par contre, au début du processus de fabrication, le moût de bière qui contient le sucre possède une densité plus élevée à 1,000. Lorsque celui-ci se sera transformé en alcool, la densité diminuera.

Mesure initiale du moût de bière : 1,040
(1,040 - 1,000) x 1000 = 40 degrés

À partir de la densité initiale, on peut avoir un aperçu du pourcentage d'alcool maximum qu'on obtiendra :

40 degrés / 7,6 = 5,26 % d'alcool

Lorsque la fermentation est terminée, on peut procéder à la mesure finale de la densité : 1,005.

En soustrayant la densité initiale et la densité finale, on obtient l'atténuation :

1,040 - 1,005 = 0,035, donc 35 degrés

L'atténuation divisée par une constante de 7,6 nous donne le pourcentage d'alcool contenu dans le mélange :

35 / 7,6 = 4,60 % d'alcool

Bien entendu, d'autres facteurs peuvent contribuer à faire varier légèrement le pourcentage, comme par exemple la température ambiante. Mais comme on brasse la bière de façon artisanale sans avoir l'intention de vendre le produit, nous laisserons le soin aux scientifiques de calculer le tout avec plus de précision. De notre côté, nous nous contenterons de déguster notre création avec des amis.


Tags: Marché des saveurs

Citation no. 79 sur l'éducation

Publié par Infinite Loop, à 10 h 05 0 commentaire

Je n'ai jamais laissé ma scolarité interférer avec mon éducation.

- Mark Twain


Tags: Citations

samedi 24 avril 2010

Rework, un livre plein de gros bon sens

Publié par Infinite Loop, à 07 h 40 3 commentaires

En entête du livre Rework, une recommandation aussi accrocheuse par Seth Godin place la barre haute avant même d'avoir débuté la lecture : Ignore this book at your own peril. Est-ce que le livre est à la hauteur des attentes et en vaut-il les 17$ que j'ai dépensé sur Amazon ? De prime abord, je répondrais oui car il est plein de bons sens. Mais il ne faut pas s'attendre à des révélations extraordinaires.

Jason Fried et David Heinemeier Hansson décrivent en chapitres concis l'approche qu'ils ont appliqué au sein de leur entreprise 37signals (créateurs de Ruby on Rails), une PME à succès de 20 employés et qui génère quelques millions de revenus à ce qu'on dit. Appliquer leurs conseils n'est pas un gage de réussite pour autant. Comme ils le disent eux-même, ça vaut pour eux et il ne faut pas tenter de les imiter en tout point.

Il faut voir ce livre comme un guide qui tend à remettre en questions les notions académiques traditionnelles de la gestion d'entreprise. Chaque sujet présenté mérite qu'on se pose des questions face à notre approche du travail et c'est ce qui est encouragé par les auteurs. Faire à notre façon quoi qu'en disent les autres.

Travaillant moi-même pour une PME en informatique, j'ai trouvé leurs commentaires pertinents et souvent applicables à notre situation. Par exemple :

Resumé are ridiculous
Un CV est souvent bourré de demi-vérités. Oh que oui. J'ai vu le curriculum vitae d'un ancien employé qui a quitté il y a plusieurs années et il indiquait dans ses réalisations avoir conçu avec nous le site d'une vedette de la scène artistique québécoise alors qu'à mon souvenir, il avait à peine travaillé une heure sur le projet pour corriger un bogue. Un autre s'attribuait tous les mérites de prix que l'entreprise avait remporté quelques années avant son arrivée dans l'équipe!

Years of irrevelance
Toujours relatif. 5 ans d'expérience dans une entreprise qui n'évolue pas ou présente peu de défis peut être équivalent à 1 an dans une autre.

Forget about formal education
Il faut que des gens efficaces soient en place. J'ai vu des bacheliers en informatique au dessus de leurs affaires et qui n'arrivaient pas à la cheville du talent de programmeurs juniors sortant du collège.

Une mention spéciale aux leçons apprises à l'école qu'il faut oublier une fois sur le marché du travail. Quelques exemples :

  • Plus un document est long, plus il importe
  • Utiliser les grands mots est impressionnant / imposant
  • Il faut écrire un nombre minimum de mots pour faire le point et se faire comprendre
Culture
Une table de babyfoot ne fait pas parti de la culture d'entreprise.

Politique
Une entreprise devrait commencer à écrire une politique interne lorsqu'il y a un abus général dans l'équipe. Autrement, mieux vaut avertir et régler le problème avec l'individu fautif et ne pas pénaliser le reste de l'équipe. De toute façon, qui lit les politiques ?

ASAP is poison
Un mot parmi tant d'autres à éliminer. On est déjà au courant que le client aimerait qu'on voit à sa demande le plus rapidement possible. Si tout est considéré urgent, quand saura-t-on si ce l'est vraiment cette fois-ci ? Ça me fait penser à l'analogie que j'ai déjà fait avec la mécanique automobile.

Press release are spam
On dira ce qu'on voudra, c'est une forme de message non sollicité. Il faut faire en sorte que le client et les médias s'intéressent à nous autrement.

Inspiration
Un de mes préférés. Les idées sont immortelles. L'inspiration possède une date d'expiration. C'est un élément magique, un multiplicateur de productivité, un motivateur. Nul besoin d'en dire plus.

Ce n'est que quelques exemples qu'on retrouve au fil des pages de Rework. Ça remet les idées en place pour nous permettre de focusser au bon endroit, sur les vrais problèmes. Bien que le livre compte 270 pages, les auteurs disent qu'ils ont coupé le contenu de moitié. Si on ne compte pas les nombreuses images qu'on retrouve une page sur deux, ils auraient pu en faire un livret de 100 pages ou moins. Mais si vous jetez un coup d'oeil aux esquisses des illustrations de Rework, on comprendra qu'elles ont leur place et qu'elles sont bien choisies. Personnellement, j'ai trouvé que ça allégeait la lecture et qu'en feuilletant les pages pour retrouver les passages repris pour écrire ce billet, ce sont les images qui me permettaient de retrouver rapidement les sujets. Comme quoi une images vaut mille mots.

Je termine en vous invitant à poursuivre votre lecture sur le blogue Signal vs. Noise de 37signals et à visiter leurs archives.


Tags: Livres

vendredi 23 avril 2010

Servez à ce monsieur une bière et des kiwis

Publié par Infinite Loop, à 21 h 11 4 commentaires

Je profite de l'entracte de ce qui pourrait être le dernier match de la saison de nos Glorieux (note pour les lecteurs hors-Québec : club de hockey Canadiens de Montréal) pour parler d'un petit truc curieux qui apparaît dans Microsoft Word. Ce n'est pas tout à fait un easter egg mais ça mérite au moins une mention :

  1. Ouvrez Microsoft Word (2003 - 2007)
  2. Entrez ceci : =rand(10,1)
  3. Regardez ce qui apparaît dans la page
On voit apparaître un pangramme, c'est-à-dire une phrase qui contient toutes les lettres de l'alphabet. Les paramètres de l'expression rand(10,1) peuvent être remplacés par autre chose puisqu'il s'agit d'une fonction indiquant le nombre de lignes et le nombre de répétitions par ligne pour générer du texte de remplissage (ne pas confondre avec Lorem Ipsum). Ici, on veut 10 lignes avec 1 répétition par ligne.

En anglais, la phase est : The quick brown fox jumps over the lazy dog.

En français, ce n'est pas tout à fait un pangramme car la phase choisie contient presque toutes les lettres : Servez à ce monsieur une bière et des kiwis.

Pour utiliser toutes les lettres, la phrase aurait pu être : Portez ce vieux whisky au juge blond qui fume.

Pour en savoir plus :
  • Une phrase commune pour tester les machines à écrire et les claviers d'ordinateurs
  • Insérer un exemple de texte dans un document Word
Mise à jour d'après-match : le CH a gagné ce qui veut dire qu'il y en aura au moins un autre lundi prochain !


Tags: Easter Eggs

jeudi 22 avril 2010

Reporter l'interprétation JavaScript avec defer

Publié par Infinite Loop, à 21 h 13 5 commentaires

Jusqu'à maintenant dans mon travail, j'ai optimisé les sites web en utilisant les suggestions provenant soit de l'extension YSlow de Yahoo!, soit de Page Speed de Google (soit dit en passant, les deux sont excellents pour l'apprentissage de bonnes pratiques). Compresser les librairies JavaScript et CSS (avec YUI Compressor), compression HTTP avec gzip, minimiser le nombre de requêtes HTTP et utiliser le cache ne sont que quelques exemples qui permettent d'accélérer le chargement des pages.

En toute honnêteté, le score maximum (depuis que je l'utilise) que j'ai obtenu dans l'analyse Page Speed sur la page principale d'un de mes projets avancés a été de 88/100. Impossible d'atteindre la perfection malgré tout le fine tuning.

Un des points proposés par PageSpeed est d'utiliser l'attribut defer dans la balise script des librairies JavaScript attachées à la page. Ceci permet d'indiquer au fureteur qu'il peut choisir de ne pas attendre que le code JavaScript soit fini d'être interprété pour poursuivre le chargement de la page, ce qui accélère l'affichage du contenu HTML. Bien entendu, il faut que le script ne crée aucun contenu, par exemple aucune instruction document.write().

Je n'avais pas l'habitude d'utiliser defer car seul Internet Explorer le supportait (depuis la version 4). Mais plus récemment, Firefox 3.5 et les versions suivantes tiennent compte de l'attribut defer. Sans surprise, des statistiques que j'ai consulté montrent que le pourcentage des développeurs qui utilisent defer est encore assez faible.

Faisons un essai avec le snippet HTML suivant :

<div id="myDiv"></div>
<button type="button" id="btn">OK</button>
Et un peu de JavaScript (avec jQuery) :
<script type="text/javascript" src="js/jquery-1.4.min.js"></script>
<script type="text/javascript">
$j = jQuery.noConflict();
$j(document).ready(initialize);

function initialize(){
$j('#myDiv').html('Hello World');
$j('#btn').click( function(){ alert('Click'); } );
}
</script>
  • Si je place un attribut defer="defer" sur le chargement de la librairie, la console Firebug de Firefox me lance l'erreur : jQuery is not defined. C'est normal, elle devrait être chargée à la fin, après le bloc de code JavaScript.
  • Si j'ajoute defer="defer" au bloc de code, je n'ai pas plus de succès, la même erreur se produit.
  • Si je retire defer du chargement de la libraire, tout se passe bien.
Quel est l'avantage de defer si le code JavaScript de la page est dépendant de la librairie ? En fait, le secret réside dans l'extraction du code JavaScript de la page vers un fichier externe .js.
<script type="text/javascript" src="js/code-de-la-page.js" defer="defer"></script>
De cette façon, on peut reporter l'interprétation de plusieurs scripts dépendants sans rencontrer de conflit. Mais le gain demeure assez peu significatif.


Tags: Extensions Firefox, JavaScript

mercredi 21 avril 2010

La cuillère est une arme dangereuse

Publié par Infinite Loop, à 16 h 37 0 commentaire

Une personne qui connaît bien mes goûts pour l'absurde m'a recommandé le visionnement de ce film : The Horribly Slow Murderer with the Extremely Inefficient Weapon par Richard Gale.

L'histoire épique de la rencontre d'un homme avec ce qui pourrait être l'assassin le plus impitoyable de tous les temps. Il te tuera, même si ça doit prendre le reste de ta vie !

Prévoyez 10 minutes pour regarder la vidéo, ça en vaut le coût.



Déjà vu par plus de 4 millions de personnes sur YouTube, je me suis : coudonc, j'étais où quand le buzz a eu lieu ? Coté 8.1 sur 10 sur IMDB.


Tags: Club Vidéo

Je suis un programmeur ninja !

Publié par Infinite Loop, à 08 h 37 3 commentaires

Il n'y a pas si longtemps, quand on parlait de postes de développeurs dans les technologies de l'information, on pouvait comprendre la classification de deux façons. Les grosses boîtes fonctionnaient par niveaux hiérarchiques monotones (level 1, level 2, level n) alors que les plus petites préféraient utiliser les termes junior, senior et gourou (guru).

Depuis quelques années, on a vu apparaître des buzzwords spécifiques au monde de la programmation. Dorénavant, chacun peut s'auto-proclamer programmeur ninja, samurai ou même rockstar. Même les offres d'emplois ont adopté ces nouvelles appellations. Pourquoi est-ce qu'on se donne des titres si farfelus ? Est-on vraiment à la recherche d'un titre ou c'est pour ridiculiser la chose ?

Imaginez si c'était appliqué à d'autres domaines, comme les dentistes ou la comptabilité. Votre préparateur de déclaration de revenus se qualifie-t-il de sumo du calcul fiscal ? C'est pas sérieux...

Le titre est tellement peu important, c'est le résultat qui compte. Mais tant qu'à faire un peu de dérision, quels autres titres pourraient s'appliquer à notre domaine ?


Tags: Le coin du geek

lundi 19 avril 2010

Attention aux extensions multiples sur Apache

Publié par Infinite Loop, à 18 h 18 1 commentaire

J'aimerais attirer votre attention sur une particularité du serveur web Apache que j'ai de la difficulté à m'expliquer. Quelle est l'utilité d'autoriser plusieurs extensions aux fichiers déposés sur le serveur ?

Ce que je veux dire, c'est que normalement, si un fichier se nomme cornichon.jpg, Apache déduit immédiatement que le handler par défaut qui le prendra en charge est celui pour les images. Du même coup, on s'attend à ce que page.php.jpg soit reconnu comme un jpeg. Le reste fait parti du nom de fichier. Mais la documentation d'Apache 2.2 indique qu'un fichier peut être nommé welcome.fr.html ou welcome.html.fr et qu'il ne fera pas la différence puisque l'extension .fr est inexistante et qu'aucun mime-type ne correspond. Il en déduit qu'il doit utiliser l'extension alternative, soit .html.

Ce qui, d'une certaine façon, ouvre la porte à une vulnérabilité. Supposez que vous autorisiez l'envoi de fichier sur le serveur par les visiteurs. Peut-être aurez-vous tendance à vérifier le type de fichier envoyé en comparant l'extension avec une liste d'extensions proscrites ? Vous ne désirez surement pas qu'ils puissent envoyer des fichiers .php qui s'exécuteraient sur le serveur ! Mais si le visiteur nomme son fichier page.php.code18, l'extension .code18 n'a pas de handler reconnu et Apache tentera de le résoudre en tant que script PHP. Bonjour le désastre.

Mes recommandations :

  • comparer l'extension principale avec une liste d'extensions autorisées avant d'accepter le fichier (celles prises en charge par les handlers)
  • vérifier le mime-type du fichier
  • conserver un seul point dans le nom du fichier et remplacer les autres (par exemple avec un tiret ou un underscore)
Connaissez-vous un moyen de désactiver cette directive d'Apache ? Quels autres moyens utilisez-vous pour contrer cette faille ?


Tags: Apache

dimanche 18 avril 2010

Formater un champ monétaire en JavaScript

Publié par Infinite Loop, à 09 h 40 0 commentaire

Dans plusieurs langages de programmation, quand vient le temps de manipuler des valeurs monétaires, on doit tenir compte d'un certain nombre de décimales. En SQL, plusieurs préféreront utiliser le type numeric en indiquant la précision plutôt que de prendre le type money qui se limite à 4 décimales.

Quand le montant contient plus de 2 décimales, on voudrait certainement tronquer celles-ci pour obtenir un nombre sous cette forme : 22,58 $. On pourrait utiliser le truc classique de multiplier par 100 pour obtenir une valeur entière et de le diviser à nouveau par 100 pour conserver deux chiffres après la virgule :

var num = 22.5812;
console.log(Math.round(num*100)/100); // 22.58
Dans certains cas, ça fait l'affaire pour éliminer les décimales superflues. Le hic, c'est que les décimales se terminent par zéro, elles seront aussi tronquées et ne seront pas affichées à l'écran :
var num = 22.5009;
console.log(Math.round(num*100)/100); // 22.5
Ce n'est pas tout à fait le résultat attendu. Les 0 sont essentiellement inutiles dans le nombre, sauf qu'on voudrait afficher les zéros non-significatifs dans un montant monétaire. Et c'est la même chose si la valeur est entière :
var num = 22.00; // ou 22
console.log(Math.round(num*100)/100); // 22
J'ai vu plusieurs façons de faire apparaître les zéros par programmation mais je vous suggère une fonction built-in toute simple de l'objet Number qui vous évitera d'écrire plusieurs lignes de code : toFixed(). Il suffit d'indiquer le nombre de décimales à conserver pour le résultat final :
num = 22;
console.log( num.toFixed(2) ); // 22.00

num = 22.5;
console.log( num.toFixed(2) ); // 22.50

num = 22.4949;
console.log( num.toFixed(2) ); // 22.49

num = 22.5456;
console.log( num.toFixed(2) ); // 22.55

num = 22.9900;
console.log( num.toFixed(2) ); // 22.99
Un autre point qu'il faut penser quand on travaille avec des champs monétaires dans l'interface, c'est que l'utilisateur pourrait avoir tendance à saisir une virgule à la place du point. Assurez-vous de faire le remplacement avant d'effectuer des calculs ou d'insérer la valeur dans la base de données.
console.log(9.99 * 2); // 19.98
console.log(9,99 * 2); // oups, 9198 !


Tags: JavaScript

Citation no. 78 sur la vieillesse

Publié par Infinite Loop, à 08 h 37 0 commentaire

Un archéologue est un époux rêvé : plus sa femme vieillit, plus il s'intéresse à elle.

- Agatha Christie


Tags: Citations

samedi 17 avril 2010

Étrange détail dans les Fraggle Rock

Publié par Infinite Loop, à 08 h 39 1 commentaire

Il y a quelques années, la CBC (Canadian Broadcasting Corporation), le volet anglophone de la Société Radio-Canada, avait rediffusé à la télévision des épisodes de l'émission pour enfants Fraggle Rock.

Étant fan lorsque j'étais petit, je m'étais mis à en regarder un pour me remémorer des souvenirs (je possédais toute la collection des figurines incluses dans les Joyeux Festins vendus chez McDonalds). En portant un regard avec mes yeux d'adulte, j'avais cru avoir repéré un détail amusant mais troublant.

Gobo, un des Fraggle, sortait de son univers par un tunnel qui débouchait à l'atelier de Doc pour y récupérer une carte postale de Uncle Traveling Matt. Afin de se cacher du chien Sprocket et pour ne pas être aperçu par son propriétaire, la marionette se tenait derrière des boîtes en carton dont une semblait arborer le logo de la SAQ (Société des alcools du Québec) ! Du moins, j'avais l'impression que ça lui ressemblait vraiment. Remarquez que je peux me tromper mais j'ai toujours voulu éclaircir ce mystère.

Sachant que la production de la série s'est faite à Toronto (Ontario, Canada), la province voisine du Québec aurait bien pu glisser par mégarde une de ces boîtes dans le décor. Ce qui révélerait un petit problème d'éthique.

J'aimerais retrouver cette séquence. Est-ce que quelqu'un possède les DVD et pourrait me confirmer qu'il a vu la même chose ? Un screenshot serait apprécié.

En attendant une réponse, je vous laisse avec le vidéo du thème francophone de l'émission.



Down at Fraggle Rock!


Tags: Curiosités, Musique

vendredi 16 avril 2010

Pages web en unicode (UTF-8)

Publié par Infinite Loop, à 17 h 28 1 commentaire

Vous êtes familier avec le caractère � ? Les mots dans votre page web s'affichent comme ceci "développement", avec des ?, des ou encore des carrés remplacent certains caractères ? C'est que vous avez un problème d'encodage ou de jeu de caractères.

Souvent, c'est parce que le charset n'est pas spécifié correctement dans la page. Assurez-vous autant que possible d'utiliser l'encodage UTF-8 et de placer ce meta tag (doit être le premier pour être certain que l'interpréteur en tienne compte) :

<meta http-equiv="Content-Type" content="text/html;  charset=utf-8" />
Je vous recommande aussi d'enregistrer vos fichiers sources dans le même encodage.

Mais ASCII, ANSI, ISO-8859-1, ANSII, Unicode, UTF-8, UCS-2... Comment décortiquer le tout ?

Je vous donne une piste de solution en vous renvoyant à un article intéressant qu'on peut trouver sur le blogue de Joel Spolsky et que j'ai relu cette semaine : The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!). Une traduction française est aussi disponible.


Tags: Intégration

jeudi 15 avril 2010

Death Star Logo de AT&T

Publié par Infinite Loop, à 16 h 44 0 commentaire

Ce midi, sur mon heure de lunch, je lisais la plus récente édition de 2600, The Hacker Quarterly (vol.37, no.1), mon premier numéro à vie que j'ai acheté par curiosité de voir ce qu'il présentait (je suis pourtant loin d'être un hacker).

Dans la section Speak (courrier des lecteurs, page 43), "Grumble" fait mention du Death Star Logo qui fait référence à une compagnie de communications. Ne sachant pas de quoi il était question (surtout qu'ils sont discrets au Québec), une recherche sur Google m'a permis de comprendre qu'il parlait d'AT&T.

En effet, leur ancien logo, dont le design remonte à 1983 fait référence à l'Étoile de la mort de Star Wars. Simple hasard ou clin d'oeil bien placé ?

Depuis, ils ont changé de logo mais certains se sont amusés à le transformer pour qu'il colle encore à son surnom.

En fouillant un peu, j'ai vu qu'il y avait des rencontres de lecteurs du magazine 2600 à Montréal qui se tiennent les premiers vendredi de chaque mois au 1000 de la Gauchetière. Pourquoi avoir choisi l'édifice Bell pour les réunions du 2600? Comme le groupe l'explique sur son site web, si on considère les débuts du hacking et phreaking qui a débuté sur les lignes de téléphone, avoir choisi l'édifice Bell est symbolique (voir Captain Crunch).

Quelqu'un est déjà allé à une de ces rencontres (à Montréal ou ailleurs) ? À quoi peut-on s'attendre ? J'ai vu qu'il existait un site qui disait détester 2600 et qui remettait en question sa crédibilité et sa raison d'être : 2600 sucks. Qu'est-ce que vous en pensez ? Vous êtes d'accord ou non avec cette initiative ? Pour ma part, les trucs de conspirations me font un peu trop penser au livre Jaune no. 5 écrit par des hurluberlus. Ce qui me fait penser que si vous voyez ce livre, dites-vous qu'il vaut mieux mettre son argent ailleurs.


Tags: Curiosités

David le gnome, version métal

Publié par Infinite Loop, à 08 h 43 0 commentaire

Je viens d'en faire mention sur Twitter mais comme j'en ris encore, je me dois de le publier sur mon blogue pour le partager avec vous. C'est un vidéoclip reprenant le thème de David le Gnome en version métal, interprété par le groupe italien Elvenking.



Il paraît que c'était un poisson d'avril :-)


Tags: Musique

mercredi 14 avril 2010

Améliorer la performance d'une boucle en PHP

Publié par Infinite Loop, à 18 h 10 1 commentaire

Une chose que je vois souvent dans du code PHP, c'est de faire une boucle for avec comme condition le count(array) à l'intérieur.

for($i=0 ; $i < count($arr); $i++)
Une explication qu'on m'a donné pour utiliser ce moyen est qu'on n'a pas à déclarer une variable pour stocker le résultat du count() et qu'on sauve une ligne de code. D'un point de vue, c'est vrai, mais d'un autre, ça peut affecter la performance selon l'application que vous en faites, sans compter qu'on n'est pas à quelques bytes de mémoire vive près.

Le vrai désavantage ici est qu'à chaque itération de la boucle, il doit rappeler la fonction pour vérifier la valeur comptée qui correspond au nombre de résultats de l'array (qui ne devrait pas changer en cours de route). Si on avait d'abord extrait le total, on optimiserait la performance, même si elle peut sembler minime.

Pour illustrer ce qui se passe, je vais créer un array qui contient 1 million de valeurs et je vais créer une boucle vide qui fera l'itération sur chaque indice. Ceci nous permettra de vérifier le temps d'exécution avant et après l'optimisation. Pour calculer ce temps, je vais utiliser une astuce qui consiste à obtenir le temps microtime() avant et immédiatement après la boucle.
// générer 1 million d'enregistrements
$arr = range(1, 1000000);

// obtenir le temps de départ
$start = (float) array_sum(explode(' ',microtime()));

// boucle vide
for($i=0 ; $i < count($arr); $i++){
// on ne fait rien ici...
}

// obtenir le temps de fin
$end = (float) array_sum(explode(' ',microtime()));

// imprimer à l'écran la différence
echo sprintf("%.4f", $end-$start) . " secondes";
Avec le count() dans la condition, j'obtiens un résultat de 0.5964 secondes.

Maintenant, appliquons un changement mineur. Après avoir généré l'array initial, on peut compter une seule fois le nombre d'éléments dans l'array :
$arr = range(1, 1000000);
$count = count($arr);
Ensuite on remplace la condition de bris de la boucle pour utiliser la variable :
for($i=0 ; $i < $count ; $i++)
On exécute le script à nouveau. Le résultat : 0.1835 secondes, soit 3 fois plus rapide (dans le cas de mon ordinateur personnel). C'est certain que si vous avez un tableau de petite taille, ça ne fera pas une grande différence mais elle sera notable dès que le nombre d'itérations sera élevé.

Dans ce cas-ci, mon exemple était en PHP mais ça vaut aussi pour tous les autres langages. Faites-le par principe pour conserver les meilleures pratiques en tout temps.


Tags: PHP

mardi 13 avril 2010

FIMAV, John Zorn et la poutine

Publié par Infinite Loop, à 18 h 37 3 commentaires

J'ai reçu hier soir un courriel intéressant d'un lecteur (Ben, pour le nommer) avec qui, de toute évidence, je partage des intérêts musicaux communs. Tout comme moi, il aime John Zorn et l'a vu à quelques reprises en spectacle. Seulement, lui c'était au Festival international de musique actuelle de Victoriaville (Fimav), un événement pour lequel, malheureusement, j'ai toujours "choké" à aller assister malgré la courte distance qui le sépare de Montréal (environ 2 heures).

Avant d'aller plus loin, je dois préciser que le but de son message était de partager le lien d'un site web d'un artiste qui participera au festival et qui constitue en soi une prouesse technique en JavaScript : Shalabi Effect. Admirez le chargement, la transition et l'affichage de l'image en ASCII (sélectionnez en une portion pour constater la taille des caractères). Mauvais pour le référencement mais excellent pour le bouche à oreille !

Voilà c'est dit. Vous pouvez poursuivre la lecture si la musique vous intéresse.

Dans son message, il me dit qu'il a vu 2 fois Fantômas en spectacle et John Zorn à 3 reprises. Chanceux! La dernière fois qu'on m'a dit quelque chose de semblable, c'était une employé de la Bouquinerie du Plateau à qui je jasais et qui me disait qu'elle venait juste d'aller le voir à "Victo". À ce moment-là, j'avais un brin de jalousie en moi. Par la suite, j'ai pu assister à une performance de Zorn avec Masada en 2006 au festival de Jazz de Montréal (Théâtre Maisonneuve) et une autre fois dans une salle obscure dans Lower East Side à New York, The Stone. C'était assez particulier car la salle est minuscule et plusieurs artistes viennent faire de l'expérimentation. Il y en avait un qui a improvisé quelque chose en lançant dans les airs son fil de guitare qui produisait une rythmique lorsqu'il retombait. Essayez d'imaginer la scène !

John Zorn est un personnage difficile à cerner. Même à travers le documentaire Bookshelf On Top Of The Sky, c'est à peine suffisant pour avoir une vague opinion de ce virtuose de la musique. Dommage car même si certaines séquences sont bonnes, la réalisatrice Claudia Heurermann n'aide pas la cause puisqu'il y a à peu près autant de footage d'elle que de son sujet, ce qui a tapé sur les nerfs de la plupart de ceux que je connais qui ont visionné le DVD.

Pour en revenir au Fimav, qui aura lieu du 20 au 23 mai 2010, John Zorn sera absent cette année (zut) mais j'ai vu dans la programmaton que René Lussier présentait un projet avec Michel Langevin de Voivod. Je ne sais pas à quoi on peut s'attendre mais ça devrait être spécial. Je me souviens avoir entendu un truc de Lussier assez expérimental qui me faisait penser à Steve Reich (The Cave je crois, allez savoir pourquoi!). Ça s'appelait Le trésor de la langue.

Une autre promesse que je me suis fait si je passe dans le coin, ce sera d'aller manger une poutine à la cantine Annie. Selon plusieurs personnes, parait-il que c'est un détour obligé.

Cantine Annie
27, boul. Arthabaska Est
Victoriaville
819-751-2756

Cela dit, merci Ben pour ton commentaire.


Tags: Club Vidéo, JavaScript, Musique

lundi 12 avril 2010

Service de géolocalisation GeoBytes IP Locator

Publié par Infinite Loop, à 18 h 26 0 commentaire

Voici une alternative intéressante à l'extension PHP GeoIp de MaxMind. Contrairement à cette dernière, ce qu'il y a de bien, c'est qu'il n'y a absolument rien à installer car seule une requête HTTP GET est nécessaire pour obtenir les résultats. Un genre de service web simpliste.

Avant de poursuivre, je vous redirige à l'interface web de GeoBytes IP Locator pour en faire l'essai. Suite à cela, il sera possible d'extraire les résultats de la requête par programmation. Cet exemple est en PHP mais ce n'est pas contraignant vu le mode de récupération avec GET.

$url = 'http://www.geobytes.com/IpLocator.htm?GetLocation&template=php3.txt&IpAddress=';
$ip = '67.205.76.55';
$tags = get_meta_tags($url . $ip);

print_r($tags);
Aperçu du résultat obtenu (tableau associatif) :
Array
(
[known] => true
[locationcode] => CAQCMONT
[fips104] => CA
[iso2] => CA
[iso3] => CAN
[ison] => 124
[internet] => CA
[countryid] => 43
[country] => Canada
[regionid] => 35
[region] => Quebec
[regioncode] => QC
[adm1code] => CA10
[cityid] => 1182
[city] => Montreal
[latitude] => 45.5000
[longitude] => -73.5830
[timezone] => -05:00
[certainty] => 94
)
Les informations retournées sont plus complètes mais il possède aussi une limitation : en mode gratuit, seules 20 requêtes par heure sont autorisées. Au-delà de cette limite, un message apparaîtra :

The IP Address that you are currently using: xx.xx.xx.xx has exceeded it's reasonable usage limit, and has been temporarily blocked from accessing this service. Please try back again later.

Vous pourrez alors décider de payer pour le service s'il s'agit d'un élément critique pour le développement de votre application web.


Tags: PHP

dimanche 11 avril 2010

HTML 5 : test de fureteurs

Publié par Infinite Loop, à 21 h 21 5 commentaires

Il faut en parler et le prendre au sérieux car ça représente une percée majeure dans le futur du développement web : le HTML 5.

Cela dit, savez-vous si votre fureteur est suffisamment prêt pour supporter le standard ? Vous pouvez effectuer le test HTML 5 mis au point par Niels Leenheer. Rendez-vous simplement sur le site avec votre fureteur préféré pour en avoir un avant-goût.

Voici un sommaire des résultats que j'ai obtenu en date d'aujourd'hui sur 3 fureteurs populaires :


Firefox 3.6
Chrome 4.1
Internet Explorer 8
Doctype :
4 / 4 4 / 4
4 / 4
Canvas :
12 / 12 12 / 12
0 / 12
Video :
25 / 30 30 / 30
0 / 30
Audio :
20 / 24 20 / 24
0 / 24
Geolocalisation :
5 / 5 0 / 5
0 / 5
Storage :
8 / 8 4 / 8 8 / 8
Offline Web Applications :
8 / 11 3 / 11 0 / 11
Workers :
6 / 6 6 / 6 0 / 6
Section elements :
0 / 7
7 / 7 0 / 7
Grouping content elements :
0 / 2
2 / 2 0 / 2
Text-level semantic element :
0 / 5 4 / 5 0 / 5
Forms : 1 / 27 14 / 27 0 / 27
User Interaction : 12 / 19 12 / 19 7 / 19
Score final :
101 / 160
118 / 160
19 / 160

Jusqu'à maintenant, Chrome de Google a une longueur d'avance sur Firefox alors qu'Internet Explorer fait honneur à sa réputation en étant loin derrière la concurrence. C'est à peine s'il se mérite un prix de participation. Je suis désolé de ne pas avoir eu le temps de considérer Safari mais si vous avez fait le test sur d'autres fureteurs, je vous invite à me faire parvenir les scores obtenus.


Tags: HTML

Citation no. 77 sur la faim

Publié par Infinite Loop, à 08 h 18 0 commentaire

Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson.

- Confucius


Tags: Citations

samedi 10 avril 2010

Créer des graphiques de statistiques gratuitement

Publié par Infinite Loop, à 10 h 05 1 commentaire

On le sait, les dirigeants d'entreprises aiment les chiffres, surtout quand ils sont disposés en diagrammes. Quand mon patron m'a demandé d'incorporer des graphiques de statistiques (communément appelés "charts") à une application web, j'ai fait des recherches pour trouver quelque chose d'intéressant à l'oeil et malléable pour qu'un intégrateur ou un programmeur puisse effectuer son travail rapidement tout en ayant des résultats satisfaisants. Tout ça pour parler le même langage que mon patron.

C'est comme ça que j'ai découvert l'existence de FusionCharts, un produit indien très riche en possibilités. La license complète de FusionCharts v3 se détaille à 500$ mais pour commencer, on peut se contenter d'utiliser FusionCharts Free version 2.2, plus limitée mais suffisante pour mes besoins. Elle compte 22 types de graphiques animés en Flash, dont plusieurs caractéristiques sont personnalisables. Il y a même la possibilité de faire des diagrammes de Gantt (approved by my boss!). Voyez les différences entre les versions gratuite et payante pour choisir celle qui vous convient le mieux.

Lorsque vous aurez téléchargé le zip, décompressez-le et ouvrez Index.html pour obtenir de la documentation et des exemples. Pour vous faire une démonstration plus concrète, je vais tenter de reproduire mes statistiques de visites (fournies par Statcounter.com) pour que vous puissiez voir le résultat.

Statcounter



La première chose à faire pour générer un graphique, c'est d'avoir une source de données à notre disposition. J'ai généré un fichier XML statique qui respecte les spécifications de FusionCharts. Il aurait aussi pu provenir d'une page dynamique qui génère à la volée les données XML.

data.xml

<graph caption='Code 18 - Monthly statistics' subcaption='April 2009 - March 2010' divlinecolor='DDDDDD' numdivlines='7' showAreaBorder='1' areaBorderColor='000000' showNames='1' formatNumberScale='2' rotateNames='1'  decimalPrecision='0'>

<categories>
<category name='April' />
<category name='May' />
<category name='June' />
<category name='July' />
<category name='August' />
<category name='September' />
<category name='October' />
<category name='November' />
<category name='December' />
<category name='January' />
<category name='February' />
<category name='March' />
</categories>

<dataset seriesname='Page loads' color='7DC622' showValues='1'>
<set value='2116' />
<set value='2464' />
<set value='3426' />
<set value='4830' />
<set value='4920' />
<set value='7269' />
<set value='7673' />
<set value='8078' />
<set value='8340' />
<set value='9746' />
<set value='9234' />
<set value='11565' />
</dataset>

<dataset seriesname='Unique visitors' color='0069B3' showValues='1'>
<set value='1740' />
<set value='2001' />
<set value='2650' />
<set value='3940' />
<set value='3820' />
<set value='5643' />
<set value='6075' />
<set value='6477' />
<set value='6589' />
<set value='7638' />
<set value='7455' />
<set value='9298' />
</dataset>

<dataset seriesname='Returning visitors' color='EE9C00' showValues='1'>
<set value='161' />
<set value='257' />
<set value='327' />
<set value='511' />
<set value='480' />
<set value='681' />
<set value='762' />
<set value='764' />
<set value='808' />
<set value='876' />
<set value='944' />
<set value='1399' />
</dataset>

</graph>
Le fichier est séparé comme suit :
  • Les catégories correspondent aux noms sur l'axe des x (les mois)
  • Chaque bloc dataset correspond à une ligne de données
On crée un conteneur qui accueillera le graphique dans le DOM HTML :
<div id="graphHolder"></div>
On charge la librairie JavaScript de FusionCharts et optionnellement le framework jQuery pour initialiser le graphique au chargement de la page :
<script type="text/javascript" src="/js/jquery-1.4.min.js"></script>
<script type="text/javascript" src="/FusionChartsFree/JSClass/FusionCharts.js"></script>
On charge le graphique en indiquant son type et l'emplacement des données :
$(document).ready( initFusionCharts );

function initFusionCharts(){
var chart = new FusionCharts("../Charts/FCF_MSColumn2D.swf", "ChartId", "600", "400");
//var chart = new FusionCharts("../Charts/FCF_MSColumn3D.swf", "ChartId", "600", "400");
//var chart = new FusionCharts("../Charts/FCF_MSArea2D.swf", "ChartId", "600", "400");

chart.setDataURL("data.xml");
chart.render("graphHolder");
}
Le graphique peut ne pas être chargé en JavaScript, mais c'est plus simple et plus lisible que de l'écrire au long avec la balise <object>.

Voici le résultat :

Colonnes en 2 dimensions (FCF_MSColumn2D.swf)



Utilisez les autres définitions que j'ai placé en commentaires pour voir deux autres styles générés à l'aide de la même source de données.

Colonnes en 3 dimensions (FCF_MSColumn3D.swf)



Surface en 2 dimensions (FCF_MSArea2D.swf)


Tags: Intégration, JavaScript

vendredi 9 avril 2010

Invasion de New York City en pixels

Publié par Infinite Loop, à 08 h 47 0 commentaire

Création vidéo très intéressante de Patrick Jean dans le décor de la ville de New York. En vedette : une tonne de pixels, le jeu de Tetris avec les bâtiments, Space Invaders, Pac Man, Donkey Kong sur l'Empire State Building, etc... Très réussi !


Tags: Le coin du geek

jeudi 8 avril 2010

Pourquoi j'ai viré ma secrétaire

Publié par Infinite Loop, à 16 h 49 0 commentaire

Je me suis réveillé ce jour-là et j'avais 40 ans. Je ne me sentais pas très bien mais j'espérais que ma femme me souhaiterait un Joyeux Anniversaire. A ma grande déception, elle ne m'a même pas dit bonjour. Au petit-déjeuner, mes enfants ne m'ont pas parlé.

Au bureau, ma secrétaire m'a dit : Joyeux Anniversaire ! J'étais heureux, car au moins elle s'était souvenue de moi, mais à ma grande tristesse, mes collègues m'avaient oublié.

À midi, ma secrétaire m'a dit : Pourquoi ne pas déjeuner ensemble? J'ai dis que c'était la plus belle chose qu'on m'avait proposée ce jour. Nous sommes alors partis prendre un verre et manger ensemble.

Sur le chemin du bureau, elle m'a dit : "Pourquoi retourner au boulot si tôt un tel jour ?" et me proposa de passer chez elle. Arrivés à son domicile, elle m'a offert un verre et m'a dit : "Cela ne te dérange pas que je me mette à l'aise ?". J'ai répondu : "Quelle question!"

Et dans ma tête je me disais que ça pouvait être une expérience intéressante. Elle est partie dans sa chambre et est revenue avec un énorme gâteau... suivie de ma femme, de mes enfants, de mon patron et de tous mes collègues.

Et moi comme un con, j'étais à poil dans le salon...

Conasse.

Petite blague tirée de mon répertoire Outlook qui contient des trucs drôles que mes contacts m'ont envoyé au fil du temps. Dont beaucoup trop de diaporamas Powerpoint!


Tags: Humour

mercredi 7 avril 2010

Amazon et UPS : duo imbattable

Publié par Infinite Loop, à 18 h 09 3 commentaires

Essayez de comprendre cela... Lundi soir (5 avril 2010), j'ai passé une commande sur le site web d'Amazon Canada. Les items, tous en stock, étaient les suivants :

  • Rework de Jason Fried et David Heinemeier Hansson (37signals). 16,89$
  • Freakonomics de Steven D. Levitt et Stephen J. Dubner. 9,99$
  • The Best of 2006, A Hacker Odyssey de Emmanuel Goldstein. 27,58$
Donc 3 livres, pour un total de 57,18$ (incluant 2,72$ de taxes).

Pour la livraison, j'avais 3 choix (si je groupais mes items dans un même colis) :
  • FREE Super Saver Shipping (entre 4 et 7 jours ouvrables)
  • (entre 3 et 5 jours ouvrables). Supplément de livraison : 9,80$
  • (2 ou 3 jours ouvrables). Supplément de 16,96$
J'ai choisis la livraison gratuite. Or, j'ai reçu ma commande ce matin, soit moins de 48 heures après le paiement, sans avoir eu à débourser pour un supplément de livraison. Selon le tracking number fournit par Amazon, le paquet est parti de l'entrepôt vers 14h le 6 avril et a été reçu à 10h le lendemain.

Lorsque je l'ai eu en mains, l'autocollant indiquait que c'était livré par UPS (c'est nouveau ?), en provenance de Mississauga en Ontario vers Montréal et que le colis faisait 6 lbs à la pesée. Le délais et le choix du service m'ont étonné car UPS n'a pas la réputation d'être le service le plus économique.

À titre de comparaison, je me suis rendu sur le site d'UPS Canada pour calculer les frais qu'il m'en aurait coûté pour envoyer moi-même un colis identique :
  • En provenance de Mississauga (L5R 3W5)
  • Boîte de 6 lbs
  • Dimensions de 12 x 9 x 5 pouces
  • Valeur déclarée : 60$
Les différents services offerts :
  • UPS Standard : 21,16$
  • UPS Expedited : 22,18$
  • UPS Express Saver : 23,87$
  • UPS Express : 28,12$
Tous avec une promesse de livraison pour le lendemain. Vous y comprenez quelque chose ? Je veux bien croire qu'ils ont une entente de partenariat mais s'il y a réellement des frais minimum de 21$ de livraison qu'Amazon débourse pour livrer une commande de 60$, je me demande bien où ils font leur profit! Ils bénéficient certainement de tarifs préférentiels, mais quand même... Quelqu'un pourrait m'éclairer ?


Tags: Le coin du geek

mardi 6 avril 2010

7 autres équivalences Prototype vs jQuery

Publié par Infinite Loop, à 20 h 42 1 commentaire

Dans le cadre d'un projet de migration d'une librairie construite sous Prototype vers jQuery, j'ai eu l'occasion d'apprendre à trouver des équivalences entre les deux frameworks JavaScript. J'ai pris le temps de les noter pour vous montrer de quelle façon on peut les remplacer lors de la réécriture du code. J'espère que ça sera aussi utile à vous qu'à moi.

1. strip() = trim()
Pour retirer les espaces au début et à la fin.

var str = '    code 18 est ici        ';

// Prototype
str.strip();

// jQuery
$.trim(str);
2. include() = inArray()
Pour savoir si un élément fait parti de la liste.
var arr = ['ebay', 'paypal', 'amazon'];

// Prototype
arr.include('facebook');

// jQuery
$.inArray('facebook', arr);
3. any() = inArray()
Un truc pratique avec inArray pour savoir si au moins une condition est respectée.
var price = 50;
var discount = 10;
var shipping = true;
var paid = true;

var conditions = [
(price < 0),
(discount > price),
(!shipping),
(!paid)
];

// Prototype
if(conditions.any()){
// code
}

// jQuery
if($.inArray(true, conditions) != -1){
// code
}
4. each()
Pour boucler sur les éléments du tableau.
//  Prototype
arr.each(
function(index, context){
// code
}
);

// jQuery
$.each(arr,
function(index, value){
// code
}
);
5. Sélecteur
Avec jQuery, le sélecteur retourne une collection. Le premier élément est à l'indice 0 même si on fait référence à son identificateur :
// Prototype
$('element_id');

// jQuery
var collection = $('#element_id').get();
var element = collection[0];

ou

var element = $('#element_id').get(0);
6. Pluck()
Cette fonction de Prototype n'existe pas nativement en jQuery. Mais on peut la coder facilement.
// Protoype
arr.pluck('value');

jQuery :
var arrPluck = [];
$.each(arr,
function(){
arrPluck.push($(this).val());
}
);
Comme dans l'exemple :
var arrInputs = $('input');

var arrPluck = [];
$.each(arrInputs,
function(){
arrPluck.push($(this).val());
}
);

console.log(arrPluck);
7. uniq() != unique()
Sous jQuery, unique() fonctionne seulement avec des objets du DOM. Contrairement à ce qu'offre Prototype pour traiter un array, on doit trouver une solution alternative comme le plugin UNIQ.

Si vous voulez en apprendre plus sur le sujet, vous pouvez lire un ancien billet que j'ai écrit en février 2009 sur quelques équivalences Prototype et jQuery.


Tags: JavaScript

Job de professionnel

Publié par Infinite Loop, à 09 h 40 0 commentaire

Celle-là est une belle gaffe d'un infographiste pour l'emballage d'une carte mémoire Lexar Professional de 8 GB. Remarquez le reflet miroir.



Tiré de Photoshop Disasters et répertorié récemment dans l'article 45 obvious Photoshop mistakes that could have been avoided sur Pxleyes.com.


Tags: Curiosités

lundi 5 avril 2010

Les aventures de Sivis Pacem et Para Bellum

Publié par Infinite Loop, à 10 h 56 2 commentaires

À l'issue des années rock psychadéliques des années 60 où les drogues hallucinogènes étaient en vogue, l'auteur québécois Louis Gauthier a probablement désiré très fort être une rockstar. À défaut de maîtriser le médiator (communément appellé un pick), c'est du côté de la plume qu'il excellait. Et dans cette oeuvre publiée en 1970, il en a visiblement conservé l'atmosphère pour en faire un roman. C'est absurde, incompréhensible, un tour de force dans le genre littéraire qui en surprendra plus d'un.

Le livre m'avait été recommandé par un ami (que je soupçonnais lui-même être dans un état second) à l'époque de mes études au Cegep. Et depuis, c'est devenu un de mes romans québécois préférés tellement c'est rafraîchissant et pour son pied de nez envers la littérature établie. Un 10$ bien investi.

Les aventures de Sivis Pacem et Para Bellum, Tome 1 (et oui, il y a un tome 2!), c'est :

  • un livre dont le titre impressionnera vos amis
  • une histoire qui met en scène des personnages comme : Sivis Pacem, Para Bellum, Scrap Book, Bicyclette Premier (anciennement connu sous le nom de Pierrejeanjacques Jeanjacquespierre), Brodie XXX, Fred Flinstone, Jello Bananananas, Jelly Bean, Sun Life, Fleur d’Oranger, le baron Paupiette de Veaubraisé, etc...
  • une intrigue qui se déroule au niveau planétaire, particulièrement à Abab-Rupto
  • un livre où, dès le chapitre 2, on nous lance un avertissement : où l'on voit que l'éditeur aurait dû réfléchir un peu avant de publier des insanités pareilles
  • Des rebondissements et de l'humour, dont mon coup de coeur au chapitre 6 (c'est ça un quiproquo ?)
  • Où le chapitre 10 a été complètement supprimé car ses amis lui avaient recommandé de le retravailler
Pour mieux décrire ce roman, mieux vaut laisser la parole à Dieu-le-père (oui oui, le vrai) qui a su le décrire admirablement bien (tel que retranscrit de la fin du livre) :

LES AVENTURES DE SIVIS PACEM ET DE PARA BELLUM (7).
Roman d'aventure avec Sivis Pacem et Bicyclette Premier. Un jeune homme devient malgré lui vedette internationale de tous les temps. Superficiel. Intrigue dispersée. Scénario confus. Longueurs. Plusieurs clichés. Interprétation caricaturale. Manque d'unité dans le style. Piètre réalisation - ambiance trouble. Personnages pervertis. Recherche gratuite d'effets suggestifs. Scènes d'alcôve. Vulgarités. Exhibitionnisme. Allusion à des moeurs dévergondées. Scènes osées. Langage grossier. Immoralité totale des personnages.

* La cote 7, on le sait, signifie qu'une oeuvre est minable.

De ce que j'ai lu par la suite, seul Ghislain Taschereau s'est légèrement rapproché de ce style avec L'inspecteur Specteur et le doigt mort (le seul que j'ai lu de lui). Si vous avez des suggestions dans le même genre, soumettez les moi.

Comme le cite le livre lui-même : une oeuvre résolument moderne et tellement éclatée que l’auteur n’a pas réussi à rassembler tous les morceaux. Colle non fournie.


Tags: Curiosités, Livres

dimanche 4 avril 2010

Créer une page de maintenance pour un site

Publié par Infinite Loop, à 09 h 48 0 commentaire

Lorsqu'on programme un site ou une application web, il arrive parfois qu'on ait à procéder à des changements importants sur le serveur et qu'on ait besoin de placer le site en maintenance pendant le temps qu'on applique les modifications. Dans mon cas, c'est souvent relié à un changement de structure dans la base de données ou dans les fonctions et procédures stockées.

C'est pourquoi je prends la précaution de faire une redirection temporaire à une page de maintenance en attendant que le processus soit complété pour éviter que tout se mette à briser si des visiteurs arrivent au même moment (ce qui est toujours le cas).

Habituellement, la façon la plus simple est de créer une page vierge (avec design ou pas) et d'y inscrire un message annonçant qu'une maintenance est en cours :

maintenance.html
Nous sommes désolé, le service n'est pas accessible dans l'immédiat. Nous sommes en train d'améliorer le service qui atteindra un niveau inégalé. Votre visite est importante pour nous, veuillez revenir plus tard. N'ayez crainte, le site sera de retour dès que notre équipe de développeurs aura terminé leur tournoi de babyfoot.

.htaccess
Cela dit, on peut ensuite utiliser le fichier .htaccess à la racine pour y inscrire les instructions mod_rewrite suivantes :

RewriteCond %{SCRIPT_FILENAME} !maintenance\.html$ [NC]
RewriteRule ^(.*)$ /maintenance.html [L]

La dernière ligne indique la page où le message est inscrit. Naturellement, on ajoute une condition pour exclure la page elle-même pour ne pas faire une redirection en boucle infinie.

Quand il s'agit d'un site de commerce électronique, par exemple s'il y a paiement par PayPal, il serait judicieux de ne pas oublier d'exclure la page qui reçoit l'IPN (Instant Payment Notification) car c'est elle qui reçoit tous les messages en provenance du service externe et elle devrait toujours être accessible. Dans ce cas, excluez la en ajoutant une condition supplémentaire :

RewriteCond %{SCRIPT_FILENAME} !paypal\.notifications\.php$ [NC]


Tags: Apache

Citation no. 76 sur la programmation

Publié par Infinite Loop, à 07 h 43 0 commentaire

Bad programming is easy. Idiots can learn it in 21 days, even if they are Dummies.

- Matthias Felleisen


Tags: Citations

samedi 3 avril 2010

3 façons de dessiner un cercle avec GIMP

Publié par Infinite Loop, à 08 h 51 4 commentaires

Je ne suis pas designer donc loin d'être un expert en Photoshop. De plus, plutôt que de payer une license onéreuse, je me contente de GIMP qui est gratuit et qui possède déjà trop de fonctionnalités pour ce que j'aurai besoin (en passant, existe-t-il des professionnels qui l'utilisent intensivement en entreprise ?).

Hier, en voulant mettre en évidence le logo qui ressemblait au mien sur la photo, je cherchais à l'entourer d'un cercle et j'ai dû y aller à tâton pour trouver le moyen d'y arriver. Faire une sélection et utiliser le remplissage pour mettre une couleur de fond sont des étapes intuitives, mais faire un beau cercle en bordure allait déjà au-delà de mes compétences en matière de manipulation d'image (resize, crop, etc.).

Ce qui est bien dans ce genre de situation, c'est qu'on découvre et retient plusieurs approches pour arriver à ses fins. En voici un compte rendu, tel que testé avec GIMP 2.6.8.

Établir une sélection

  • Ouvrir l'image de base.
  • Créer un nouveau layer de la même taille (Shift+Ctrl+N).
  • Choisir dans la palette d'outils Ellipse Select Tool. Un autre raccourci possible est d'entrer seulemenr la lettre "e".
  • Dessiner une ellipse de n'importe quelle dimension.
  • Dans la palette d'outils, ajustez size (largeur, hauteur) pour avoir un cercle parfait.
OU
  • Assurez-vous choisir Aspect Ratio dans la liste déroulante.
  • Faites votre sélection.
  • Sans relâcher le bouton gauche de la souris, appuyez sur Shift et relâchez le bouton. Le cercle s'ajustera correctement en proportion.
OU
  • Toujours avec Aspect Ratio, cochez aussi la case Fixed à sa gauche. Ceci vous évitera d'utiliser Shift.
Dessiner le cercle

Méthode 1 :
  • Faites la sélection.
  • Menu Select / Border.
  • Entrez l'épaisseur de la bordure (sélection seulement).
  • Un deuxième cercle se dessinera de l'intérieur.
  • Choisissez Bucket Fill Tool (Shift+C), sélectionnez une couleur pour la bordure et cliquez une fois dans la bordure du cercle.
Méthode 2 :
  • Faites la sélection.
  • Choisissez la couleur de bordure.
  • Menu Edit / Stroke Selection.
  • Définissez le Line Width (épaisseur), Solid color et cliquez le bouton Stroke.
  • La bordure se dessinera à cheval sur la sélection (moitié intérieure, moitié extérieure).
Méthode 3 :
  • Faites la sélection.
  • Remplissez la couleur de fond du cercle avec le Bucket Fill Tool.
  • Menu Select / Shrink.
  • Indiquez le nombre de pixels et cochez Shrink from image border. Faites OK.
  • Une sélection de cercle plus petit se fera à l'intérieur.
  • Appuyez une fois sur la touche Delete pour supprimer la nouvelle sélection.
  • La bordure sera faite à partir de l'intérieur de la sélection initiale.
Avec cette tâche relativement simple (pour un programmeur), je me suis davantage familiarisé avec GIMP et j'ai probablement appris 5 ou 6 trucs que je ne savais pas. J'ai aussi testé la méthode avec les autres outils de sélection (rectangle, free et fuzzy) pour obtenir les mêmes résultats.


Tags: GIMP

vendredi 2 avril 2010

Ce petit personnage sympathique

Publié par Infinite Loop, à 18 h 36 0 commentaire

Durant un voyage ayant eu lieu l'été dernier, j'étais sur un traversier et j'ai pris une photo d'une pancarte "Surface slippery when wet" dont je me suis approprié le logo tellement je trouvais le personnage comique. Voici l'image originale :



Mine de rien, quand j'ai fait l'épicerie cette semaine, j'ai remarqué un personnage semblable sur la boîte de barres de céréales Compliments Les indispensables (IGA et Marchés Tradition) :



Ressemblant non ? C'était un argument suffisant pour me la procurer.


Tags: Pancartes et écriteaux

jeudi 1 avril 2010

Poisson d'avril 2010

Publié par Infinite Loop, à 07 h 18 0 commentaire

Hey! Code 18 est présentement absent et je prends le contrôle du site pour la journée. Votre nouvel hôte : Uncle Travelling Matt. Peut-être que vous vous souvenez de moi dans les Fraggle Rock ? (sinon voyez mon compte Twitter au cours de la journée pour une confession...)

L'an dernier, on avait eu droit à plusieurs attrapes que j'avais partiellement listé dans un billet : quelques poissons d'avril de 2009. Qu'en est-il de la cuvée 2010 ?

D'abord, YouTube! lance aujourd'hui TEXTp, une nouvelle expérience de visionnement de vidéo en mode texte. Par exemple, un extrait de The Matrix en Lego sous TEXTp. Contrairement à la haute définition, ceci permet à YouTube de sauver 1$ par seconde en coût de bande passante.

Du côté de Google, on parlait des villes qui voulaient attirer le géant du web en donnant comme argument qu'ils changeraient le nom de leur municipalité pour devenir "Google". Eh bien, surprise, c'est Google qui a changé son nom pour Topeka pour ne pas qu'il y ait de confusion!

Sur ThinkGeek, maintenant un classique annuel, vous trouverez une nouvelle gamme de produits des plus excitants (à voir en page d'accueil) :

  • iCade - iPad Arcade Cabinet (pour placer votre iPad et en faire une arcade)
  • Monolith Action Figure de 2001 : a space odyssey
  • moodINQ - Programmable Tattoo System
  • My First Bacon : You've got a friend in meat
  • Dharma Initiative Alarm Clock
Si vous entrez sur Google Maps avec StreetView, vous verrez une nouvelle icône sous le contrôle de zoom pour voir en 3D (les lunettes avec un côté rouge et l'autre bleu sont nécessaires).

Une nouvelle application pour Android : Google Translate for Animals : Grunt, Woof and Moo to you too.

Celui-ci est particulièrement drôle : Google Japan a créé un nouveau type de clavier inspiré d'un drum (batterie). À voir.

Toujours chez Google, faites une recherche par la page d'accueil de Google.com. Voyez le temps nécessaire pour sortir les résultats : Results 1 - 10 of about 672,000,000 for test [definition]. (0.35e+43 Planck times).

Tel que mentionné par @patdion (Twitter) : belle job de retouche de Cyberpresse sur Mauvais Oeil.

Mise à jour 18h00
Je viens de trouver une liste sur TechCrunch.com qui liste tout ce qu'ils ont trouvé : TechCrunch April Fools 2010, The Definitive List. Allez y faire un tour!

Mentions spéciales à :
  • Toshiba TubeTop, The world's first inflatable laptop
  • Chatroulette Cheerleader de Dr.Pepper
  • Google Standard Voicemail mode


Tags: Curiosités

Messages plus récents Messages plus anciens Accueil
S'abonner à : Messages (Atom)
    Suivre @code18 sur Twitter

    Catégories

    • Apache (21)
    • Citations (167)
    • Club Vidéo (24)
    • Coffre à outils (56)
    • CSS (8)
    • Curiosités (117)
    • Design Pattern (2)
    • Drupal (8)
    • Easter Eggs (22)
    • Extensions Firefox (20)
    • GIMP (7)
    • Histoire (21)
    • HTML (32)
    • Humour (57)
    • Intégration (34)
    • iPod (12)
    • JavaScript (110)
    • Jeu de combat (6)
    • Le coin du geek (128)
    • Liens (12)
    • Linux (56)
    • Livres (78)
    • Lois et principes (46)
    • Marché des saveurs (26)
    • Mathématique (18)
    • Mobile (5)
    • Montréal (32)
    • Musique (112)
    • Pancartes et écriteaux (16)
    • Perl (8)
    • Pérou (1)
    • PHP (130)
    • PostgreSQL (44)
    • Programmation (105)
    • Saviez-vous que (55)
    • Sécurité (22)
    • SEO (5)
    • SQL Server (22)
    • Vieilles publicités (6)
    • Virtualisation (8)
    • Voyages (1)
    • Zend Framework (26)

    Divers

    Archives

    • ►  2015 (6)
      • ►  août 2015 (1)
      • ►  juillet 2015 (1)
      • ►  février 2015 (3)
      • ►  janvier 2015 (1)
    • ►  2014 (8)
      • ►  décembre 2014 (1)
      • ►  novembre 2014 (1)
      • ►  octobre 2014 (1)
      • ►  août 2014 (2)
      • ►  juillet 2014 (2)
      • ►  janvier 2014 (1)
    • ►  2013 (53)
      • ►  décembre 2013 (2)
      • ►  novembre 2013 (1)
      • ►  octobre 2013 (3)
      • ►  septembre 2013 (2)
      • ►  août 2013 (5)
      • ►  juillet 2013 (3)
      • ►  juin 2013 (5)
      • ►  mai 2013 (3)
      • ►  avril 2013 (7)
      • ►  mars 2013 (7)
      • ►  février 2013 (11)
      • ►  janvier 2013 (4)
    • ►  2012 (105)
      • ►  décembre 2012 (8)
      • ►  novembre 2012 (5)
      • ►  octobre 2012 (4)
      • ►  septembre 2012 (1)
      • ►  août 2012 (8)
      • ►  juillet 2012 (7)
      • ►  juin 2012 (7)
      • ►  mai 2012 (10)
      • ►  avril 2012 (13)
      • ►  mars 2012 (15)
      • ►  février 2012 (15)
      • ►  janvier 2012 (12)
    • ►  2011 (146)
      • ►  décembre 2011 (14)
      • ►  novembre 2011 (11)
      • ►  octobre 2011 (12)
      • ►  septembre 2011 (13)
      • ►  août 2011 (15)
      • ►  juillet 2011 (17)
      • ►  juin 2011 (18)
      • ►  mai 2011 (15)
      • ►  avril 2011 (9)
      • ►  mars 2011 (7)
      • ►  février 2011 (3)
      • ►  janvier 2011 (12)
    • ▼  2010 (398)
      • ►  décembre 2010 (29)
      • ►  novembre 2010 (28)
      • ►  octobre 2010 (32)
      • ►  septembre 2010 (34)
      • ►  août 2010 (22)
      • ►  juillet 2010 (35)
      • ►  juin 2010 (42)
      • ►  mai 2010 (36)
      • ▼  avril 2010 (37)
        • Mise à jour Ubuntu 10.04 LTS
        • Calculer le temps d'exécution d'un script
        • 1816, l'année sans été
        • Chansons à 4 accords
        • Éviter de perdre le contenu rédigé sur le web
        • Épileptique neuf à vendre
        • Formule pour calculer la densité de la bière
        • Citation no. 79 sur l'éducation
        • Rework, un livre plein de gros bon sens
        • Servez à ce monsieur une bière et des kiwis
        • Reporter l'interprétation JavaScript avec defer
        • La cuillère est une arme dangereuse
        • Je suis un programmeur ninja !
        • Attention aux extensions multiples sur Apache
        • Formater un champ monétaire en JavaScript
        • Citation no. 78 sur la vieillesse
        • Étrange détail dans les Fraggle Rock
        • Pages web en unicode (UTF-8)
        • Death Star Logo de AT&T
        • David le gnome, version métal
        • Améliorer la performance d'une boucle en PHP
        • FIMAV, John Zorn et la poutine
        • Service de géolocalisation GeoBytes IP Locator
        • HTML 5 : test de fureteurs
        • Citation no. 77 sur la faim
        • Créer des graphiques de statistiques gratuitement
        • Invasion de New York City en pixels
        • Pourquoi j'ai viré ma secrétaire
        • Amazon et UPS : duo imbattable
        • 7 autres équivalences Prototype vs jQuery
        • Job de professionnel
        • Les aventures de Sivis Pacem et Para Bellum
        • Créer une page de maintenance pour un site
        • Citation no. 76 sur la programmation
        • 3 façons de dessiner un cercle avec GIMP
        • Ce petit personnage sympathique
        • Poisson d'avril 2010
      • ►  mars 2010 (34)
      • ►  février 2010 (32)
      • ►  janvier 2010 (37)
    • ►  2009 (430)
      • ►  décembre 2009 (32)
      • ►  novembre 2009 (34)
      • ►  octobre 2009 (33)
      • ►  septembre 2009 (37)
      • ►  août 2009 (37)
      • ►  juillet 2009 (39)
      • ►  juin 2009 (38)
      • ►  mai 2009 (37)
      • ►  avril 2009 (35)
      • ►  mars 2009 (37)
      • ►  février 2009 (32)
      • ►  janvier 2009 (39)
    • ►  2008 (84)
      • ►  décembre 2008 (34)
      • ►  novembre 2008 (39)
      • ►  octobre 2008 (11)

    Abonnés

Copyright © All Rights Reserved. Code 18 | Converted into Blogger Templates by Theme Craft