Pour ceux que ça pourrait intéresser, j'ai ouvert un compte sur Last.fm pour partager la musique qui entre dans ma tête. Pour le moment, il n'est pas très garni mais je vais configurer mes lecteurs musicaux chez moi (dont mon jukebox touchscreen) et au travail pour diffuser tout ce que j'écoute.
Je n'avais pas beaucoup tendance à parler de moi dans mon blogue alors c'est peut-être un moyen de présenter un autre aspect de ma personnalité à travers mes préférences musicales. Vous verrez que la palette peut être assez vaste, étant mélomane et musicien amateur, j'ai une dépendance chronique à la musique.
Si vos goûts musicaux ressemblent aux miens ou si vous avez quelque chose à me faire découvrir, ça me fera plaisir d'en faire l'écoute.
Dis moi ce que tu écoutes et je te dirai qui tu es.
Cette année, l'équipe de Google remet ça et cache dans son fichier robots.txt un petit clin d'oeil à l'occasion de l'Halloween.
User-agent: Kids
Disallow: /tricks
Allow: /treats
Rappelons nous que l'an dernier, Google avait fait quelque chose de similaire avec les zombies.
Aujourd'hui a été lancé la nouvelle version d'Ubuntu (Karmic Koala). C'est donc le moment d'effectuer la mise à jour pour passer de 9.04 à 9.10.
Avant de lancer le processus, savez-vous quelle version vous utilisez ? Vous pouvez l'obtenir à partir d'un terminal avec une des deux commandes ci-dessous :
$ cat /etc/issue
Ubuntu 9.04
$ lsb_release -a
Distributor ID: Ubuntu
Description: Ubuntu 9.04
Release: 9.04
Codename: jaunty
Pour votre information, LSB = Linux Standard Base.
Pour faire la mise à jour de la distribution, rendez-vous au menu System / Administration / Update Manager. Il suffit de cliquer sur le bouton Upgrade (difficile d'être plus simple!).
On m'avertit que :
- 655 Mo seront téléchargés
- 28 packages seront retirés
- 285 nouveaux seront installés
- 982 seront mis à jour
- Durée estimée : 19 minutes
Sujet ridicule vous direz, mais pas si bête que ça quand on y pense. Dans le cadre d'une simulation de cours de programmation 101, je vous pose la question : comment effectuez vous la comparaison d'une variable avec une constante ?
Prenez 2 secondes pour y réfléchir et poursuivez votre lecture. Dans tous les langages de programmation, il existe un opérateur d'assignation et un opérateur de comparaison. Dans le cas de PHP, le premier est le symbole = alors que le second est un ==.
D'abord la réponse : la façon la plus sûre de comparer une valeur serait de placer la constante en premier :
if(CONSTANTE == $variable){La raison : parce que si vous faites la gaffe de faire le contraire et par mégarde vous utilisez l'opérateur d'assignation, PHP ne lancera pas d'erreur et le code s'exécutera sans livrer les résultats attendus et vous devrez en chercher la raison (à moins que votre éditeur soit assez intelligent pour vous les faire remarquer - comme NetBeans).
// ...
}
if($variable = CONSTANTE){En inversant l'ordre de comparaison, on s'assure que PHP lance un avertissement si on utilise l'assignation plutôt que le == :
// ...
}
if(CONSTANTE = $variable){Parse error: syntax error, unexpected '=' in file...
// oups, on ne peut pas assigner de valeur à une constante
}
Je soulève le point car j'ai moi-même fait l'erreur récemment malgré plusieurs années d'expérience. Peut-être est-ce le temps de faire des ajustements et de réviser nos habitudes de codage ?
Oui, je suis toujours en vie! Je prends quelques minutes pour vous donner des nouvelles pendant ma pause de rédaction (qui repart tranquillement).
Samedi matin, sur un coup de tête, je me suis levé avec l'idée d'acheter une nouvelle guitare électrique pour dégourdir mes doigts autrement que sur un clavier. Depuis, ça occupe tout mon temps libre et je me rends compte à quel point jouer quelques mesures peut procurer une sensation de bien-être (causé par l'endorphine).
Hier, en revenant du bureau, j'ai pratiqué toute la soirée la rythmique et un solo de la pièce instrumentale To Live is to Die de Metallica. À vrai dire "presque", puisque quatre phrases sont prononcées vers la fin en hommage à leur ancien bassiste Cliff Burton, décédé dans un accident d'autobus en tournée.
Les paroles sont tirées d'un poème écrit par l'allemand Paul Gerhardt (1607-1676) qu'on retrouve en partie dans le film Excalibur (1981) alors que Merlin s'adresse à Arthur.
When a man lies, he murders some part of the world.Vous pouvez consulter le script complet du film ou encore regarder l'extrait vers 1h23 sur le DVD (version anglaise).
These are the pale deaths which men miscall their lives.
All this I cannot bear to witness any longer.
Cannot the Kingdom of Salvation take me home?
Je dois confesser que j'ai regardé Excalibur car j'étais dans le mood de la légende arthurienne puisque je suis présentement l'excellente série humoristique Kaamelott.
Voilà, c'est fait. Code 18 fête aujourd'hui son premier anniversaire d'existence. Né d'un projet qui était au départ un défi personnel de bloguer quotidiennement pendant un an sur l'univers des technologies de l'information, j'ai mis un accent particulier mis sur mon champ d'activité principal, la programmation.
Ça n'a pas toujours été un exercice facile de trouver les sujets d'inspiration, d'écrire un article simple et concis chaque jour mais je suis très satisfait d'y être arrivé. Depuis longtemps, j'essayais de découvrir et d'apprendre un nouveau truc régulièrement pour satisfaire ma curiosité et j'ai senti le besoin de de partager mes connaissances avec les autres.
Un an plus tard, je fais le bilan du travail réalisé : environ 1400 visites uniques chaque semaine, la formation d'une petite communauté avec qui interagir et s'entraider, ce sont des signes suffisamment encourageants pour me convaincre à continuer.
Sur un plan personnel, je juge que ce fût bénéfique puisque prendre le temps d'expliquer un concept en le mettant par écrit permet de réviser les notions, de consolider ce qu'on a appris et de découvrir quelques détails supplémentaires qui nous avaient échappés.
Pour vous mettre en contexte, chaque article pouvait me demander quotidiennement entre 20 minutes et 3 heures que je réalisais en dehors de mes heures de travail (au grand dam de ma blonde!). Parfois même, je pouvais développer certaines idées qui se sont échelonnées sur plusieurs sessions de travail. Même durant mes vacances et à l'occasion d'un voyage à l'extérieur (devinez quand!), j'ai poursuivi mon but sans interruption, juste pour le principe de gagner mon pari.
Même si je le fais d'abord pour moi, j'espère que vous appréciez la somme de mon labeur. Ce blogue va poursuivre son chemin mais pour l'instant je m'accorde un petit congé bien mérité.
Pour la prochaine année, je vais peut-être diminuer un peu la cadence de publication et je risque probablement d'aller jeter un oeil à différents événements dans la communauté culturelle montréalaise, comme YulBlog, des StartUp Camp, Pecha Kucha, Geekfest, etc.
Enfin, je vous invite à me faire part de vos questions, commentaires, idées de sujets, tout ce qui pourrait intéresser les geeks de ce monde. Vous pouvez me contacter par email, Twitter, Identica, Google Talk (code18.blogspot[at]gmail.com), ça me fera plaisir de vous parler.
À bientôt!
Pour mieux structurer une base de données PostgreSQL, j'aime l'idée de répartir les objets en schémas logiques. Ça permet entre autre d'avoir deux tables du même nom dans deux schémas différents.
Par défaut, tous les objets sont créés dans le schéma "public". Vous ne l'aviez peut-être pas remarqué car vous n'êtes pas obligés de le nommer quand vous voulez faire référence aux objets (tables, fonctions, etc) lorsque vous construisez vos requêtes SQL.
SELECT * FROM ma_table;Dès qu'on crée un nouveau schéma et qu'on y ajoute des objets, on devra les préfixer par le nom de schéma suivi d'un point :
CREATE SCHEMA music;Comme vous pouvez le constater, il existe maintenant deux vues portant le nom "collection" qui reposent dans leur propre schéma. Si vous essayez de faire une requête sur la vue collection sans spécifier le schéma, PostgresSQL vous indiquera que l'objet n'existe pas (en fait, il essaiera de référencer collection dans le schéma public mais il s'arrêtera là s'il ne le trouve pas).
CREATE TABLE music.artist(...);
CREATE TABLE music.album(...);
CREATE VIEW music.collection(...);
SELECT * FROM music.collection;
CREATE SCHEMA movie;
CREATE TABLE movie.gender(...);
CREATE TABLE movie.title(...);
CREATE VIEW movie.collection(...);
SELECT * FROM movie.collection;
Cette technique vous permet d'éviter la redondance lorsque vous nommez vos tables (qui auraient aussi bien pu se nommer client_info, client_address, client_order, etc) et qui rend vos objets programmables plus modulaires puisqu'ils sont regroupés logiquement. On trouvera un avantage certain à savoir qu'un schéma possède aussi un propriétaire auquel vous pouvez donner des privilèges particuliers.
Hier soir, j'ai rendu visite à mes parents et pendant que nous discutions des derniers films que nous avions vus chacun de notre côté, mon père m'a demandé si je pouvais lui donner un cours 101 sur la copie de DVD. Ils ont un enregistreur DVD raccordé à la télé mais dès qu'ils veulent faire un double, on peut voir les points d'interrogation dans leurs yeux. Hehe, dire qu'à l'époque où je demeurais chez eux, c'était ma tâche de programmer le vidéo (VHS) car j'avais des aptitudes comme "programmeur"...
Ah misère ! C'est vrai que ce n'est pas ce qu'il y a de plus intéressant à faire, mais bon :
- c'est facile à montrer et à apprendre
- ça va m'éviter de le faire à leur place à chaque fois
- je suis un peu coupable : c'est moi qui leur a donné un ordinateur pour qu'ils puissent s'initier à l'informatique
Je lui ai rapidement donné quelques points de repère pour qu'il puisse en connaître les différences. Bien que les DVD standards possèdent le même format et la même capacité, il y a quelques points à noter, faciles à retenir pour un débutant ou un père retraité :
Vitesse d'inscription
- Repérez le chiffre suivi d'un X (exemple : 8X). Il s'agit de la vitesse maximale que le disque peut recevoir les données en écriture.
- Plus le chiffre est élevé, plus vite sera la gravure (à condition d'avoir un graveur qui permet de graver aussi vite, sinon il faut configurer le logiciel de gravure pour qu'il écrive sur le disque à une vitesse moindre).
- Pour ne pas se casser la tête, plus le chiffre est élevé, moins vous risquez d'avoir de mauvaises surprises.
- Si vous prenez un DVD vierge et que vous comptez y graver quelque chose qui ne comblera pas le disque à pleine capacité, essayez de repérer l'option multi-session dans votre logiciel de gravure. En l'activant, vous pourrez ainsi y ajouter plus tard du contenu supplémentaire, comme par exemple des nouvelles photos dans votre album numérique, jusqu'à ce que le DVD soit plein.
- Le DVD-R est un standard plus vieux, parfait pour graver des données informatiques.
- Le DVD+R est un format plus récent et mieux adapté pour y graver des films et les écouter dans un lecteur DVD standard (compatibilité). Il possède aussi un meilleur contrôle des erreurs, est plus précis et a moins tendance à corrompre les données écrites sur le disque au moment de la gravure.
- Repérez l'inscription DVD+RW sur l'emballage.
- Ils sont plus chers car on peut effacer complètement les données et réécrire à nouveau
- Pour les spécialistes qui ont un besoin particulier.
- Attention à la confusion avec le logo du DVD+RW Alliance qui est un rectangle aux coins arrondis avec les lettres RW à l'intérieur. Les DVD réinscriptibles devraient être indiqués clairement qu'ils le sont.
- La plupart des DVD standards à bas prix sont dits à "simple couche" (single layer) et peuvent stocker 4,7 Go de données.
- Il existe aussi des DVD à double couche qui permet d'écrire presque le double de données (8.5 Go).
- Quand on parle de haute définition (HD), c'est qu'on est dans le monde des disques Blu-Ray (25 Go).
Je cherchais une information sur la vitesse de transfert sur une clé USB quand je me suis aperçu que Kingston avait lancé une clé USB DataTraveler 300 de 256 Go en juillet dernier.
Vous y pensez ? C'est gigantesque !
À vrai dire, c'est équivalent à :
- 10 DVD Blu-Ray (25 Go / chaque)
- 54 DVD standards (4.7 Go / chaque)
- 365 CD (700 Mo / chaque)
Disons que je vais conserver mon disque dur portatif (WD Passport) encore un bout de temps.
Classique de la littérature informatique, il a accumulé la poussière dans ma bibliothèque pendant quelques années et je me rappelle que j'étais tellement habitué de le voir que j'en avais oublié l'existence. Pourtant, la présence du signet à l'intérieur m'indiquait que je l'avais commencé mais j'avais dû l'abandonner pour une quelconque raison.
J'ai recommencé à le lire du début et à mesure que ma lecture progressait, je le trouvais de plus en plus pertinent car beaucoup, BEAUCOUP des idées présentées touchaient des irritants que je vis au quotidien à mon travail. Le timing était bon.
Pourtant, il ne s'adresse pas aux programmeurs et développeurs mais bien aux chargés de projets et aux gestionnaires. Quoi que dans mon cas, ayant toujours eu beaucoup d'entrepreneurship et ayant touché à un peu tout comme travailleur autonome et en entreprise (programmation, analyse, gestion de projets, recherche et développement), j'y ai trouvé mon compte assez rapidement.
Ce qui m'a impressionné, c'est que ce livre est tellement concis qu'il touche à tout coup au coeur du problème, ce qui en confirme la pertinence même si l'édition originale date de 1987. La copie que je me suis procuré est la seconde édition de 1999 qui compte 8 chapitres supplémentaires (comme l'indique la page couverture) et croyez moi, c'est encore autant d'actualité sinon plus car ça touche un élément clé du succès (ou de l'échec) d'un projet informatique :
- hardware
- software
- peopleware
On nous fait comprendre qu'il n'y a pas de recettes miracles à appliquer et que les situations sont à traiter cas par cas. Voici quelques idées abordées :
- l'investissement en capital humain : comme à la bourse, c'est rentable et à long terme
- l'effet non anticipé des heures supplémentaires : je vous laisse deviner...
- le concept des free electrons : un traitement privilégié aux employés d'exception
- l'esprit d'équipe, la chimie entre ses membres et les comportements qui peuvent la détruire
- le dérangement de toutes les façons, dont le téléphone : ne répondez pas pour rien (à chaque fois qu'on se fait déranger, ne serait-ce que 2 minutes, la perte représente 15 minutes de productivité)
- L'importante loi de Parkinson dont j'ai déjà parlé : "organizational busy work tens to expand to fill the working day"
- Plus une entreprise se rapproche de l'uniforme (ou de la cravate), moins votre emploi sera stimulant : "uniformity is so important to insecure authoritarian regimes that they impose dress codes". Comme dirait Gandalf : Fuyez pauvres fous !
- Le E-Factor : "brain time versus body time" (volontaire ou non)
- Le taux de roulement des employés (la moyenne n'est-elle pas de 2 ans au sein de la même entreprise ?). S'ils quittent trop vite, il faut se poser des questions et comprendre les motivations.
J'y ai aussi extrait quelques phrases clés qui résument la pensée des auteurs DeMarco et Lister et que je partage également :
- Learning is limited by an organization's ability to keep its people
- The fundamental response to change is not logical, but emotional
- It's supposed to be fun to work here
- Visual supervision is for prisoners
- Voluminous documentation is part of the problem, not part of the solution
- Quality, far beyond that required by the end user, is a means to higher productivity
- People under time pressure don't work better, they just work faster
En tout cas, pour moi, c'est clair que j'y ferai référence plus d'une fois.
Plus tôt aujourd'hui, j'aidais un de mes collègues à exploiter une fonctionnalité d'un site web d'un tiers parti qui nécessitait d'être appellé par le site lui-même pour que la requête soit considérée valide (juste pour préciser, rien n'était illégal dans notre démarche).
Ce que nous avons fait est un peu l'équivalent de se rendre sur une page, de remplir les champs d'un formulaire, de soumettre le tout et de récupérer le résultat pour nos besoins. La différence, c'est que nous avons fait le tout par programmation. C'est donc une méthode peu robuste et durable de faire les choses mais qui nous a servi à atteindre nos objectifs sans trop se casser la tête.
Nous avons créé un script PHP qui a lancé un appel CURL au formulaire distant. Cependant, il ne répondait pas correctement et nous avions de la difficulté à figurer pourquoi. Alors nous avons émis l'hypothèse que le formulaire devait vérifier la provenance de la requête en utilisant la variable serveur HTTP_REFERER car nous avions remarqué que CURL n'envoyait pas de valeur pour ce header.
Nous avons eu l'idée d'avoir recours à une technique nommée referrer spoofing. Ceci consiste à modifier l'entête HTTP qui indique le référant (d'où la requête provient) pour lui substituer un autre URL.
Avec CURL, il suffit d'ajouter la ligne suivante qui initialisera le header avec la valeur qu'on lui passe :
curl_setopt($handler, CURLOPT_REFERER, "http://code18.blogspot.com/");Comme par magie, ça s'est mis à fonctionner.
Si cette simple ligne de code nous a permis d'obtenir le résultat escompté, on devra en conclure que dans notre programmation, la vérification du référant peut parfois être pratique, mais il ne faut pas s'y fier comme mesure de sécurité puisque ça peut être aisément déguisé.
En phase de développement d'un projet, on a généralement tendance à programmer initialement la base de données et à mettre le tout en production une fois terminé. Lorsque le client demande des modifications au système, c'est une très mauvaise idée d'appliquer les changements sur la version en production. Un truc simple consiste à dupliquer la base de données et à poursuivre le développement localement, en redirigeant la connexion à la BD dupliquée, ce qui minimise le risque d'erreurs.
Avec un serveur PostgreSQL, on a deux choix :
- créer une copie à partir d'un gabarit
- utiliser une copie de sauvegarde
C'est la façon la plus simple de réaliser une copie complète d'une base de données (structure et données). Cependant, je passerai rapidement sur cette méthode car j'en ai parlé en détails dans un autre article. En gros, ça consiste à utiliser la commande SQL suivante :
CREATE DATABASE db_copie TEMPLATE db_source;
2. Restaurer une copie de sauvegarde
Pour restaurer un backup postgres, on doit d'abord en créer un. Sur le serveur, ouvrez un terminal et repérez l'utilitaire pg_dump qui créera un script de la base de données que psql est capable d'interpréter (dans le répertoire bin du dossier d'installation).
Si vous êtes connecté sur le serveur en tant qu'un autre utilisateur, je vous recommande d'invoquer les commandes en tant que l'utilisateur postgres (-U postgres).
pg_dump -U postgres -f /tmp/db.src -c -x -h localhost db_source
Où :
- -f spécifie l'emplacement du fichier où créer le backup
- -c pour ajouter en sortie les lignes de commandes qui créent la base de donnés
- -x pour ne pas tenir compte des privilèges (ACL)
- -h pour spécifier le serveur hôte
Avant d'utiliser le script db.src, il est nécessaire de créer une base de données vierge sur laquelle on exécutera le script. Il faut appeler la commande createdb :
createdb -U postgres db_new_name
Enfin, on appliquera le script qui créera la totalité de la structure et y insérera les données :
psql -U postgres newdb < /tmp/db.src
En conclusion
Copier une base de données à partir de la restauration d'un backup est pratique si on a besoin d'une version spécifique dans le temps. Sinon, rien ne nous empêche de dupliquer la BD selon un modèle tel que décrit à la méthode 1, ou encore de faire la même chose avec l'utilitaire createdb en prenant soin de spécifier le flag -T qui permet d'indiquer la base de données à utiliser comme modèle :
createdb -U postgres -T db_source db_copie
Finalement, si vous avez une BD volumineuse, je vous recommande de compresser le script au moment d'utiliser pg_dump.
L'ordinateur de Star Trek ne semble pas si intéressant. Ils lui demandent des questions aléatoires et il doit réfléchit un moment. Je pense que nous pouvons faire mieux que cela.
Si vous aimez partager des liens sur Twitter et sur certains outils collaboratifs, vous connaissez et utilisez certainement un service comme tinyurl.
D'un autre côté, si vous êtes programmeur, combien de fois avez-vous échangé des snippets de code avec un autre membre de votre équipe de développement ?
Vous serez heureux d'apprendre qu'il existe un service nommé CodePad qui permet d'y coller du code source, de le compiler / interpréter, l'exécuter et même de visualiser ce que ça produit en sortie pour finalement générer un URL à partager.
Le service supporte présentement plusieurs langages dont C/C++, D, Haskell, Lua, OCaml, PHP, Perl, Python, Ruby, Scheme, TCL et offre la possibilité d'offrir des URL privés à partager (ne seront pas affichés dans les plus récents posts et ne seront pas référencés par les moteurs de recherche même si l'URL reste accessible par tous).
À essayer!
Je parcourais Google Maps avec l'option Street View sur la rue Fabre à Montréal, juste au nord du Parc Lafontaine, quand j'ai aperçu une image timbre (communément appellé "thumbnail") dans le coin supérieur droit. Un utilisateur (dodlido) a ajouté une photo sur Panoramio à cet emplacement précis pour montrer quelque chose d'assez original : un pénitencier pour nains de jardins fugitifs !
L'écriteau "Do Not Feed The Dwarfs" me fait drôlement penser à l'expression "Do Not Feed The Trolls" utilisé dans le jargon Internet pour avertir qu'il ne faut pas encourager les provocateurs à créer de la polémique et à entretenir un débat qui ne mène nulle part.
Interdiction de nourrir les trolls !
Je me demande bien ce que le créateur de cette oeuvre avait en tête...
Modifier le collation d'une base de données SQL Server
Plus tôt aujourd'hui, j'ai remarqué une erreur qui traînait dans un système roulant sous SQL Server. Le collation d'une base de données avait été changé et comme tous les objets enfants héritent de la propriété au moment de la création (default collation), la comparaison des chaînes de caractères s'effectuait incorrectement dans certaines tables.
Sachant qu'un collation French_CS_AS effectue une évaluation du texte en étant sensible à la case (CS) et en tenant compte de la présence des accents (AS), une chaîne comme "Élections" n'équivaudra pas à "elections". Ça peut être embêtant si on s'attend à ce qu'ils correspondent à l'intérieur d'une requête SQL.
Pour connaître le collation actuellement configuré :
SELECT DATABASEPROPERTYEX('dbname', 'Collation')Pour réinitialiser le collation à utiliser au niveau BD pour les futures tables, on doit choisir le collation parmi la liste suivante :
SELECT * FROM ::fn_helpcollations()Je vais donc écraser le collation French_CS_AS par French_CI_AI (Case Insensitive / Accents Insensitive). Je pourrais être tenté de faire simplement ceci :
ALTER DATABASE dbname COLLATE French_CI_AIMais il est possible qu'un message d'erreur s'affiche s'il y a des locks actifs (par exemple des utilisateurs connectés, des transactions en cours, etc) :
Server: Msg 5030, Level 16, State 2, Line 1
The database could not be exclusively locked to perform the operation.
Server: Msg 5072, Level 16, State 1, Line 1
ALTER DATABASE failed. The default collation of database 'dbname' cannot be set to French_CI_AI.
Pour contourner ce problème de lock, on peut faire basculer la base de données en mode "utilisateur unique", effectuer le changement et le rétablir en mode multi-utilisateurs :
ALTER DATABASE dbname SET SINGLE_USERÀ noter que ça rétablira la propriété globale au niveau de la BD mais pas les collates conservés dans les champs textes individuels des tables existantes (char, nchar, varchar, nvarchar, text, ntext). Dans le cas où vous auriez besoin de changer le collate partout, vous devrez créer un script qui boucle dans tous les champs et qui appliquera le changement en exécutant un ALTER TABLE ALTER COLUMN...
WITH ROLLBACK IMMEDIATE
GO
ALTER DATABASE dbname COLLATE French_CI_AI
GO
ALTER DATABASE dbname SET MULTI_USER
SELECT so.name as tablename, sc.name as columnname, sc.length, st.name as typeFaites attention aux champs textes avec des clés étrangères, aux types text et ntext, car vous pourriez avoir de mauvaises surprises... À suivre.
FROM sysobjects as so
INNER JOIN syscolumns as sc ON sc.id = so.id
INNER JOIN systypes as st ON st.xtype = sc.xtype
WHERE so.type = 'U'
AND st.name IN ('char', 'nchar', 'varchar', 'nvarchar', 'text', 'ntext')
AND so.name NOT LIKE 'dt%'
ORDER BY tablename, columnname
L'utilisation du shell est un incontournable sous Linux. Il en existe plusieurs types dont voici un bref historique :
- sh (Bourne Shell) : créé par Stephen R. Bourne en 1977
- csh (C Shell) : créé par Bill Joy en 1979
- tcsh (C Shell amélioré) : créé par Ken Greer en 1979
- ksh (Korn Shell) : créé par David Korn en 1982
- bash (Bourne again shell) : créé par Brian Fox en 1987
- zsh (Z Shell) : créé par Paul Falstad en 1990
cat /etc/shells
Lorsqu'on est dans un terminal, le prompt sera généralement $ ou %. Cependant, plusieurs shells utilisent le même prompt (caractère en début de ligne). Comment savoir quel shell est en cours d'utilisation ?
echo $SHELL
Ceci est récupéré des variables d'environnement du terminal. On peut les faire afficher en entrant :
export
Résultat:
declare -x SHELL="/bin/bash"
Pour passer d'un type de shell à un autre, il suffit d'entrer le nom du shell : bash pour le Bourne Again Shell ou sh (pour le Bourne Shell). Remarquez que le prompt (invite) changera.
Je lisais les nouveaux chapitres de la deuxième édition du livre Peopleware de Tom DeMarco & Timothy Lister et au chapitre 27, ils font mention des fameux posters de motivation qui peuvent parfois être accrochés aux murs d'une entreprise.
Par exemple :
L'image est toujours accompagnée d'une phrase qui résume l'idée :
Teamwork is the ability to work together toward a common vision. It is the fuel that allows common people to attain uncommon result.
Ce sont des phrases inspirantes qui ont du sens, mais est-ce que le fait de les mettre à vue à l'attention des employés motive vraiment les troupes ? Je suis curieux d'entendre vos histoires là-dessus. Personnellement, j'ai été confronté une seule fois à ces affiches dans le cadre d'un emploi étudiant et je peux comprendre que les employés pouvaient avoir besoin d'un petit remontant : le travail était tellement aliénant!
Toute cette série d'affiches a aussi donné lieu à des parodies qu'on trouve un peu partout sur Internet dont celle-ci tirée d'une compilation Top 40 Demotivational Posters.
Je termine cette chronique en vous invitant à créer vos propres posters avec l'outil web Motivator. Voici ma création, inspirée directement de l'odeur du souper en train de cuire...
D'abord, bonjour à tous et bonne fête de l'Action de grâce (Thanksgiving), un événement que je ne célèbre pas mais qui me vaut au moins un congé bien apprécié! J'en profite donc pour faire une chose qui traîne depuis longtemps sur mon poste de travail à la maison : amorcer le transfert de mon serveur de développement vers une machine virtuelle.
En gros, j'avais installé sur mon OS Windows (hôte) tout le nécessaire pour pouvoir faire du développement dont EasyPHP qui, à force d'ajouter des modules à Apache et PHP, semble devenir de plus en plus instable. De plus, au démarrage du PC, le serveur de base de données PostgreSQL lance 6 processus en mémoire, ce qui alourdit le temps de chargement lorsque je n'en ai pas besoin. J'aurais pu juste éteindre le service par défaut mais ma décision était prise que ça serait plus logique d'avoir une VM Linux à qui déléguer le travail de serveur web de développement.
J'ai pris ma machine virtuelle Ubuntu fraîchement créée et j'y ai installé Apache :
sudo apt-get install apache2
Dans la VM, lorsque j'ouvre Firefox, je peux confirmer que tout fonctionne en entrant l'URL http://localhost ou http://127.0.0.1. Ceci affichera un fichier par défaut nommé index.html qui se trouve dans /var/www/ et qui contient la phrase explicite It works!.
Par contre, impossible d'y accéder par Windows de cette façon. Pour y arriver, on doit connaître l'adresse IP de la machine virtuelle. Si on sait que la commande ipconfig est pour Windows, ifconfig est pour Linux. Ouvrez un terminal et entrez ifconfig (interface configurator). Sous eth0, on trouvera l'IP juste à côté de inet addr: 192.168.136.134.
En basculant à Windows, je peux simplement copier l'IP dans Firefox et j'accède à mon serveur web virtuel : http://192.168.136.134.
Il suffira ensuite d'assigner un nom symbolique à l'IP dans le fichier hosts si on ne veut pas avoir à retenir l'IP.
Tout le monde aime Google Maps et ceux qui possèdent un commerce avec pignon sur rue désirent souvent afficher la carte pour indiquer leur localisation. Je vais vous montrer à quel point c'est facile d'intégrer Google Maps et je vous présenterai quelques options intéressantes.
D'abord, il vous faut une clé d'API (gratuite) qui est reliée au domaine sur lequel on veut l'installer (fonctionne aussi sur les sous-domaines et les répertoires).
Une fois en possession de votre clé, vous devrez faire un peu de JavaScript. Incluez en entête la librairie externe de Google Maps en prenant soin d'y placer votre clé d'API.
<script src="http://maps.google.com/maps?file=api&v=2&sensor=true&key=VOTRE_CLE" type="text/javascript"></script>Dans le code HTML, déclarez un conteneur dans lequel la carte s'affichera. Prenez soin d'attacher les fonctions aux événements load et unload (libre à vous de le faire comme ci-dessous ou avec Prototype ou jQuery).
<body onload="initGM()" onunload="GUnload()">Ouvrez un bloc JavaScript et déclarez les objets principaux :
<div id="mapHolder" style="width:800px;height:600px"></div>
</body>
var map;Je prendrai pour acquis qu'on utilisera la carte pour afficher qu'une seule coordonnée. Déclarez deux nouvelles variables qui contiendront les informations à afficher dans la bulle (lorsqu'on cliquera sur le marqueur) :
var geocoder;
var title = "La Banquise";Il faut définir la fonction qui initialise la carte au chargement de la page. Quelques lignes seraient suffisantes mais comme je présente quelques options, je commenterai au fur et à mesure dans le code.
var address = "994, Rue Rachel Est, Montreal, QC H2J 2J3";
function initGM() {Il ne reste qu'à définir la fonction addToMap() qui contrôle aussi le contenu affiché dans la bulle.
if (GBrowserIsCompatible()) {
// mapHolder est le conteneur HTML
map = new GMap2(document.getElementById("mapHolder"));
// on peut utiliser cette façon mais qui
// connait vraiment les coordonnées ?
// map.setCenter(new GLatLng(37.4419, -122.1419), 13);
// à la place, les trouver avec Geocoder!
geocoder = new GClientGeocoder();
// la variable address a été définie
// plus haut
geocoder.getLocations(address, addToMap);
// constantes du choix de carte
// G_NORMAL_MAP
// G_SATELLITE_MAP
// G_HYBRID_MAP
map.setMapType(G_NORMAL_MAP);
// affiche les contrôles par défaut
// (zoom et types de cartes)
// map.setUIToDefault();
// ou bien, personnaliser les contrôles
// on doit utiliser addControl
var mapTypeControl = new GMapTypeControl();
// positions possibles
// G_ANCHOR_TOP_RIGHT
// G_ANCHOR_TOP_LEFT
// G_ANCHOR_BOTTOM_RIGHT
// G_ANCHOR_BOTTOM_LEFT
var topRight = new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(10,10));
map.addControl(mapTypeControl, topRight);
// pour le contrôle de zoom
// GSmallMapControl / GLargeMapControl
// GLargeMapControl = la barre verticale
// dégradée
map.addControl(new GSmallMapControl());
}
}
function addToMap(response){Ça peut ne pas sembler très clair ce que je fais avec var streetAddress = place.AddressDetails... mais si vous éclatez l'objet "place" avec Firebug (console.log(place)), vous aurez accès à toute la structure de l'objet JSON qui permet de récupérer toutes les informations de géolocalisation sur le point demandé.
place = response.Placemark[0];
// obtenir la latitude et longitude
point = new GLatLng(place.Point.coordinates[1], place.Point.coordinates[0]);
// centrer la carte sur ce point
// 18 représente la profondeur du zoom
map.setCenter(point, 18);
// créer le marqueur
var numberedIcon = new GIcon(G_DEFAULT_ICON);
// permet de changer l'icône par défaut
// par exemple le logo de l'entreprise
// numberedIcon.image = 'http://www.domaine.com/marker.png';
markerOptions = { icon:numberedIcon, clickable:true };
marker = new GMarker(point, markerOptions);
// ajouter le marqueur à la carte
map.addOverlay(marker);
GEvent.addListener(marker, "click",
function() {
var streetAddress = place.AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.Locality.Thoroughfare.ThoroughfareName;
var city = place.AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.Locality.LocalityName;
var state = place.AddressDetails.Country.AdministrativeArea.AdministrativeAreaName;
marker.openInfoWindowHtml(
'<strong>' + title + '</strong>' + '<br>' + streetAddress + '<br>' + city + ', ' + state);
}
);
}
Je n'ai pas encore pris le temps de régler l'affichage du code sur mon blogue alors je vous suggère de l'ouvrir en cliquant sur "view plain" dans le coin supérieur gauche des blocs de code pour le voir mieux indenté et sans retour de chariots automatiques.
Vous voilà maintenant avec une carte fonctionnelle.
Pour masquer une ignorance lexicale, Perceval utilise l’expression suivante :
C’est pas faux.
Problème avec le service Google Maps : non disponible
Ce matin, j'étais en train de préparer un article expliquant comment intégrer Google Maps à son site web (avec certaines options) et alors que je testais différentes configurations, le service de Google s'est soudainement interrompu et la carte ne s'affichait plus.
J'ai ouvert Firebug et j'ai vu dans la console deux messages d'erreurs consécutifs : GUnload is not defined et GBrowserIsCompatible is not defined. C'était curieux car j'ai révisé le code source et tout semblait en ordre.
Ensuite, j'ai examiné les headers HTTP (sous l'onglet NET de Firebug), je me suis rendu compte que l'appel à "http://maps.google.com/maps" retournait l'erreur 503 : Service Unavailable.
Pourquoi le service ne serait pas disponible ? Serait-ce une panne ? J'ai ouvert le node (+) GET sorry?continue... pour connaître le détail et les sous-onglets Response et HTML ont pu m'éclairer sur ce qui se passait.
Il semblerait que vu le nombre répété de requêtes vers son service, il ait considéré mes demandes comme étant douteuses. Sous HTML, on peut voir le message suivant :
We're sorry... but your computer or network may be sending automated queries. To protect our users, we can't process your request right now. To continue searching, please type the characters you see below : [captcha].
J'ai fait le test de cliquer avec le bouton droit de la souris sur le lien "GET sorry?continue...", j'ai fait "Open in new tab" pour accéder à la page. J'ai entré le captcha et lorsque je suis retourné sur ma page qui incluait l'appel à Google Maps, le service était à nouveau disponible.
J'ai refait tout le processus pour faire afficher la trace de la création des cookies et il semblerait que dans certains circonstances, Google refuse de créer le cookie GDSESS qui est nécessaire à l'authentification du service de cartographie. Dès que le captcha est correctement remplit, ce cookie est créé et il le service fonctionnera tant et aussi longtemps qu'il existera.
Bien qu'il y ait eu bon nombre de contributeurs (des milliers), on attribue souvent le mérite de Linux à son créateur original, Linus Torvalds (la preuve : nommez moi en un autre!).
Selon le document Linus Torvalds, A Very Brief and Completely Unauthorized Biography (source: LIFO - Linux Information Project) en date de 2006, M. Torvalds aurait écrit environ l'équivalent de 2% du noyau actuel (ce qui est quand même beaucoup).
[Traduction libre]
Aujourd'hui, le code source complet de la version 2.6 du kernel pèse environ 80 Mo. Linus possède la marque de commerce "Linux" et prend toutes les décisions finales concernant les ajouts et modifications proposés.
Ses critères d'évaluation sont :
- la haute qualité et la clareté du code
- la facilité de la maintenance
- doit être bénéfique à un large éventail d'utilisateurs, plutôt qu'un seul ou une entreprise
Un extrait des notes qui fera peut-être un jour parti de l'histoire, paragraphe 7. Apologies :-) :
This isn't yet the "mother of all operating systems"...
Mais qui sait si ça le deviendra ?
En guise de conclusion :
Happy hacking.
Faut croire que c'est tous les jours fête chez Future Shop! Ce matin, j'ai reçu par courriel (liste de diffusion) cette publicité qui annonce un Solde de la Fête de fin de semaine. Dans mon calendrier à moi, c'était plutôt écrit "longue fin de semaine de l'action de grâce" mais bon, ça évolue tellement vite ces affaires là...
J'explorais différentes commandes dans un terminal Linux sur mon netbook Acer Aspire One et j'ai commencé à faire afficher différentes informations système :
Obtenir la version du noyau
cat /proc/version
2.6.28-11
Décrire l'utilisation de la mémoire vive
cat /proc/meminfo
1 016 888 bytes (1 Gb)
488 700 bytes de disponible (et j'ai activé plusieurs effets visuels "eyecandy")
Obtenir de l'information sur le microprocesseur
cat /proc/cpuinfo
Intel Atom N270 800 1.6 GHz
Dans la multitude de lignes de résultats de cette dernière commande, j'en ai vu une qui mesurait le BogoMIPS.
BogoMIPS : 3192.23
Comme dirait l'autre : kossé ça ? Le BogoMIPS (million instructions per second) est une mesure non-scientifique qui sert à calibrer une boucle d'activité interne et qui pourrait être décrite comme étant "le nombre de millions de fois par secondes que le processeur peut faire absolument rien". En gros, ça mesure de la vitesse de calcul d'un programme. Cette mesure est calculée au démarage selon une échelle de comparaison avec le processeur Intel 386DX.
Faits :
- Le plus faible score (0.02 BogoMips) a été enregistré sur un Intel 8088, 4.77 MHz, ELKS.
- Le meilleur score (3776.00 BogoMips) a été fait par un Sequent NUMA-Q, 32 CPUs P6, à 180 MHz (système d'exploitation Dynix - Dynamic Unix).
Ces dernières années, j'ai utilisé Dreamweaver que pour les quelques rares fois où j'ai eu besoin de l'éditeur WYSIWYG (mode Design). Récemment, j'ai ouvert une page PHP dans Dreamweaver et j'ai vraiment regretté...
Dans un cas très particulier, Dreamweaver modifie les variables écrites en "camel case" pour les transformer entièrement en minuscule. Et comme c'était une page PHP et que dans ce langage, les variables sont sensibles à la casse, ça a fait un beau gâchis dans de nombreuses pages de mon projet. Ce qui veut dire que $maVariable n'équivaut pas à $mavariable.
Le pire dans tout ça, c'est qu'à l'ouverture d'un fichier, Dreamweaver applique les modifications et ne montre pas que le fichier a été modifié ! Il transforme certaines variables à notre insu en suivant les directives inscrites dans les préférences.
Le contexte est particulier. Lorsque du code dynamique est placé à l'intérieur d'une balise HTML, par exemple pour ajouter un attribut de style, que ce code est écrit sur une seule ligne, sans qu'il y ait d'espace entre la fermeture du code dynamique et l'attribut HTML, il transforme ce qui se trouve entre en minuscule.
Par exemple, le code suivant :
<div$iCamelCaseVariable et $myObject seront transformés si DW trouve ceci :
<?php if($iCamelCaseVariable >= $myObject->method()) { ?>
style="display:none;"
<?php } ?>
>
method()) { ?>style="display:none;"<?php } ?>
Et ne le seront pas lorsqu'il détecte l'espace avant l'attribut style :
method()) { ?> style="display:none;"<?php } ?>
Ceci se produit en raison d'une configuration de l'application qui force l'édition du code à être uniforme, mais Dreamweaver ne semble pas considérer ou détecter correctement qu'il y a du code PHP et applique la règle à l'ensemble du code, pas seulement aux marqueurs HTML.
Heureusement, j'ai remarqué que l'option était inactive par défaut sous CS4. Sinon, on peut la désactiver par ici :
- Menu Edit / Preferences / Code Format
- Décocher l'option Override case of : Attributes
- Dans le cas contraire, Dreamweaver appliquera la règle spécifiée sous "Default attribute case"
J'ai observé ce comportement dans Dreamweaver, depuis au moins la version 8 jusqu'à la plus récente CS4.
On définit généralement la musique comme étant une forme d'expression qui agence et ordonne les sons et les silences. Par convention, la plupart des gens s'entendront pour dire qu'il y aura plus de sons que de silences.
Or, en 1952, le compositeur avant-gardiste John Cage (à ne pas confondre avec Johnny Cage, le personnage de Mortal Combat) a eu une vision qui pourrait sembler absurde : écrire une composition en trois mouvements composée uniquement de silences, le tout d'une durée totale de 4 minutes et 33 secondes (d'où le titre de la pièce).
Par sa pensée originale, Cage considérait que le silence était aussi de la musique et il a tenté d'exploiter ce contexte pour expérimenter. Plusieurs ont été amusés de son initiative alors que pour les autres, c'était totalement controversé et inacceptable.
Si vous voulez vivre l'expérience en tant qu'auditeur, voici une représentation vidéo en concert de 4'33".
Quand même, vous devrez avouer que c'est paradoxal de voir le chef diriger l'orchestre, l'interprétation des musiciens qui tournent les pages de partitions en même temps jusqu'aux applaudissements du public à la fin de la prestation.
Très populaire dans l'univers Unix/Linux, le FIGlet est un programme qui génère du texte sous forme d'art ASCII à l'aide de caractères. Autrement dit, comme celui-ci :
Même si ça date d'une autre époque, on peut aujourd'hui s'en servir pour l'appliquer sur des formulaires web en guise de captcha.
Le Zend Framework fournit un composant nommé Zend_Text qui inclut une classe pour générer des figlets très facilement. Par exemple, deux lignes de code PHP suffisent pour en générer un :
$figlet = new Zend_Text_Figlet();Le problème, c'est qu'en n'étant pas bordé de balises PRE, il s'affiche sur une seule ligne.
echo $figlet->render('Code 18');
On peut aussi configurer différents paramètres en passant un array au constructeur. À l'intérieur, on pourra optionnellement changer la font mais Zend en fournit une seule par défaut (zend-framework.flf). On pourra visualiser et télécharger d'autres fonts sur figlet.org.
$options = array(Une fois le fichier .flf téléchargé (ce n'est qu'un léger fichier texte), on le placera sur le serveur ou dans Zend/Text/Figlet. Comme Zend_Text_Figlet utilise file_exists() au moment de charger la font, il ne résout pas les chemins selon les directives dans le include_path, on devra fournir le chemin absolu (comme dans l'exemple ci-dessus).
'font' => '/var/www/project/Zend/Text/Figlet/small.flf',
'outputWidth' => 100,
'justification' => Zend_Text_Figlet::JUSTIFICATION_CENTER,
'rightToLeft' => Zend_Text_Figlet::DIRECTION_LEFT_TO_RIGHT
);
$figlet = new Zend_Text_Figlet($options);
echo '<pre style="font-size:small;">';
echo $figlet->render('Code 18');
echo '</pre>';
Si vous comptez l'utiliser, sachez que les fonts ne contiennent pas tous les caractères et que les accents ne sont pas reconnus. Je recommande l'utilisation limitée des caractères alphanumériques pour éviter les mauvaises surprises.
À mon travail, certains employés préfèrent programmer à la clareté, d'autres dans une quasi noirceur.
Un matin, un des programmeurs est arrivé à son poste et a allumé la lumière alors que certains membres de l'équipe étaient déjà présents. Un des programmeurs s'est plaint et a prétendu qu'on est plus productif lorsque la lumière est éteinte.
Je ne sais pas si c'est fondé mais ça m'a fait penser que son argument pouvait provenir de l'effet Hawthrone.
Il s'agit d'une expérience menée entre 1927 et 1932 où les résultats ne sont pas dus aux facteurs expérimentaux mais au fait que les sujets sont conscients de participer à une expérience dans laquelle ils sont testés, ce qui se traduit généralement par une plus grande motivation (Wikipedia).
Selon le professeur Elton Mayo qui mena l'étude, lorsqu'il augmentait l'intensité de la lumière, la productivité s'améliorait. Par contre, en réduisant la luminosité, la productivité augmentait encore plus par rapport aux conditions de travail normales.
Il a énoncé l'hypothèse qu'en fermant complètement la lumière, la productivité s'améliorerait grandement. Or, il a remarqué que ce n'était pas tant le niveau de luminosité qui influençait la productivité : c'était l'attrait du changement qui stimulait les gens.
Ce qui lui a permis de conclure que les gens performent mieux lorsqu'ils essaient des choses nouvelles qu'en étant dans la routine.
Laissez cent fleurs s'épanouir, laissez cent écoles de pensées rivaliser.
Ce matin, j'ai décidé de présenter le cron de Linux. Qu'est-ce que le cron ? D'abord, le nom vient du diminutif du mot "chronograph", qui est un programme système qui permet d'exécuter des tâches planifiées dans le temps (job scheduler).
Cron est aussi un daemon, c'est-à dire un processus qui roule en arrière-plan en attendant qu'il soit sollicité. Lorsque le processus est en fonction, il lira les instructions dans un fichier de configuration nommé crontab qui définit à quel moment précis il doit exécuter les tâches. Chaque utilisateur peut avoir son propre crontab mais dans le cadre de ma démonstration, je vais procéder en tant que l'utilisateur root.
Comme tâche, on pourrait faire rouler n'importe quel type de script (Bash, Perl, PHP, etc). Ici, j'en utiliserai un écrit en PHP qui imprimera dans un fichier texte un timestamp par ligne à chaque exécution. J'indiquerai au cron de rouler le script à chaque minute et nous pourrons suivre la progression en temps réel.
1. Exemple de script PHP
$file = "/code18/test/log.txt";À partir de la racine, je placerai ce script dans /code18/test/cron.php.
$fh = fopen($file, 'a') or die("Oups");
fwrite($fh, date("Y-m-d H:i",time()) . "\n");
fclose($fh);
2. Comprendre la syntaxe
Définir un cron se fait par une ligne :
- Les 5 premiers champs représentent la fréquence
- Le 6ème représente la ligne de commande (chemin de l'interpréteur)
- Le 7ème est pour le chemin du script
- Minute de l'heure : 0 à 59
- Heure du jour : 0 à 23
- Jour du mois : 1 à 31
- Mois de l'année : 1 à 12, ou textuel en anglais (voir plus bas)
- Jour de la semaine : 0 à 6, dimanche étant zéro
Par exemple, si on veut rouler le script :
- le 15 du mois : 15
- le 15 et le 30 du mois : 15,30
- du 15 au 20 du mois : 15-20
- tous les jours du mois : *
Ce dernier est pratique pour exécuter quelque chose au moment du démarage de l'ordinateur. Dans mon cas, pour exécuter mon script à chaque minute, la fréquence sera : * * * * *
Pour trouver le chemin de l'interpréteur PHP, on peut utiliser la commande which qui retourne le chemin absolu à utiliser :
which php
Sur ma machine :
/usr/bin/php
Finalment, mon script se trouvera dans /code18/test/cron.php
3. Modifier le fichier crontab
À partir d'un terminal, lancer la commande :
crontab -l
Ceci listera les tâches planifiées pour l'utilisateur courant. Pour en ajouter une, il faudra modifier le fichier de configuration :
crontab -e
Ceci ouvrira le fichier de configuration avec l'éditeur par défaut. Si comme moi vous n'aimez pas vi (lancé par défaut sous Fedora), vous pouvez vous référer à mon entrée de jeudi pour savoir comment le substituer par nano.
Dans le haut de la fenêtre, remarquez le nom du fichier :
File: /tmp/crontab.XXXXXXXXXXX
Ne vous fiez pas au fait qu'il soit dans le répertoire temporaire. Comme vous modifiez le fichier par crontab, il crée une nouvelle tâche et la déplacera automatiquement au bon endroit au moment de la sauvegarde.
Ajoutez la ligne suivante (adaptez la à vos besoins) :
* * * * * /usr/bin/php /code18/test/cron.php
Enregistrez le fichier et sortez de nano. Créé en tant que root, les instructions sont placées dans le fichier /var/spool/cron/root.
4. Est-ce que ça marche ?
Exécutez à nouveau crontab -l pour vous assurer que la tâche a bien été ajoutée. Vous devriez voir la ligne s'afficher. Maintenant, je veux m'assurer que le script fonctionne bien. Je vais l'ouvrir avec less
less /code18/test/log.txt
Une fois less lancé, je peux suivre la progression de ce qui est ajouté à la fin du fichier en faisant la combinaison des touches SHIFT+F. À chaque minute, un enregistrement sera ajouté à la fin et je le verrai apparaître (vous verrez un message "Waiting for data"). CTRL+Z pour sortir de ce mode.
5. Supprimer les tâches
Vous pouvez retirer la ligne du fichier ou simplement appeler la commande crontab -r pour tout effacer les ordres.
Voici une info-publicité des plus inquiétantes! Je ne peux pas croire que c'est vrai, même si c'en a l'air. J'en ris tellement que j'en ai mal à la mâchoire !
Connaissez-vous l'approche Do-Hy ? Voyez le clip vidéo :
Après vérification :
- un site web existe à l'adresse www.dohy.net
- sur PagesJaunes.ca, le numéro de téléphone apparaissant à l'écran est en fonction
- pratiquement tous les témoins sont de la famille Lavallée
- noms à coucher dehors :
- Éveille Lavallée, guide spirituel
- Lafleur-Guy Lavallée (Guy Guy Guy!)
- Sinuzette Lavallée
- Éveille Lavallée, guide spirituel
- je cite : Sinuzette dit qu'elle se nettoie le nez avec de l'eau (sinus ?)
- apparition de mots à l'écran : chiiii...
- "tecnique" au lieu de "technique" (ajouté par la suite ?)
- pratiquer la technique Spïn-Grën dans la douche...
Configurer l'éditeur par défaut dans un terminal Linux
En essayant de configurer un cronjob par un terminal Linux, j'étais agacé par le fait que lorsque je lançais crontab, l'éditeur qui démarrait par défaut était vi :
crontab -e
Comme c'est le cas ici, crontab tente de lire une variable d'environnement du shell nommée EDITOR qui détermine l'éditeur par défaut à lancer lorsque la commande est appelée.
Pour modifier ma préférence session et utiliser nano, je dois utiliser la commande suivante :
export EDITOR=nano
L'appel à crontab -e démarre maintenant nano. Il faut se souvenir que cette modification est valable que pour la session en cours. Si on ferme le terminal et on en ouvre un autre, la préférence sera perdue. Pour éviter que ça arrive, on peut conserver cette configuration en l'ajoutant au script .bashrc. Ce fichier permet de définir, pour chaque utilisateur, comment le shell réagira.
Pour l'utilisateur root, on le trouvera dans /root/.bashrc. Sinon, chaque utilisateur aura son propre fichier dans /home/[user]/.bashrc. Si vous listez les fichiers avec ls, il sera nécessaire de les afficher tous, même ceux commençant par un point, en utilisant : ls -a.
Aussi, on peut accéder à son répertoire personnel en tappant : ~/
On ouvrira le script à modifier avec ceci :
nano ~/.bashrc
Ajouter la ligne :
export EDITOR=nano
Le prochain terminal que vous ouvrirez utilisera cette nouvelle configuration (aucun redémarrage du système n'est requis).