Le Luxembourg, ce pays aux adresses IP méconnues

FFox-PokerstarsEn essayant d’accéder à un site internet de Poker j’ai observé un comportement assez amusant. Le site qui est pourtant un des sites les plus réputés ne s’affichait pas dans mon navigateur à cause d’un problème de redirection excessive.

En utilisant curl, j’ai loggé les redirections et il semble que la Belgique et la France se disputent l’appartenance des clients Luxembourgeois ! :-)


$ curl -visk -L http://www.pokerstars.com/ 2>/dev/null | grep Location
Location: http://www.pokerstars.be/
Location: http://www.pokerstars.eu/fr/
Location: http://www.pokerstars.BE/
Location: http://www.pokerstars.eu/fr/
Location: http://www.pokerstars.BE/
Location: http://www.pokerstars.eu/fr/
Location: http://www.pokerstars.BE/
Location: http://www.pokerstars.eu/fr/
Location: http://www.pokerstars.BE/
Location: http://www.pokerstars.eu/fr/
Location: http://www.pokerstars.BE/
Location: http://www.pokerstars.eu/fr/
Location: http://www.pokerstars.BE/
Location: http://www.pokerstars.eu/fr/
[...]

Publié dans Browser, IT | Un commentaire

Firefox 18 est disponible

Ecran d'informations de Firefox 18Sortie officielle de Firefox 18. Il inclut le nouveau compilateur JavaScript IonMonkey qui devrait grandement accélérer l’exécution du code des applications. Cette version confirmera-t-elle le retour en grâce du navigateur qui avait perdu du terrain ces derniers temps face à Google Chrome ?

En parcourant les release notes de cette nouvelle version , j’ai découvert qu’une propriété DOM window.devicePixelRatio permettait de connaitre le rapport entre les pixels réels de l’écran physique et ceux servant aux calculs de dimensionnement. Il est principalement utilisé sur des écrans à très haute résolution comme le retina. Le temps du positionnement au pixel est définitivement révolu !

Pour en savoir plus sur ce concept: http://www.quirksmode.org/blog/archives/2012/06/devicepixelrati.html

Publié dans Browser, IT, Open Source | Laisser un commentaire

Les bronzés font de l’ASCII

J’ai ouvert un nouveau projet sur SourceForge qui s’appelle « Ascii Art for Java » et est disponible en ligne sur https://sourceforge.net/projects/asciiart/ pour les sources (Mercurial) et les binaires (jar). Si vous utilisez Maven, il suffit d’ajouter la dépendance suivante dans votre projet:

<dependency>
    <groupId>org.alcibiade</groupId>
    <artifactId>asciiart-core</artifactId>
    <version>0.2.0</version> 
</dependency>

Ce projet est un portage de tout le code de gestion de flux ASCII réalisé dans le cadre d’un autre projet et packagé sous forme autonome.

Le projet permet:

  • La construction de documents ASCII structurés (tableaux, mises en formes, …);
  • La sortie directe de collections et de maps vers des logs JCL ou SLF4j sous forme de tables avec gestion des ruptures de lignes;
  • La conversion d’images en ASCII;
  • D’autres fonctions viendront dans les releases suivantes…

Il y a trois modules:

  • asciiart-core: Le système de rendu (widgets, containers, rasters, …)
  • asciiart-jcl: Un wrapper pour sortir directement des données ASCII vers un log Apache commons-logging (dépend de asciiart-core)
  • asciiart-slf4j: Un wrapper pour SLF4j (dépend de asciiart-core)

Des exemples valent mieux que de longs discours,  pour les questions envoyez moi des mails…

Utilisation d’asciiart-core seul

+--------+
| Fruit  |
+--------+
| Orange |
| Apple  |
| Lemon  |
+--------+

Source code:

    List<String> items = new ArrayList<String>();
    items.add("Orange");
    items.add("Apple");
    items.add("Lemon");

    TableModel tableModel = new TableModelCollectionAdapter(items, "Fruit");
    TableWidget tableWidget = new TableWidget(tableModel);

    CharacterRaster raster = new ExtensibleCharacterRaster(' ');
    tableWidget.render(new RasterContext(raster));

    System.out.println(raster);

(Notez ci-dessous l’alignement implicite sur détection de type numérique dans les valeurs)

+-----------+-----------+
| City      | Value     |
+-----------+-----------+
| Amsterdam |    3.1415 |
| London    | 2012.0    |
| Paris     |   42.0    |
+-----------+-----------+

Source code:

    Map<String, Double> items = new TreeMap<String, Double>();
    items.put("Paris", 42.);
    items.put("London", 2012.);
    items.put("Amsterdam", 3.1415);

    TableModel tableModel = new TableModelMapAdapter(items, "City", "Value");
    TableWidget tableWidget = new TableWidget(tableModel);

    CharacterRaster raster = new ExtensibleCharacterRaster(' ');
    tableWidget.render(new RasterContext(raster));

    System.out.println(raster);
+----------+----------+----------+----------+
| Column 0 | Column 1 | Column 2 | Column 3 |
+----------+----------+----------+----------+
| 00:00    | 01:00    | 02:00    | 03:00    |
| 00:01    | 01:01    | 02:01    | 03:01    |
| 00:02    | 01:02    | 02:02    | 03:02    |
| 00:03    | 01:03    | 02:03    | 03:03    |
| 00:04    | 01:04    | 02:04    | 03:04    |
| 00:05    | 01:05    | 02:05    | 03:05    |
+----------+----------+----------+----------+

Source code:

    TableWidget tableWidget = new TableWidget(new CustomTableModelImpl());

    CharacterRaster raster = new ExtensibleCharacterRaster(' ');
    tableWidget.render(new RasterContext(raster));

    System.out.println(raster);

class CustomTableModelImpl extends AbstractTableModel {

    @Override
    public int getWidth() {
        return 4;
    }

    @Override
    public int getHeight() {
        return 6;
    }

    @Override
    public String getCellContent(int x, int y) {
        return String.format("%02d:%02d", x, y);
    }

    @Override
    public String getColumnTitle(int x) {
        return "Column " + x;
    }
}
                             _______,,__                                        
                        __ggggggggg@NNNNNMMPPMNNNg,_                                     
                      _gNP^` ````_              `*NNg,                                   
                  _g@NP^,'     _#`                  *NNg_                                
                _gP%P _p`      N_                     ^MNg,_                             
              _gN`__,gNL _____ggNg       _     *qgg__    *NNg_                           
      ____,gpNNP #N^NTMNNP*JNP*^*Ngg____gL___    ^Np>- `*Nq@NNg__                        
      N@**^__JNNg_ NZg#*          ^NNNNNNNE^Npg__ _`       `^*MNNN@gggg______            
       *N@NNMP5gNP5gNNg@NNN@ggg_  gNNNNgJhN&#_gNPP^         Ng_    `^^*PNNNNNNNN@gp      
         *NqggP`_dNN{NNNNNNNNNNN  ^^^NNNNNggNP^      q_      ^Ng__      ____, ,NNP       
            gNP_N'   ^*NNNNNN*`       ^NNNNF          Ng,_     ^MNgggg@NNNNFg@NP         
            %P gP     ^NNNNNN^         'NNk^           NL`    ,..wwWNMP**`gNNF           
           _NN K        _NF             JN^k          _gN  ,,ggggpppqNNNNNP`             
           NNL Ny   __ggNNNgg_        ,_NNB         ,@P5-    NNF                         
           _NNL^NkggP*`NNNNNNNNg,_  ,_^NNB^       _gNM^,+   gNF                          
           T`{Nk ^Nk  gNNNNNNNNPNNg__^NNk^      _gNNgM^,

Source code:

        File imageFile = new File(args[0]);
        int columns = Integer.parseInt(args[1]);

        BufferedImage image = ImageIO.read(imageFile);
        int rows = columns * image.getHeight() / image.getWidth() / 2;

        CharacterRaster raster = new ExtensibleCharacterRaster();
        ImageRasterizer.rasterize(image, new RasterContext(raster),
                new TextBoxSize(columns, rows));

        System.out.print(raster.toString());

Utilisation d’asciiart-slf4j ou asciiart-jcl

22:34:55.331 [main] INFO  org.alcibiade.asciiarttest.App - Here is a basic log line
22:34:55.348 [main] INFO  org.alcibiade.asciiarttest.App - +--------+
22:34:55.348 [main] INFO  org.alcibiade.asciiarttest.App - | Fruits |
22:34:55.348 [main] INFO  org.alcibiade.asciiarttest.App - +--------+
22:34:55.348 [main] INFO  org.alcibiade.asciiarttest.App - | Orange |
22:34:55.348 [main] INFO  org.alcibiade.asciiarttest.App - | Apple  |
22:34:55.348 [main] INFO  org.alcibiade.asciiarttest.App - | Lemon  |
22:34:55.348 [main] INFO  org.alcibiade.asciiarttest.App - +--------+

Source code:

    List<String> items = new ArrayList<String>();
    items.add("Orange");
    items.add("Apple");
    items.add("Lemon");

    AsciiArtLogger logger = new AsciiArtLogger(LoggerFactory.getLogger(App.class));
    logger.info("Here is a basic log line");
    logger.info(items, "Fruits");
Publié dans IT, Java, Open Source | Laisser un commentaire

Code Source de Final Fantasy XIII disponible !

Le code source de Final Fantasy XIII a été publié sur internet ! Le voici:

public void finalFantasyXIII() {
    int monsterLevel = 1;

    while ( monsterLevel < 99 ) {
        runStraightAhead();
        fightMonster(monsterLevel++);
        viewCinematicSequence();
    }
}

On pourra donc bientôt voir apparaitre un portage sous Linux de ce moteur de jeu innovant ! ;-)

Publié dans IT | Un commentaire

Music.history -= 40

J’aimerais faire un flashback sur quelques morceaux d’anthologie de l’histoire de la musique… vous ramener vers une époque où les durées de morceaux à deux chiffres ne faisaient peur à personne et où les premiers synthétiseurs faisaient leur apparition. Cette idée m’est venue en réalisant que ces morceaux figurent de façon permanente dans la plupart de mes listes de lecture et ont cette année quarante ans ! La production n’est pas comparable à ce qui se fait aujourd’hui, mais c’est bien mieux: ils sont devenus intemporels.


Heart of the Sunrise
Sur l’album Fragile de Yes, 1971

Parmi les groupes barrés et psychédéliques, Yes fait partie des précurseurs. Leur charismatique bassiste Chris Squire, donne la pleine mesure de son talent et de sont goût pour les rythmes syncopés et les mesures impaires. Ce morceau figure sur « Fragile », le troisième album du groupe. Jon Anderson, chanteur et auteur des paroles explique qu’elles sont inspirées par la puissance émotionnelle de l’aube sur la ville.

Le résultat est un morceau puissant alternant des mouvements majestueux et des parties plus enlevées aux rythmiques impeccables.


Echoes
Sur l’abum Meddle de Pink Floyd, 1971

Plus atmosphérique, ce morceau fut le premier à définir le son du groupe qu’il conservera par la suite. Les premiers albums étaient très expérimentaux et fortement influencés par le Syd Barrett. L’arrivée de David Gilmour et de son style aérien et puissant apporte ici vraiment une maturité et définit un genre souvent imité mais jamais égalé.


Tarkus
Emerson, Lake and Palmer, 1971

Ce morceau de plus de vingt minutes est composé de plusieurs mouvements et occupait à l’ensemble de la face A du disque. Il raconte l’histoire d’une créature mutante moitié animale et moitié tank née d’un oeuf craché par un volcan.

Les ambiances musicales font penser tour à tour à Santana, Deep Purple ou Genesis. Ce trio de virtuoses formait le « super-groupe » de l’époque et définissent un jalon avec ce morceau.

J’aurais pu également parler de Genesis qui sortit cette année là son album « Nursery Cryme » avec Peter Gabriel, du premier album de Mahavishnu Orchestra, de Brian Eno… Même en France cette époque fût prolifique en albums conceptuels avec Magma, Gainsbourg qui sortait « Melody Nelson » et Ange qui faisait ses débuts…

Publié dans Musique | 5 commentaires

Application Struts 2 sur serveur WebSphere AS 7

Dans le cadre d’un projet professionnel, nous avons développé une interface utilisateur web avec le framework Apache Struts 2. L’application est destinée à être hébergée sur IBM WebSphere AS 7 et lors des premiers déploiements nous avons rencontré un problème d’exceptions laissant des traces dans les logs:


[3/26/11 18:23:23:423 CET] 00000010 LocalizedText E com.opensymphony.xwork2.util.logging.commons.CommonsLogger error Could not reload resource bundles
java.lang.NoSuchFieldException: cacheList
at java.lang.Class.getDeclaredFieldImpl(Native Method)
at java.lang.Class.getDeclaredField(Class.java:510)
at com.opensymphony.xwork2.util.LocalizedTextUtil.clearMap(LocalizedTextUtil.java:877)
at com.opensymphony.xwork2.util.LocalizedTextUtil.reloadBundles(LocalizedTextUtil.java:837)
at com.opensymphony.xwork2.util.LocalizedTextUtil.findDefaultText(LocalizedTextUtil.java:197)
at com.opensymphony.xwork2.util.LocalizedTextUtil.findDefaultText(LocalizedTextUtil.java:219)
at com.opensymphony.xwork2.DefaultTextProvider.getText(DefaultTextProvider.java:67)
at com.opensymphony.xwork2.DefaultTextProvider.getText(DefaultTextProvider.java:82)
at com.opensymphony.xwork2.DefaultTextProvider.getText(DefaultTextProvider.java:129)
at org.apache.struts2.util.TextProviderHelper.getText(TextProviderHelper.java:79)
at org.apache.struts2.util.TextProviderHelper.getText(TextProviderHelper.java:53)

Ces messages se reproduisaient à chaque invocation d’un libellé par les écrans de l’interface utilisateur, mais sans provoquer de problème particulier. Les tests faits avec le même binaire déployé sur Glassfish ou Tomcat ne généraient pas ces exceptions et les forums semblaient muets sur ce sujet….

Comme les classes provoquant le problème sont issues de librairies Open Source, je suis allé analyser le comportement du code en question. Lors du chargement d’un libellé, Struts invoque des méthodes de la librairie xwork2 pour charger les informations issues des bundles i18n. La trace des appels sur la pile montre que lors du chargement de libellé, la méthode LocalizedTextUtil.clearMap(…) est invoquée pour purger un objet de classe ResourceBundle. Celle-ci utilise un mécanisme d’introspection pour aller réinitialiser le champ cacheList qui est privé dans l’implémentation Java de Sun. Ceci est fait comme mesure préventive visant à limiter les risques de memory leaks.

Cependant, la particularité de WebSphere par rapport aux autres serveurs utilisés lors des tests est d’embarquer sa propre JVM développée par IBM. Or, il semble que celle-ci diffère dans l’implémentation de la classe ResourceBundle qui n’a pas de champ privé cacheList et lève donc une erreur lors de la réinitialisation des libellés i18n.

La solution pour faire cohabiter Struts2 et WebSphere est de systématiquement configurer l’application en mode production:

<struts>
<constant name="struts.devMode" value="false" />
<constant name="struts.i18n.reload" value="false" />
<constant name="struts.configuration.xml.reload" value="false" />
...
</struts>

Publié dans Java, Open Source | Laisser un commentaire

Changement de version dans un projet Maven


Dans le développement en Java de projets construits avec Maven, la gestion précise des versions est primordiale. Tout le mécanisme de gestion des dépendances est basé sur des versions précises de tous les « artefacts ».

Dans le cas d’un projet simple, il suffit souvent d’aller modifier le fichier pom.xml qui contient l’ensemble de la description du projet. Cela devient nettement plus sensible dans le cas où les projet est composé de plusieurs modules devant avoir des versions cohérentes. Il faut alors aller mettre à jour la version dans tous les descripteurs, et souvent en double (version du module et version du module parent).

Pour se simplifier la vie, il est possible d’utiliser le « maven-release-plugin ». Celui-ci est principalement destiné à gérer complètement la création d’une nouvelle release du projet. Il va procéder ainsi sur l’ensemble des modules:

  • L’utilisateur saisit la nouvelle version de développement X.Y.Z
  • Changement de la version courante de A.B.C-SNAPSHOT en A.B.C
  • Création d’un tag A.B.C dans le système de versionning
  • Changement de la version courante en X.Y.Z-SNAPSHOT

L’astuce que je vais vous présenter ici est qu’il est également possible de l’utiliser pour uniquement mettre à jour la version spécifiée dans les descripteurs maven, sans tag ni commit. Je vais utiliser pour l’exemple mon projet d’émulateur d’ordinateur Matra Alice.

La version courante était « 1.0-SNAPSHOT », mais ce n’était pas cohérent avec le fait que la première release planifiée sera la « 0.1.0″, la version de développement devrait donc logiquement être « 0.1.0-SNAPSHOT »…

Tout d’abord, il faut déclarer le plugin dans le pom.xml racine du projet:

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.1</version>
<configuration>
<autoVersionSubmodules>true</autoVersionSubmodules>
</configuration>
</plugin>

L’option « autoVersionSubmodules » permet de n’avoir à saisir qu’un seul numéro de version qui sera appliqué de façon homogène à l’ensemble des sous-modules.

Ensuite, nous invoquons la cible « release:update-versions » qui va nous demander de saisir interactivement les versions des modules et mettra les références à jour automatiquement dans les fichiers pom.xml du projet.


macpro:Emulation yk$ mvn release:update-versions
[INFO] Scanning for projects...
[INFO] Reactor build order:
[INFO] Emulation
[INFO] Emulation Core Components
[INFO] Motorola 6847 GPU emulation
[INFO] Motorola 6800 CPU family emulation
[INFO] Matra Alice Computer Emulation
[INFO] ------------------------------------------------------------------------
[INFO] Building Emulation
[INFO] task-segment: [release:update-versions] (aggregator-style)
[INFO] ------------------------------------------------------------------------
[INFO] [release:update-versions {execution: default-cli}]

What is the new development version for "Emulation"? (org.alcibiade:emulation) 1.1-SNAPSHOT: : 0.1.0-SNAPSHOT

[INFO] Transforming 'Emulation'...
[INFO] Transforming 'Emulation Core Components'...
[INFO] Transforming 'Motorola 6847 GPU emulation'...
[INFO] Transforming 'Motorola 6800 CPU family emulation'...
[INFO] Transforming 'Matra Alice Computer Emulation'...
[INFO] Cleaning up after release...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 9 seconds
[INFO] Finished at: Sat Feb 19 11:37:14 CET 2011
[INFO] Final Memory: 21M/81M
[INFO] ------------------------------------------------------------------------

Et voilà, le tour est joué !

Encore un détail, ce plugin agira sur les versions des modules et des déclarations de parents, mais pas sur les dépendances. Pour que les dépendances entre modules référencent bien toujours la même version, il faut utiliser ${project.version}:


<dependency>
<groupId>org.alcibiade</groupId>
<artifactId>emulation-motorola-68xx</artifactId>
<version>${project.version}</version>
</dependency>

Publié dans Java, Open Source | Laisser un commentaire

Le Saint Graal de la Vidéo


La Vidéo fait partie des domaines les moins fournis dans le milieu des logiciels Open Source. Les applications de visualisation sont présentes mais pour le montage et l’encodage, l’expérience était assez douloureuse !

En bon geek qui se respecte ayant fait « shell script » comme seconde langue à l’école, je suis un habitué de ffmpeg qui est le couteau suisse de l’encodage vidéo. Il permet de faire à peu près toutes les acrobaties possibles, mais sa courbe d’apprentissage le réserve à un public averti !

C’est là qu’interviennent les créateurs de Miro, le célèbre outil de téléchargement et de gestion de bibliothèque multimédia. Celui-ci utilise déjà en interne les librairies de ffmpeg pour la gestion des différents formats audio et vidéo. Ils ont eu l’idée brillante de packager une application dédiée au transcodage de vidéos.

Voici enfin un outil qui va permettre au grand public de pouvoir encoder sans trop de migraines: Miro Video Converter. Il dispose de qualités indéniables:

  • L’interface est tellement efficace que n’importe quelle ménagère de moins de cinquante ans pourra encoder des épisodes de Joséphine Ange Gardien pour son téléphone portable
  • Il s’agit d’un Logiciel Libre téléchargeable et utilisable sans contrainte
  • Il est disponible pour Mac, Linux, et même windows pour toi l’ami qui utilise le dernier système d’exploitation non Unix du marché !

Pour les encodages « master » de mes vidéos professionnelles, je continuerai à privilégier l’utilisation directe de ffmpeg ou quicktime pour avoir un maximum de contrôle sur les paramètres, mais avec cet outil, la porte est grande ouverte à la démocratisation du transcodage par et pour le peuple !

Publié dans IT, Open Source, Vidéo | Laisser un commentaire

Seul au monde

Faisant partie des « early adopters » de périphériques mobiles Apple, je n’avais toutefois jamais fait d’achats d’applications en ligne sur l’App Store. Ce n’est pas l’envie qui manquait, mais l’aspect addictif de l’achat en deux clics me poussait à me méfier de moi-même !

Hier, en parcourant les applications pour iPad je suis tombé sur iA Writer. Un outil d’une simplicité qui le rendait indispensable: un éditeur de texte brut centré sur la saisie incluant une synchronisation directe avec Dropbox.

Donc, là, en bon candide, j’enregistre ma carte de crédit sur mon compte apple, et au moment de la validation, j’ai un gentil message m’indiquant que ma carte n’est pas valide pour cette boutique… Quid ? Interloqué, je réalise qu’habitant au pays des trois frontières et du secret bancaire (le Luxembourg pour vous les français qui payez encore des impôts), je suis persona non grata sur la boutique française ! J’ai donc du basculer sur l’App Store Luxembourgeois…

L’App Store Luxembourgeois, c’est comme l’App Store Français, mais que pour toi ! En effet on se sent terriblement seul au milieu toutes ces applications sans aucune évaluation ni commentaire. On se sent comme enfermé de nuit dans un supermarché à la veille du début des soldes !

Publié dans IT, Moi | Laisser un commentaire

Drobo Rocks

Le cauchemar de l’informatique reste la défaillance matérielle… Le cloud computing arrive, mais pour le geek de 2010 il faut encore savoir faire face à l’adversité. Comme le veut la loi de Murphy, c’est souvent la partie la plus fragile qui est aussi la moins évidente à remplacer. Pour avoir connu les affres de disques durs défaillants dans le passé, la démocratisation des systèmes NAS m’a poussé à aller chercher la sérénité et le bien être mental dans ce type de solutions.

J’ai opté pour un Drobo, plus précisément le modèle Drobo Pro. Ouah avec un nom pareil, la médiocrité n’est pas permise ! Ces modèles ont vraiment le « X factor », ce petit je ne sais quoi qui fait que l’on se sent vraiment en présence d’un produit fini, fiable et orienté utilisateur. Il ne présente aucune interface en ligne évoluée, simplement un stockage redondant fiable, disponible en Ethernet gigabit, USB ou FireWire 800. J’ai opté pour cette dernière solution, car je ne l’utilise que depuis le MacPro et c’est celui-ci qui gère les accès aux données via SSH/SCP. J’ai aussi besoin d’un temps de latence minimal pour l’accès aux données quand je fais de la musique ou de la vidéo, d’où la connexion locale.

Le système permet la manipulation à chaud de disques durs au format SATA2 3″1/2. Ce format est particulièrement économique et te permet donc  à toi aussi, prolétaire des temps modernes de monter en capacité à moindre coût. Il sait fonctionner avec des disques de tailles hétérogènes de façon efficace et garantit la redondance des données sur deux ou trois disques simultanés. Le modèle Pro possède 8 baies de disque, donc un bon potentiel de croissance puisqu’il est capable d’adresser jusqu’à 16 partitions de 16To. Bref, inutile de le préciser, j’adore ce système qui me procure une totale liberté de pensée cosmique vers un nouvel age réminiscent !

Attention toutefois à ne pas le confondre avec son quasi-homonyme, le service de stockage en ligne Dropbox qui partage ce « X factor » mais dans un environnement en ligne qui est complémentaire.

Publié dans Matériel | Laisser un commentaire