Say hello to MySQL

Why does software so often fail to understand basic social conventions?

MySQL - Hello

A tip to improve the performance of your Bloomberg API application

If you make a request for data which results in a lot of events generated by Bloomberg API (such as long historical intraday data request, or possibly real time subscriptions), do not use the pattern specified in the API documentation, as it may end up making your application very slow to retrieve all events. Basically, do not call NextEvent() on a Session object, use a dedicated EventQueue instead.

Instead of doing this:

var cID = new CorrelationID(1);
session.SendRequest(request, cID);
do {
   Event eventObj = session.NextEvent();
   ...
}

Do this:

var cID = new CorrelationID(1);
var eventQueue = new EventQueue();
session.SendRequest(request, eventQueue, cID);
do {
   Event eventObj = eventQueue.NextEvent();
   ...
}

This simple change may yield performance improvements by an order of magnitude (or not, as the API is known to not be particularly deterministic…).

Recursive algorithm to generate all combinations of elements in successive enumerables

If you need to flatten ordered enumerables, that is taking one element of each enumerable, in order, to flatten a combination, here is a quick solution in C# and VB.NET, accompanied with an example:

Code in VB.NET:

Private Shared Sub GetCombinationsRec(Of T)(sources As IList(Of IEnumerable(Of T)), chain As T(), index As Integer, combinations As ICollection(Of T()))
	For Each element As var In sources(index)
		chain(index) = element
		If index Is sources.Count - 1 Then
			Dim finalChain = New T(chain.Length - 1) {}
			chain.CopyTo(finalChain, 0)
			combinations.Add(finalChain)
		Else
			GetCombinationsRec(sources := sources, chain := chain, index := index + 1, combinations := combinations)
		End If
	Next
End Sub

Public Shared Function GetCombinations(Of T)(ParamArray enumerables As IEnumerable(Of T)()) As List(Of T())
	Dim combinations = New List(Of T())(enumerables.Length)
	If enumerables.Length > 0 Then
		Dim chain = New T(enumerables.Length - 1) {}
		GetCombinationsRec(sources := enumerables, chain := chain, index := 0, combinations := combinations)
	End If
	Return combinations
End Function

Code in C#.NET:

private static void GetCombinationsRec<T>(IList<IEnumerable<T>> sources, T[] chain, int index, ICollection<T[]> combinations) {
	foreach (var element in sources[index]) {
		chain[index] = element;
		if (index == sources.Count - 1) {
			var finalChain = new T[chain.Length];
			chain.CopyTo(finalChain, 0);
			combinations.Add(finalChain);
		}
		else {
			GetCombinationsRec(sources: sources, chain: chain, index: index + 1, combinations: combinations);
		}
	}
}

public static List<T[]> GetCombinations<T>(params IEnumerable<T>[] enumerables) {
	var combinations = new List<T[]>(enumerables.Length);
	if (enumerables.Length > 0) {
		var chain = new T[enumerables.Length];
		GetCombinationsRec(sources: enumerables, chain: chain, index: 0, combinations: combinations);
	}
	return combinations;
}

Usage is simple:

Dim list1 = New String() {"hello", "bonjour", "hallo", "hola"}
Dim list2 = New String() {"Erwin", "Larry", "Bill", "Steve"}
Dim list3 = New String() {"!", ".."}
Dim result = Utils.GetCombinations(list1, list2, list3)
For Each r In result
    Debug.Print(String.Join(" "c, r))
Next

or in C#:

var list1 = new[] { "Hello", "Bonjour", "Hallo", "Hola" };
var list2 = new[] { "Erwin", "Larry", "Bill", "Steve" };
var list3 = new[] { "!", "..." };
var result = Utils.GetCombinations(list1, list2, list3);
foreach (r in result) {
    Debug.Print(string.Join(" ", r));
}

As with any recursive function, memory usage can be exponential so make sure you know the number of target combinations is reasonable. Speed-wise, parallelizing this function is not worth it as we are just iterating over the elements.

How to replace Drupal core’s tracker module using views

This can be pretty handy, especially if you would like to customize it a bit more and add other tabs. Here is a simple step-by-step tutorial:

  1. Disable Drupal’s original core tracker module.
  2. Install views.
  3. Go to Site Building > Views and enable the tracker view.
  4. In the tracker view, go to the Page item, and rename it for example as “Recent posts” in Basic settings > Name and Basic settings > Title.  Make sure you click on override before saving, so that you keep the original configuration in Defaults.
  5. In the Page settings fieldset, set Path to tracker/all and the type to Default menu tab. Set Title to Recent posts and Weight to -10. Click on update and when asked for the Parent menu item, select Normal menu item, and once again type Recent posts as Title. Click on update. We are done with this page type that will display the latest nodes modifications by all users. You can now enjoy the power of views and tweak the display to precisely show what you have in mind.
  6. In the left drop-down list, select Page and click Add display. Rename it for example as “My recent posts” in Basic settings > Name and Basic settings > Title.  Make sure you click on override before saving, so that you keep a version of the original values.
  7. In the Page settings fieldset, set Path to tracker/my and the type to Menu tab. Set Title to My recent posts and Weight to 1. Click on update.
  8. In the Arguments fieldset, click on Node: User posted or commented (if it doesn’t exist, add it), and as the Action to take if argument is not present, select Provide default argumentUser ID from logged in user.
  9. That’s it! The link to your new tracker view is mysite.com/tracker; two tabs will be displayed just like in the original core module. You may for example create a menu item that links to this page.

Cloning objects with events in Visual Basic .NET

The easiest way to clone an object (deep copy) in .NET is to use the serialization functions available:

    Public Shared Function CloneObject(ByVal obj As Object) As Object
        If Not obj Is Nothing Then
            Dim bf = New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter()
            Dim fs = New System.IO.MemoryStream()
            bf.Serialize(fs, obj)
            fs.Seek(0, System.IO.SeekOrigin.Begin)
            Dim copy = CType(bf.Deserialize(fs), Object)
            fs.Close()
            Return copy
        Else
            Return Nothing
        End If
    End Function

Though the performance is not very good, for occasional operations it will do the job perfectly. However, I was confronted to the following problem: what if there are events inside the class, to which other objects have subscribed? I found several methods (and functions :-)) on various places over the Internet; they basically were:

  • Implement ISerializable yourself (meaning you have to update it each time you modify the class);
  • Disconnect from events (retrieved using Reflection), serialize the object, and then reconnect the events (I could not make this working properly);
  • Implement a serialization surrogate;
  • Implement your events in a separate class that is not serialized;
  • Implement your events in a C# base class.

Plenty of potential solutions, but none of them was good enough for me. So I played around with Reflection and found something that nobody else might have done so far. For a cloning interface that does just a shallow copy, like what MemberwiseClone does, but without event, I wrote this:

    Public Function Clone() As Object Implements System.ICloneable.Clone
        Dim cl = New MyClassName(Me)
        'Here we don't capture events, only normal fields, including non public ones (private, protected...)
        Dim FldInfos() As Reflection.FieldInfo = Me.GetType.GetFields(Reflection.BindingFlags.Instance Or Reflection.BindingFlags.Public Or Reflection.BindingFlags.NonPublic)
        For Each FldInfo As Reflection.FieldInfo In FldInfos
            FldInfo.SetValue(cl, FldInfo.GetValue(Me)) 'For serialization purpose we just need not to have events, so no need to perform a deep copy of the fields.
        Next
        Return cl
    End Function

Now if one of your class member is an object with events (or if you want to perform a deep copy), you should call its clone method (to be implemented the same way) when performing the FldInfo.SetValue, like this:

        For Each FldInfo As Reflection.FieldInfo In FldInfos
            If FldInfo.Name <> "MyObjectWithEvents" Then
                FldInfo.SetValue(cl, FldInfo.GetValue(Me)) 'It is not really necessary to clone a possible reference class member here for serialization purpose, we just need not to have events in the clone
            Else
                FldInfo.SetValue(cl, Me.MyObjectWithEvents.Clone())
            End If
        Next

If you have an object that is for example a dictionary of objects with events, you can call this:

        For Each FldInfo As Reflection.FieldInfo In FldInfos
            If FldInfo.Name <> "MyObjectsWithEventsDictionary" Then
                FldInfo.SetValue(cl, MyLib.CloneObject(FldInfo.GetValue(Me))) 
            Else
                FldInfo.SetValue(cl, Me.MyObjectsWithEventsDictionary.ToDictionary(Of String, MyObjectWithEvent)(Function(entry) entry.Key, Function(entry) CType(entry.Value.Clone(), MyObjectWithEvent)))
            End If
        Next

Finally, if you intend to use the Clone interface to serialize objects, you should make sure you don’t include class members marked as NonSerialized():

        For Each FldInfo As Reflection.FieldInfo In FldInfos
            If Not FldInfo.IsNotSerialized Then
                FldInfo.SetValue(cl, FldInfo.GetValue(Me))
            End If
        Next

I hope this will give you an insight to build something more tailored to your needs. There are other optimizations I can already think of, such as implementing a recursive Clone function where you would just put your original object and a virgin instance of it as a reference, and get a perfect serializable deep copy, whatever the class members and sub class members are! This could become a universal Clone method…

How to sort WordPress posts by modified date instead of published date?

Here is the simple solution. Simply use this:

<?php query_posts($query_string . '&orderby=modified&order=desc'); ?>

before where the Loop checks for posts:

<?php /* If there are any posts: */ 
if (have_posts()) ...
?>

It basically adds a condition to the Loop. Enjoy!

Le primat du software

Walter Mossberg and Kara Swisher interview Steve Jobs and Bill Gates at ‘D5: All Things Digital’ conference in Silicon Valley in 2007. Quotes made during the time of the photograph.

Kara: “What you think each has contributed to the computer and technology industry, starting with you, Steve, for Bill, and vice versa.”

Steve: “Bill built the first software company in the industry and I think he built the first software company before anybody really in our industry knew what a software company was, except for these guys. And that was huge. That was really huge. And the business model that they ended up pursuing turned out to be the one that worked really well, you know, for the industry. I think the biggest thing was, Bill was really focused on software before almost anybody else had a clue that it was really the software.”

Walt: “Bill, how about the contribution of Steve and Apple?”

Bill: “Well, first, I want to clarify: I’m not Fake Steve Jobs. [Peals of laughter.] What Steve’s done is quite phenomenal, and if you look back to 1977, that Apple II computer, the idea that it would be a mass-market machine, you know, the bet that was made there by Apple uniquely—there were other people with products, but the idea that this could be an incredible empowering phenomenon, Apple pursued that dream. Then one of the most fun things we did was the Macintosh and that was so risky. People may not remember that Apple really bet the company. Lisa hadn’t done that well, and some people were saying that general approach wasn’t good, but the team that Steve built even within the company to pursue that, even some days it felt a little ahead of its time—I don’t know if you remember that Twiggy disk drive and…”

Bill Gates and Steve Jobs at D5: all things digital

Aujourd’hui encore, le software n’a pas perdu de sa superbe et de son importance. Plusieurs exemples sont là pour nous le rappeler.

Synaptics est le principal équipementier en pavés tactiles (touchpads) pour ordinateurs portables. Regardez dans la liste des drivers de votre machine, il y a de bonnes chances pour que ce nom apparaisse quelque part.
En septembre dernier, ils ont sorti en grande pompe plusieurs nouvelles gestures rappelant celles utilisables sur des écrans multitouch. On aurait pu saluer l’innovation et s’en arrêter là. Oui mais voilà, ces fonctionnalités auraient pu être implémentées depuis plus de 5 ans ! Le hardware, et même le firmware peuvent depuis bien longtemps différencier les doigts, capter leurs coordonnées absolues (comme une tablette graphique), et ce avec une résolution d’environ 640×480 ! Pourtant, seuls trois misérables logiciels de démonstration étaient jusqu’alors disponibles sur le site de Synaptics. Quant au SDK, il n’a pas été mis à jour depuis 2004. Si aujourd’hui le nouveau driver offre quelques gestures supplémentaires (et encore pas disponibles sur tous les firmware malgré la compatibilité matérielle), Il faut donc toujours passer par la pseudo API en C++ pour accéder à la matrice générée par le touchpad et créer un gestionnaire de fonctionnalités supplémentaires.

Théorie du complot ou non sur les raisons de ce bridage, on peut surtout retenir que le fabricant du hardware ne verse pas beaucoup dans le software, et c’est donc une inefficience qu’il faut combler ! On peut imaginer bon nombre d’applications qui pourraient profiter à plusieurs centaines de millions d’utilisateurs instantanément.

On ne se rend pas non plus compte à quel point les connectiques comme le bluetooth ou le Wifi ne sont utilisées que partiellement par le software qui les accompagne. Une start-up a d’ailleurs développé des drivers Wifi voués à faire au moins aussi bien que le Bluetooth en termes de débit de données et consommation électrique pour des applications identiques (casque, clavier…). Voilà qui risque de faire un peu d’ombre au consortium Bluetooth.
Je cherchais moi-même à faire quelque chose a priori très simple : lire simultanément de la musique sur mon ordinateur et celui de mon frère, lorsqu’on est physiquement peu éloigné. Les solutions trouvées ont été les suivantes :
Développer un script AutoIT qui synchronise la lecture des morceaux via le réseau (avec une parfaite synchronisation d’horloge),
Mettre en place un serveur de streaming temps réel (contrairement à Youtube ou à toutes les webradios, il s’agit de pouvoir écouter avec seulement quelques millisecondes d’écart le son qui est joué sur le serveur, il n’est donc pas possible d’avoir extensivement recours à la mémoire tampon),
Utiliser un bon vieux câble audio reliant la prise casque d’un ordi à la prise line in de l’autre.

Chaque solution présente des inconvénients : la première suppose que les bibliothèques des deux ordis soient identiques ou très proches, la deuxième n’offre pas une qualité d’écoute suffisamment stable (distortions comme en VoIP), et la troisième vous fait réaliser qu’il n’est même pas possible sur un ordi portable de choisir de ne pas désactiver les hauts-parleurs lorsque quelque chose est branché sur la prise line out (seul mon ordinateur, un Asus F3JA, et la version courante de mon driver son, présente un dysfonctionnement qui permet d’avoir les 2 simultanément au sortir d’une mise en veille :-), cela suppose donc d’utiliser un jack et des hauts parleurs externes au moins sur l’ordinateur émetteur.

Ne devrait-on pas pouvoir envoyer de l’analogique ou quasi analogique (pour éviter toute décompression complexe ou gestion des pertes) avec un protocole approprié sur un câble RJ45 ? Ce câble n’a pas moins de fonctionnalité qu’un câble audio classique. Mais soit, plutôt que d’inventer un nouveau protocole from scratch, pourquoi ne peut-on pas tout simplement activer le profil standardisé “Headset” ou “Generic Audio Video Distribution Profile” sur le PC de destination du signal ? Aujourd’hui, on ne peut pas par défaut utiliser un PC comme extension sonore d’un autre PC, sans raison valable vu que tout le hardware nécessaire est pourtant là. En allant plus loin, pourquoi est-il impossible d’utiliser les profils bluetooth standards sur des réseaux Ethernet Wifi ou RJ45 ?

Si le hardware a atteint une certaine maturité, on voit donc que le software en est encore à ses balbutiements en terme de mise en valeur des périphériques sous-jacents. Espérons que les interfaces utilisateurs à venir basées sur le multitouch et les caméras 3D s’accompagneront également d’une révolution en termes de software. On peut bien sûr compter sur les fabricants de hardware, mais je ne saurais que trop nous conseiller à nous tous, utilisateurs et développeurs, d’être à l’origine de cette refondation du rapport de l’homme à la machine. C’est ni plus ni moins ce qu’ont su faire en leur temps, dans une perspective business appropriée, Apple et Microsoft.

Du software, toujours du software !

ASIN to EAN converter

Since I was needing an EAN to ASIN converter and ASIN to EAN converter (UPC/barcode and Amazon code), but could not find any on the web, I decided to write one myself. It is always fun to learn a new API (here I used Amazon Web Services). And when it works exactly as you expect, you are definitely API!

You can input several codes (batch mode) by separating them with “;” (semicolon). The output will be one column with the original code and another with the converted code.

So, long story short, here comes the beauty, and the beast (also available here on a dedicated page/window):

This converter can easily be embedded on your own website using the following code:

<iframe style="border: solid 1px #ccc;" src="https://www3.erwinmayer.com/labs/asin2ean/" width="490" height="630"></iframe>

Latest features:
30/12/2014: Tab in URL and locale persistence.
19/12/2014: Responsive/Mobile-friendly version.
09/12/2014: Much faster batch operations & UI rewritten for easier readability.
09/06/2014: UI improvements for batch operations.
30/04/2014: Added support for BR (Brazil) and IN (India) locales.
02/10/2011: Added support for ES (Spain) locale.
27/08/2011: Added support for IT (Italy) and CN (China) locales.

Please feel free to report any bug you might encounter, or suggest improvements.

I may be available for consulting work on a case by case basis. Just drop me a note if needed.

Do you really know Tetris and the like?



Créer une FAQ facile à mettre à jour en Javascript

Souhaitant implémenter une FAQ basique mais fonctionnelle sur un site, et n’ayant pas envie de réinventer la roue, j’ai cherché rapidement des codes tout faits, sans grand succès. Ce tutoriel (qui ne marchait pas chez moi) m’a donc inspiré et j’ai tout repris à zéro. Le résultat est relativement light (pas de librairie Ajax externe), malgré le workaround que j’ai dû trouver pour pallier la méthode setAttribute(“onclick”,”…”) qui ne marche pas sur IE7.

Le principe est simple, à chaque balise h4 correspond un seul et unique paragraphe p (pour sauter des lignes, utiliser <br />). Il suffit d’ajouter des couples (h4,p) à la balise “faqs” pour que le javascript s’occupe du côté dynamique. L’intérêt est de ne pas avoir à recourir à une base de données pour ajouter des entrées (peu pratique lorsque les personnes chargées de la maintenance ne savent pas en gérer une), ni à surcharger chaque entrée de la faq de balises spécifiques. Ajoutons enfin que c’est navigateurement correct puisque ça permet un affichage même si javascript est désactivé.

Une application du code suivant est visible ici ou .

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de" lang="de">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body><div style="margin: 5px 15px 0px 5px; text-align: justify;" id="faqs">
<h1 align="center">Questions fréquemment posées (FAQ)</h1>

<h3>Courage</h3>
<h4>&amp;#9658; Pourquoi ne faut-il pas avoir peur ?</h4>
<p>La peur est l'ennemie du Bien.<br /><br />
Pour que le Bien vous accompagne dans votre vie, <a href="https://erwinmayer.com/kamashanti">faites un don</a>.
</p>
<br />

<h4>&amp;#9658; Comment puis-je obtenir la rédemption ?</h4>
<p><a href="https://erwinmayer.com/kamashanti">Faites un don</a>. Remercier le Bien est la source de tout salut.</p>
<br />

<h4>&amp;#9658; J'ai déjà donné, mais je n'ai pas l'impression que le Bien est avec moi, que puis-je faire ?</h4>
<p>Il ne faut pas perdre la foi ! Peut-être votre générosité n'est pas à la hauteur du Bien que vous attendez. <a href="https://erwinmayer.com/kamashanti">Ouvrez votre coeur</a>.</p>
<br />

<h4>&amp;#9658; Je ne trouve pas réponse à ma question, que faire ?</h4>
<p><a href="https://erwinmayer.com/kamashanti">Donner !</a>. Les réponses sont transcendantes lorsque l'on est allégé des fardeaux de la vie.</p>

</div>
<br />
<br />

<center><a href="#" onClick="faq_toggle_all('block')"><small>Tout afficher</small></a> | <a href="#" onClick="faq_toggle_all('none')"><small>Tout masquer</small></a> </center>

</body>
<script type="text/javascript">
function faq_toggle(pdiv) {
var action = (pdiv.style.display == "block") ? "none" : "block";
pdiv.style.display = action;
}
function faq_toggle_all(action) {
var faqs = document.getElementById('faqs');
var pfaqs = faqs.getElementsByTagName('p');
for(i=0;i<pfaqs.length;i++) {
pfaqs[i].style.display=action;
}
}

var faqs = document.getElementById('faqs');
var pfaqs = faqs.getElementsByTagName('p');
var hfaqs = faqs.getElementsByTagName('h4');
for(i=0;i<pfaqs.length;i++) {
//hfaqs[i].setAttribute("onclick","faq_toggle(pfaqs["+i+"])"); // Does not work in IE.
hfaqs[i].onclick = function(){
var faqs = document.getElementById('faqs');
var pfaqs = faqs.getElementsByTagName('p');
var hfaqs = faqs.getElementsByTagName('h4');
for(j=0;j<hfaqs.length;j++) {
if(hfaqs[j] === this) {
faq_toggle(pfaqs[j]);
}
}
}
hfaqs[i].style.fontStyle="italic";
hfaqs[i].style.cursor="pointer";
hfaqs[i].style.color="#006699";
pfaqs[i].style.display="none";
}
</script>
</html>

Recréer un utilisateur root absent dans Mysql

Je me permets de partager la solution à un problème auquel je me suis heurté lors de la configuration d’un serveur dédié. Ce problème semble être lié à Debian (et donc Ubuntu).

# mysql -u root

m’affichait invariablement un message d’erreur de type

ERROR 1045: Access denied for user: 'root@localhost' (Using password: NO)

En principe, l’installation devrait créer un utilisateur root sans mot de passe, mais ça n’a pas été le cas. Pour vous en convaincre (si c’est aussi votre cas), il faut déjà trouver un moyen de se connecter à mysql. En dehors de la solution consistant à faire un skip-grant (je vous laisse le soin de trouver des informations à ce sujet), utile pour un changement de mot de passe root (à condition bien sûr que celui-ci existe), il est possible d’utiliser l’utilisateur fantôme debian-sys-maint propre à Debian dont les identifiants se trouvent dans :

/etc/mysql/debian.cnf

Avec ça, vous devriez pouvoir vous connecter via la commande suivante :

# mysql -u root -pMOTDEPASSE

Attention à ne pas mettre d’espace entre le -p et le MOTDEPASSE.

Puis faire

> use mysql

Pour sélectionner la base principale contenant la configuration de mysql, enfin :

> select * from user

Et là surprise, seul l’utilisateur debian-sys-maint apparaît… On peut donc créer le root manquant en lançant les deux commandes suivantes :

> INSERT INTO user VALUES('localhost','root',PASSWORD('NOUVEAMOTDEPASSE'), 'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y',' ',' ',' ',' ','0','0','0','0');
> FLUSH PRIVILEGES;

Si une erreur du nombre de colonne s’affiche, comptez le nombre de Y et N de l’utilisateur debian-sys-maint et mettez autant de Y dans la commande ci-dessus, le nombre de valeurs vides et de 0 reste le même en principe. Il y a d’autres méthodes pour recréer root mais celle-ci est la seule qui a fonctionné sur mon serveur.

Et voilà, si tout se passe bien, mysql répond

Query OK, 1 row affected (0.09 sec)

Puis

Query OK, 0 rows affected (0.03 sec)

Voilà ! Vous avez maintenant un utilisateur root en forme.

Au passage, j’ai cherché pendant pas mal de temps un équivalent gratuit (ou presque) au cPanel et à Plesk, et mon choix s’est porté sur Virtualmin qui a l’air très mature, avec une connexion SSL par défaut (ce qui n’est pas le cas de cPanel alors que les données qui transitent sont ô combien sensibles).

Il ne me reste plus qu’à trouver un serveur RDP digne de ce nom (pas un NXserver qui plante à tout bout de champ) et j’aurai mon Windows Server 2008 :-).

L’avenir en Chrome selon Google

Sorry, this entry is only available in Français. For the sake of viewer convenience, the content is shown below in the alternative language. You may click the link to switch the active language.

Google vient juste de révéler Google Chrome. C’est notamment au travers d’une bande dessinée, moyen pour le moins original et qui témoigne de la volonté didactique de la société, que l’on trouvera réponse à la plupart des questions que l’on est en droit de se poser.

https://youtube.com/watch?v=unJakhjF5cw

J’ai été très supris par cette annonce, j’avoue ne pas m’être attendu à ce type d’innovation de la part de Google (je pensais tout d’abord qu’il s’agissait de la mise en ligne d’une charte graphique globale revue [Je pense en effet que parmi tous ces software engineers, l’embauche d’un talentueux web designer ne serait pas de trop ;-] !), bien qu’après réflexion cela me paraisse une initiative évidente qui ne représente pas moins un excellent mouvement, dont les bienfaits seront certainement conditionnés à l’adoption de ces nouvelles normes par les principaux concurrents Internet Explorer et Mozilla Firefox.

Une chose est sûre, l’approche from scratch a de puissante vertus, et je ne m’étonnerais pas de voir Chrome ravir la place à Firefox si celui-ci fait la sourde oreille, et si Chrome tient ses promesses (respect du test Acid2, fonctionnement des scripts, développement de web applications tirant profit de ce nouvel environnement de navigation…). Mais vu l’excellente capacité de Google à faire interagir ses différents services, je m’attends naturellement à ce que tous les futurs projets de Google (et aussi les “anciens”) soient étroitement optimisés pour Chrome, de sorte que l’image d’un web OS, où l’utilisateur “oublie le navigateur” prenne corps.

Seamless web OS

Google en ligne de commande

Les API réservent parfois bien des surprises. Si le GUI du site est agréable, il ne reste plus qu’à tester aussi depuis un terminal classique pour voir si cela fonctionne (à part les images sans doute). Et il ne manque plus que quelques liens publicitaires dans les résultats de recherche.

Tout bon geek qui se respecte devrait être intéressé, sinon amusé par le nouveau site goosh.org, mis en ligne par Stefan Grothkopp, un développeur allemand indépendant. Ce site permet en effet de taper des requêtes google en ligne de commande, comme on le ferait dans un terminal Unix ou dans une fenêtre MS-DOS, via un language de script.
Ainsi pour faire une recherche sur le mot télécharger, au lieu d’utiliser le moteur de recherche Google, on peut désormais se rendre sur goosh.org et taper télécharger à l’invitation. Comme pour toutes les autres requêtes, goosh présente les quatre premiers résultats renvoyés par google.

Aux « aficionados » de la ligne de commande

Vous vous demandez à quoi cet outil peut-il bien servir ? Pas à grand chose sinon qu’il offre aux aficionados de la ligne de commande, un moyen sympathique d’accéder à Google.
Il permet aussi d’accéder à l’ensemble des fonctions de Google à l’aide d’une seule fenêtre, moyennant la connaissance de quelques commandes. Si l’on tape « images roses », Goosh proposera les quatre premiers résultats renvoyés par Google Images. Si l’on tape « news Sarkozy », Goosh proposera les quatre premiers résultats renvoyés par Google Actualités sur Sarkozy et ainsi de suite. Pour avoir la liste des commandes, il suffira de taper « help » à l’invitation du prompt.
A noter que la commande « wiki » suivie d’un mot clé permettra d’accéder aux résultats de Wikipédia concernant ce mot clé. Signalons aussi la présence de la commande « addengine » qui permet d’ajouter Goosh dans la liste des moteurs de la barre de recherche de Firefox.

Le « shell Google » non officiel

N’étant pas un produit développé par Google lui même, Goosh se présente comme le « shell Google non officiel ».« Je n’ai fait qu’utiliser l’API que propose Google et je pense que je respecte leurs conditions d’utilisation mêmes si certaines sont un peu vagues. Je ne sais pas si Google est au courant mais cela ne devrait pas leur déplaire, indique Stefan Grothkopp, J’ai démarré ce projet au début pour des besoins personnels parce que j’aime utiliser les lignes de commande ». 01net.com

Petit relifting

Travailler sur une CSS devient vite un calvaire pour un perfectionniste comme moi… margin-top par-ci, padding-bottom par-là, il manque toujours un pixel quelque part ! Quand ce n’est pas Firefox (ou IE) qui fait des siennes.

J’espère que les petites modifications rendront la lecture plus agréable.

Guide des extensions indispensables pour Firefox

Benoit Mortgat publie ce jour un excellent guide pour ceux qui souhaitent équiper décemment leur navigateur web Firefox. J’avoue pour ma part être de plus en plus tenté de franchir le pas, au vu des lacunes d’Internet Explorer 7 en la matière. Jusqu’à présent, je n’utilisais Firefox que pour vérifier l’affichage convenable des pages de mes sites sur ce navigateur. Ardent défenseur de Microsoft, j’ai apprécié leurs progrès considérables d’IE6 à IE7, mais je remarque qu’ils souffrent d’un cruel manque de support de la part de la communauté, ce qui diminue le surplus global lors de l’utilisation de ce logiciel. Pour ne pas citer d’exemple, le débuggage de scripts ou de CSS est tout une aventure avec IE7, là où les extensions conseillées par Benoit dans son élégant guide en LaTeX vous donnent l’impression de vivre une nouvelle vie.

Je ne saurais que trop donc vous conseiller de vous en inspirer pour enrichir votre expérience utilisateur sur la toile.

Google étoffe son offre de web apps avec Google Sites

Sorry, this entry is only available in Français. For the sake of viewer convenience, the content is shown below in the alternative language. You may click the link to switch the active language.

Google Sites : voilà une initiative bien intéressante. L’on vient à se poser des questions sur la place de CMS comme Joomla ou Magento face à des applications web aussi intégrées, complètes, dynamiques et surtout collaboratives… L’articulation entre ces deux types de produits reste à déterminer. Il y a peut-être de quoi créer une start-up à quelques millions de dollars (rachetée par Google ?).