Puyb Inside

mercredi 11 août 2010

Le truc de l'année

Ce qui est énervant avec les prise RJ45 que l'on trouve sur les câbles ethernet, c'est que le petit picot en plastique qui sert à bloquer le câble a la très mauvaise habitude de venir se coincer dans les autres câbles et finit très vite pas se casser... Ensuite, on se retrouve avec un câble qui a toujours tendance à vouloir s'extraire de la prise où on l'avait confortablement installé, ce qui bien sûr occasionne de nombreuses pertes de connexion... Grrr...

Heureusement, il y a des gens astucieux sur terre... Des MacGyver, qui avec trois fois rien, peuvent vous sauver la vie :


Vous trouverez les instructions étape par étape pour réparer une prise ethernet sur le ce site.

mardi 10 août 2010

Comment éviter une division par zéro en perl

Je travail sur un logiciel écrit en Perl par des gens qui visiblement ne maîtrisaient complètement leur art... J'en veux pour preuve un petit extrait dudit logiciel :
if($i !~ /1|2|3|4|5|6|7|8|9/) {
  $result = 0;
} else {
  $result = $n / $i;
}

Bravo, le développeur à penser à gérer le cas de la division par zéro... Ce qui me gêne le plus, c'est la façon dont il détecte cette division par 0... Avec une expression régulière qui teste si il n'y a pas de chiffre autre que 0 dans ce nombre !

Les moins tordus d'entre nous aurait peut être préféré écrire "$i != 0", mais s'eu été beaucoup trop simple ;-)

Moi, j'aurai même été tenté d'écrire juste :
$result = $i && $n / $i;

lundi 28 juin 2010

Il y a des stations de vélib partout

Mais là, je suis pas sûr de pouvoir y aller déposer mon vélo en moins de 30 minutes !

D'après le site des Vélib, la station 12151 est situé au beau milieu du Sahara ! Plus exactement par 27.140973374539° de latitute et -3.4045606242531° de longitude !

mercredi 10 mars 2010

Gna!


Je ne suis pas sûr que je puisse aller à Solution Linux avec ce badge !

Pour ceux qui ne voient pas pourquoi, il y a juste un joli message d'ereur à la place du code barre !

mercredi 3 mars 2010

Build a call tree in Javascript

Disclaimer: This is my first post in english (or at least, the first that try to). So if my writings makes your eyes bleed, please leave a comment about it !

Yesterday, at work, i had to debug an old Internet Explorer only javascript application. This software was made by dumb monkeys who had no clue about how to write maintainable code. I had to go through something close to two thousand line of code and more than an hundred of carefully nested functions... In less than an hour, I was completely lost !
This application was carefully designed to run only under Internet Explorer. There's no hope to be able to used a decent debugger like Firebug. So as usual with this project, i decided to start to build my own tool.

I made a little script that fetches all functions to wrap them in a new function that log the function name, the caller name, the current time, the arguments and the returned value... I hoped this was enough to help me debug the code !

function build_calltree() {
    var call_log = [];
    function log_wrapper(func, name) {
        func.function_name = name;
        function wrapped_func() {
            var caller = arguments.callee.caller || wrapped_func.caller;
            var data = {
                name: name,
                caller: caller,
                caller_name: caller && caller.function_name || '__unknown__',
                'date': new Date(),
                'arguments': arguments
            };
            call_log.push(data);
            var ret = func.apply(this, arguments);
            data['return'] = ret;
            return ret;
        }
        wrapped_func.original = func;
        wrapped_func.function_name = name;
        return wrapped_func;
    }
    for(var k in window) {
        if(typeof window[k] == 'function') {
            window[k] = log_wrapper(window[k], k);
        }
    }
    return call_log;
}
var call_log = build_calltree();

I wrote and test this code in Firefox. But when i tried to test it in IE, it didn't worked...

I found that in IE, global objects (those who aren't declared in the scope of a function) are not attached to the window object. I found a good article that describes the problem.
So I can't iterate through the window object in order to get all the functions. Again, this an IE bug ! The only solution I found is to parse all the js files to extract all the functions names. Crazy, inefficient, and error prone ! Isn't that a good description of IE ?

So i gave up, walked through the code manually, took some paracetamol, and after several hours, find the bug ! But, i want to publish the code above to think that i didn't wrote it for nothing.

vendredi 11 décembre 2009

Open Wifi Auto Connect

Je ne sais pas si vous utilisez souvent des réseaux wifi qui filtrent l'accès en utilisant un portail de capture web pour vous authentifier ? Personnellement, j'utilise régulièrement le service FreeWifi de Free...

Le principe de ces services est que le pare-feu bloque toutes les connexions qui ne sont pas authentifiés. Pour s'authentifier, il faut utiliser un navigateur Web, tenter de naviguer vers un site quelconque pour se faire rediriger vers la page d'authentification puis y entrer ses identifiants...

Comme je suis toujours plus fainéant, je viens de faire un petit script qui se charge de faire toutes ses étapes automatiquement. Le principe est de surveiller les connexions aux différents réseaux sans fils, et dès qu'un réseau est reconnu (que son nom est dans une liste), il se charge tout seul de récupérer la page du portail, puis de la renvoyer accompagnée des identifiants de connexion.

Utilisation :

  1. Téléchargez le fichier.
  2. Copiez le dans le dossier de votre choix.
  3. Créez le fichier de configuration. Il se nomme .OpenWifiAutoConnect, doit être placer dans votre dossier personnel (~) et est au format .ini. Les sections correspondent aux nom des réseaux. Les clefs correspondent au champs du formulaire ou il faut entrer une valeur. Par exemple:
    [UnReseau]
    email=test@example.com
    pass=azerty
    
    [FreeWifi]
    login=1234567890
    password=secret
    
  4. Ajoutez le programme au démarrage de votre session.
  5. Vérifier que les paquets (ubuntu / debian) suivant sont installé : python-dbus, python-notify et python-beautifulsoup
  6. Redémarrer votre session pour que le programme se lance
  7. Connectez vous à un réseau wifi et attendez que la magie s'opère. Une popup de notification vous préviendra du succès de l'authentification.

Comment ça marche ?


Avant tout, voici le code :
#!/usr/bin/env python

################################################################################
# OpenWifiAutoConnect - Stephane PUYBAREAU (puyb <at> puyb <dot> net) - 2008   # 
# Fully automated authentication to capture portal based wifi networks.        # 
# Config file: ~/.OpenWifiAutoConnect - Format: ini                            #
# Section are network SSID (names)                                             #
# key / value pair define user submited information (based on the html form)   #
#                                                                              # 
# This software is provided under the terms of the GPL v3 licence.             # 
# See http://www.gnu.org/licenses/gpl.html for more information                # 
#                                                                              # 
# This software use python dbus bindings, pynotify and BeautifulSoup modules   #
################################################################################


# The url the program will try to open hoping to be redirected to the portal
URL = 'http://perdu.com/'

import sys
import gobject
import dbus
import dbus.mainloop.glib
import urllib2, urllib
from BeautifulSoup import BeautifulSoup
import re
import ConfigParser
import os
import pynotify

def properties_changed_signal_handler(props):
    if not props.has_key('ActiveConnections'):
        return
    for device_path in props['ActiveConnections']:
        device = bus.get_object('org.freedesktop.NetworkManager', device_path)
        device_props = device.GetAll("org.freedesktop.NetworkManager.Connection.Active", dbus_interface="org.freedesktop.DBus.Properties")
        if device_props['Default']:
            return
        ap_path = device_props['SpecificObject']
        if ap_path.startswith('/org/freedesktop/NetworkManager/AccessPoint/'):
            ap = bus.get_object('org.freedesktop.NetworkManager', ap_path)
            ssid = ap.Get("org.freedesktop.NetworkManager.AccessPoint", "Ssid", dbus_interface="org.freedesktop.DBus.Properties")
            ssid = ''.join([chr(c) for c in ssid])
            if ssid not in config.sections():
                return
            print ssid
            device.connect_to_signal("PropertiesChanged", device_properties_changed_signal_handler(ssid), dbus_interface="org.freedesktop.NetworkManager.Connection.Active")

def device_properties_changed_signal_handler(ssid):
    def handler(props):
        if not props.has_key('State'):
            return
        if props['State'] != 2:
            return
        print ssid
        section = dict(config.items(ssid))

        if login(section):
            txt = "Successfully logged on " + ssid
        else:
            txt = "Failled to log on " + ssid
        n = pynotify.Notification("Open Wifi Auto Connect", txt, "dialog-warning")
        n.set_urgency(pynotify.URGENCY_NORMAL)
        n.set_timeout(10)
        #n.add_action("clicked","Button text", callback_function, None)
        n.show()
    return handler


def login(values):
    # build an http fetcher that support cookies
    opener = urllib2.build_opener( urllib2.HTTPCookieProcessor() )
    urllib2.install_opener(opener)

    # try to open the portal page
    f = opener.open(URL)
    data = f.read()
    redirect_url = f.geturl().split('?')[0]
    f.close()
    if redirect_url == URL:
        return # Our request wasn't hijacked by the portal (maybe the wifi network isn't the default connection)

    # parse the portal page
    soup = BeautifulSoup(data)
    form = soup.find('form')
    if not form:
        return # There's no form on this page
    
    # creating the post values
    login_post = {}
    for input in form.findAll('input'):
        if input.has_key('name'):
            default = ''
            if input.has_key('type') and input['type'] == 'checkbox':
                default = 'on'
            login_post[input['name']] = input.has_key('value') and input['value'] or default

    login_post.update(values)

    # guessing the post url
    if not form.has_key('action'):
        url = redirect_url
    elif not form['action'].startswith('/'):
        url = '/'.join(redirect_url.split('/')[:-1]) + '/' + form['action']
    else:
        url = '/'.join(redirect_url.split('/')[:3]) + form['action']

    # GET ou POST ?
    postBody = None
    if form.has_key('method') and form['method'].lower() == 'post':
        postBody = urllib.urlencode(login_post)
    else:
        url += '?' + urllib.urlencode(login_post).replace(' ', '+')

    # submit the form
    f = opener.open(url, postBody)
    data = f.read()
    f.close()

    # Test if the login was a success
    f = opener.open(URL)
    data = f.read()
    status = f.geturl() == URL
    f.close()
    return status

if __name__ == '__main__':
    config = ConfigParser.RawConfigParser()
    config.read(os.path.expanduser('~/.OpenWifiAutoConnect'))

    pynotify.init( "Open Wifi Auto Connect" )

    dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)

    bus = dbus.SystemBus()
    nm = bus.get_object("org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager")
    nm.connect_to_signal("PropertiesChanged", properties_changed_signal_handler, dbus_interface="org.freedesktop.NetworkManager")

    loop = gobject.MainLoop()
    loop.run()


Le programme utilise D-Bus pour demander au NetworkManager de lui signaler chaque changement au niveau du réseau. A chaque changement, il tente de déterminer, toujours grâce à D-Bus, si ce reseau est un réseau Wifi et quel est son SSID. Si le réseau est dans le fichier de configuration, il attend que que le réseau soit correctement connecté pour lancer la fonction login avec les paramètres de connexion.

Cette fonction commence par mettre en place un client HTTP supportant les cookies (il est possible (FreeWifi le fait) que le portail nous envoie des cookies). Il tente d'ouvrir une page vers un site quelconque (en l'occurrence perdu.com. Le client supporte les redirections HTTP, il teste donc si la requette a été redirigé. Si c'est le cas, le HTML est analysé avec Beautiful Soup pour récupérer toutes les informations sur le formulaire. Elle sont modifiées avec les informations de connexion provenant du fichier de configuration. Puis, le formulaire est envoyé. Enfin, il vérifie si l'authentification à réussi en tentant de joindre à nouveau perdu.com...

Limitations :

  • Ce programme ne fonctionnera pas si le SSID du réseau n'est pas toujours le même. J'ai cru comprendre que les réseaux Fon n'avait pas tous le même nom, si c'est le cas, ça ne fonctionnera pas (enfin, pas pour tous les réseau Fon, mais juste pour ceux dont on a donner les noms.
  • Ce programme ne fonctionnera pas non plus si les noms des champs à remplire dans le formulaire sont variables.
  • Enfin, ça ne fonctionnera pas non plus si il y a un captcha (une joli image où l'on doit jouer à Champolion pour deviner ce qu'il ya d'inscrit).


Voilà, j'espère que ça va servir à quelqu'un (d'autre que moi)... Si il y a un problème, n'hésitez pas à laisser un commentaire... Et si il n'y a pas de problème, vous pouvez aussi laisser un commentaire ;-)

jeudi 10 décembre 2009

J'aime pas le perl

Mais je suis obligé de bosser dessus...

J'ai horreur cette syntaxe si particulière qui donne l'impression que Larry Wall a absolument tenu à utiliser les 94 symboles de la table ASCII...
Pourquoi diable se faire chier à différentier les variables en fonction de leur type avec des $, @ et autre % ?
Qui a besoin de systématiquement aplatir les tableaux imbriqué et les arguments ?
Pourquoi emmerder les développeurs avec une distinction entre référence et variable ? Peut être par nostalgie du C...
Et surtout, voici un petit exemple qui montre à quel point ce langage est tordu :
use strict;
use Data::Dumper;

my %h = (
    'a' => (
        'b' => 'c',
    ),
);
print Dumper(\%h);

Il y a une erreur dans ce code. J'ai utilisé des () au lieu des {} pour le deuxième hash. Ce qui fait que je n'ai pas une référence vers mon deuxième hash... N'importe quel langage aurai levé une exception devant une tel erreur... Au lieu de cela, Perl affiche tout fièrement :
$VAR1 = {
          'c' => undef,
          'a' => 'b'
        };
Il à aplatit le hash en décalant tout ! Hallucinant ! Qui peut bien avoir besoin d'une telle "fonctionnalité" ?

La bonne solution est :
use strict;
use Data::Dumper;

my %h = (
    'a' => {
        'b' => 'c',
    },
);
print Dumper(\%h);

Ce qui donne :
$VAR1 = {
          'a' => {
                   'b' => 'c'
                 }
        };

Je ne vois aucune raison pour justifier une telle complexité !

jeudi 26 novembre 2009

Microsoft supporte la vidéo sur iPhone "grace à SilverLight"

dixit PC Inpact...

Mais comment font-ils alors même qu'Apple refuse à Adobe de porter sa technologie flash sur l'iPhone ? Apple aurait autorisé Microsoft à adapter SilverLight (qui est un technologie concurrente de Flash) ?

Et bien non, Microsoft joue juste sur les mots :
Microsoft utilise simplement la balise HTML 5 <video />, déjà supporté par la version de WebKit intégré à l'iPhone... Et Silverlight dans l'affaire ? Et bien on en a tout simplement pas besoin pour faire tourner une vidéo dans une page Web sur un iPhone. Il suffit d'utiliser la balise <video />. En fait, la démonstration faite par Microsoft montre tout simplement que SilverLight est capable de s'adapter automatiquement à l'iPhone. Ou, que SilverLight est capable automatiquement d'utiliser les standards Web à la place du plugin SilverLight quand celui n'est pas disponible... En gros que SilverLight est inutile dans un navigateur Web qui respecte les standards !

C'est tout de même assez ironique car Microsoft tente depuis quelques années d'imposer sa technologie SilverLight dans les navigateurs, pour concurrencer le flash, et de plus, n'implémente pas la balise <video /> dans Internet Explorer alors que tous ses concurrents (Firefox, Safari, Chrome) la supporte déjà. Jusqu'à peu, Microsoft refusait même de participer au travaux sur le HTML5 (sans doute pour ne pas concurrencer sa technologie SilverLight)... Je trouve cela amusant que Microsoft fasse lui même la preuve que sa technologie propriétaire SilverLight est inutile !

Allez Microsoft, la prochaine étape, c'est de prouver que Linux est mieux que Windows... Tu peux le faire ;-)

mercredi 25 novembre 2009

Apple's mistake

Et non, je ne suis pas mort, il va falloir patienter encore un peu...

Pas mal de changements dans ma vie (nouveau boulot, déménagement, etc.) m'ont empêchés de continuer à écrire sur ce blog... Mais promis, je vais essayer de m'y remettre.

Aujourd'hui, j'ai lu un billet de Paul Graham intitulé "Apple's mistake". Ce document résume assez bien mon sentiment vis à vis d'Apple depuis quelques années. Je regrette même d'avoir acheté mon dernier Macbook Pro (d'ailleurs, il ne me sert quasiment plus).

Voici quelques morceaux choisis :
They make such great stuff, but they're such assholes.


When you look at the famous 1984 ad now, it's easier to imagine Apple as the dictator on the screen than the woman with the hammer. [2] In fact, if you read the dictator's speech it sounds uncannily like a prophecy of the App Store.

We have triumphed over the unprincipled dissemination of facts.

We have created, for the first time in all history, a garden of pure ideology, where each worker may bloom secure from the pests of contradictory and confusing truths.

mercredi 25 mars 2009

Défillement à deux doigts sous Ubuntu

Ceux qui on déjà utilisé un portable sous Mac OS X savent de quoi je parle. Pour les autres, il s'agit en fait de pouvoir faire un défilement horizontal ou vertical sur le touchpad d'un portable en utilisant deux doigts sur toutes la surface du touchpad au lieu d'un seul doigt sur les bords. A l'usage, c'est tout simplement génial ! L'essayer c'est l'adopter ;-)

Donc , comment qu'on fait donc ? Il faut créer un fichier /etc/hal/fdi/policy/shmconfig.fdi contenant :
<?xml version="1.0" encoding="ISO-8859-1"?>
<deviceinfo version="0.2">
 <device>
  <match key="input.x11_driver" string="synaptics">
   <merge key="input.x11_options.SHMConfig" type="string">True</merge>
   <merge key="input.x11_options.VertTwoFingerScroll" type="string">1</merge>
   <merge key="input.x11_options.HorizTwoFingerScroll" type="string">1</merge>
  </match>
 </device>
</deviceinfo>

Ensuite, redémarrer hal :
sudo /etc/init.d/hal restart
Et l'interface graphique en tapant Ctrl + Alt + Backspace.

C'est tout !