iMotion

Mon logiciel iMotion avance doucement. Quelques optimisations du code avec GStreamer permettent maintenant de switcher d’effet trčs rapidement. En effet auparavant le changement d’effet réinitialisait le pipeline et donc la webcam. Maintenant je bloque le pad de la webcam, ce qui me permet de détruire l’ancien GstElement en charge de l’effet, le recréer avec le nouvel effet puis relier les pads. Le résultat est un changement trčs réactif, on peut s’amuser ŕ jongler entre les effets sans latence. GStreamer me parait trčs puissant et est ŕ mon avis mal exploité par les logiciels existants. Par exemple Cheese réinitialise la webcam ŕ chaque changement d’effet, je la vois qui clignote…

Il y a je pense encore beaucoup ŕ faire côté multimédia sur Linux, et si l’on veut un peu plus qu’un “simple” lecteur vidéo il nous faudrait de tout évidence un GIMP de la vidéo. Je n’ai bien sűr pas cette prétention, d’autant plus que je m’intéresse plus ŕ l’aspect temps réel que post traitement. Sans aller vers un logiciel aussi poussé que vidvox GNU/Linux est ŕ mon avis capable d’aller sur ce secteur dévolu ŕ Apple. Encore faut-il accepter que cela sera impossible en utilisant de simple langage script comme Python ou Ruby, chose que j’ai fini par admettre :)

Be Happy

Ca s’arrange pas dans la section ciné, on est trčs déçu de ce Be Happy qui semblait prometteur. Hormis le jeu sympathique de l’actrice, le film tourne en rond et ŕ part quelques rigolades c’est plutôt plat …

Babylon A.D.

Bin dis donc le gros caca de Mathieu Kassovitz !

Le rubyFlow FR disponible

Après que Peter Cooper ait libéré le code original de rubyflow, Bruno Michel a pris les choses en mains pour traduire l'application. L'association RubyFrance a ensuite hébergé le tout. Nous voilà donc maintenant avec notre propre rubyflow FR. Bravo pour cette initiative.

RubyFlow Fr

Il y avait RubyFlow, grâce Ă  l’association RubyFrance il y a maintenant RubyFlow Fr

Vous ne pourrez pas dire que vous ne saviez pas…

Gettext avec Rails, ca peux ĂŞtre long pour un formulaire en erreur

Aujourd'hui, j'ai passé la journée à essayer de comprendre un problème que j'avais sur l'application que je réalise dans le cadre de mon nouveau travail. Ce bug est très simple. Durant la validation d'un formulaire, si celui-ci n'était pas valide, je retournais sur la même page qui m'indiquait les champs en erreur. Dans la pratique, ceci est très simple. Mais dans notre cas, la page m'était pas moins de 40 secondes à se renderer. Car la latence n'avait pas lieu dans le controlleur, mais belle est bien durant le rendering de la page.

Pour essayer de comprendre la cause de tout ça, j'ai fini par réaliser un profile de ma requête avec le script /script/performance/request qu'il a déjà fallu faire fonctionner, mais ceci fera l'objet d'un autre billet. Une fois le profilling réalisé, j'ai constaté que ce qui me posait problème était une recherche incessante de traduction des messages d'erreurs. Après de longue recherche dans le code, j'ai fini par découvrir la vrai cause du problème.

Dans Rails, durant chaque création de tag, il y a une demande de récupération de errors.on pour connaitre là où les erreurs sont et ainsi mettre en surbrillance le champs ou non. Mais là où normalement dans Rails, ce n'est qu'un appel vers un valeur figé, Gettext a décoré la méthode pour réaliser une traduction de la chaine. Bien sûr si ce n'était que ça, ça pourrait encore passé, car finalement c'est le comportement en production. Les chaines étant misent en cache, l'accès est quasiment aussi rapide que sans gettext. Mais dans le cas d'un environnement en Développement, il n'y a aucun cache des chaines de Gettext. Ainsi à chaque tentative de traduction le mo file est chargé et une itération à lieu sur tout ce fichiers pour trouver la chaine à traduire. C'est ces itérations incessantes qui entrainait un temps de traitement extrêmement long de ma requête.

Ce phénomène n'a lieu uniquement qu'en environnement de développement, car il y a un test sur le nom de l'environnement. Dans tous les autres cas autre que développement, les mo sont mis en cache.

Pour résoudre ce problème, soit vous changé le nom de votre environnement par défaut, par exemple dev au lieu de développement, où alors mettre le code GetText.cached = true dans votre environnement.rb. Cela implique par contre que si vous modifier les fichiers mo, il faudra redémarrer le serveur pour avoir les nouvelles entrées.

(FOP + Ruby) / Rjb

Je travaille en ce moment, dans le cadre de mon boulot, sur la mise en place d’une plateforme documentaire. L’idĂ©e Ă©tant d’ĂŞtre capable de gĂ©nĂ©rer de la documentation sous format HTML et PDF.

J’utilisais dĂ©jĂ  FOP pour ce travail, mais en “solo”. Le besoin maintenant implique un travail d’Ă©quipe avec plusieurs rĂ©dacteurs, correcteurs, relecteurs… Nous avions dĂ©jĂ  une XSL permettant de passer de XML vers FO, et on pourrait croire qu’un simple gestionnaire de version complĂ©terait simplement cet existant pour permettre un travail de groupe.

Ce n’est pas aussi simple que cela. En effet, nous voulons que la documentation soit gĂ©nĂ©rĂ©e sur le serveur ou sont placĂ©s les documents XML. Facile direz vous. Oui, mais il faut en plus pouvoir contrĂ´ler comment se passe la “fabrication” des documents. Pouvoir les visualiser… Et mĂŞme, pouvoir en corriger certaines parties, et cela, sans obliger ceux qui interviennent ponctuellement sur les documents (correcteurs, relecteurs en particulier) Ă  ne pas ĂŞtre obligĂ©s de se plonger dans une syntaxe XML obscure et rebutante. Pour cela une petite interface Web est apparue comme une bonne solution. J’en reparlerai plus tard, mais nous avons mĂŞme une solution simple permettant de modifier en WYSIWYG un fichier XML…

Venons-en au fait… Vous vous en doutiez, mais cette interface (et tout le reste de la plateforme) est faite en Ruby (je me demande bien avec quoi ?). Et très rapidement j’ai eu besoin de pouvoir gĂ©nĂ©rer les documents via FOP depuis des scripts Ruby. Pour cela RJB est mon ami. Voici ce que donne le source ExampleXML2PDF.java proposĂ© par Apache une fois passĂ© dans les mains du couple Ruby-RJB :

require ‘rubygems’
require ‘rjb’

# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# export CLASSPATH=~/Downloads/fop-0.95/build/fop.jar:\
#   ~/Downloads/fop-0.95/lib/xmlgraphics-commons-1.3.1.jar:\
#   ~/Downloads/fop-0.95/lib/commons-logging-1.0.4.jar:\
#   ~/Downloads/fop-0.95/lib/commons-io-1.3.1.jar:\
#   ~/Downloads/fop-0.95/lib/avalon-framework-4.2.0.jar:\
#   ~/Downloads/fop-0.95/lib/batik-all-1.7.jar

class Fop
  def initialize( classpath = nil )
    # The ‘-Djava.awt.headless=true’ parameter is due to the "Can’t start the AWT" error on Mac.
    # I hope it do not affect others environments.
    Rjb::load( classpath, [‘-Djava.awt.headless=true’] )

    @jFile = Rjb::import( ‘java.io.File’ )
    @jFileOutputStream = Rjb::import( ‘java.io.FileOutputStream’ )
    @jBufferedOutputStream = Rjb::import( ‘java.io.BufferedOutputStream’ )

    # jTrasnformer = Rjb::import( ‘javax.xml.transform.Transformer’ )
    @jTransformerFactory = Rjb::import( ‘javax.xml.transform.TransformerFactory’ )
    # jSource = Rjb::import( ‘javax.xml.transform.Source’ )
    # jResult = Rjb::import( ‘javax.xml.transform.Result’ )
    @jStreamSource = Rjb::import( ‘javax.xml.transform.stream.StreamSource’ )
    @jSAXResult = Rjb::import( ‘javax.xml.transform.sax.SAXResult’ )

    @jFOUserAgent = Rjb::import( ‘org.apache.fop.apps.FOUserAgent’ )
    @jFopFactory = Rjb::import( ‘org.apache.fop.apps.FopFactory’ )
    @jMimeConstants = Rjb::import( ‘org.apache.fop.apps.MimeConstants’ )
    # jFop = Rjb::import( ‘org.apache.fop.apps.Fop’ )
  end
 
  def xml2pdf( xmlFile, xslFile, pdfFile )
   
    # Setup directories
    baseDir = @jFile.new( "." )
    outDir = @jFile.new( baseDir, "out" )
    outDir.mkdirs()
   
    # Setup input and output files
    xml = @jFile.new( baseDir, xmlFile )
    xslt = @jFile.new( baseDir, xslFile )
    pdf = @jFile.new( outDir, pdfFile )
   
    # configure fopFactory as desired
    fopFactory = @jFopFactory.newInstance( )
    foUserAgent = fopFactory.newFOUserAgent( )
   
    # Setup output
    out = @jFileOutputStream.new( pdf )
    out = @jBufferedOutputStream.new( out )
   
    # Construct fop with desired output format
    fop = fopFactory.newFop( @jMimeConstants.MIME_PDF, foUserAgent, out )
 
    # Setup XSLT
    factory = @jTransformerFactory.newInstance( )
    transformer = factory.newTransformer( @jStreamSource.new( xslt ) )
   
    # Set the value of a <param> in the stylesheet
    # transformer.setParameter( "versionParam", "2.0" )
   
    # Setup input for XSLT transformation
    src = @jStreamSource.new( xml )
   
    # Resulting SAX events (the generated FO) must be piped through to FOP
    res = @jSAXResult.new( fop.getDefaultHandler( ) )
   
    # Start XSLT transformation and FOP processing
    transformer.transform( src, res )
   
    # Close output file
    out.close( )
  end
end

if $0 == __FILE__
  fop = Fop.new
  fop.xml2pdf( "xml/pdf/index-pdf.xml", "xsl/XML2PDF.xsl", "doc.pdf" )
end

Extlib

Extlib regroupe les extensions de Ruby Core qui ont été développées pour Merb, DataMapper et DataObjects. C’est pratique, c’est léger et il y a des specs ! Et c’est une dépendance de Qt::JRuby 0.2.2.

La couleur de l’Ajax…

Dans un post du mois d’aout, Nicolas disait voir rouge… Et bien j’aime la couleur !

Dans un autre poste, plus ancien, Sunny nous proposait de redécouvrir cursor:progress.

Et bien je me suis amusé à marier les deux via un plugin Bivouac (non encore disponible) :

Ajax::Responders.register( {
  :on_create => function {  
    e = $class-(‘body’)
    e.first().addClassName(‘loading’)
  },
  :on_complete => function {
    if Ajax[:activeRequestCount] == 0
      e = $class-(‘body’)
      e.first().removeClassName(‘loading’)
    end
  }
} )

Fin des vacances…

Et ce fut le grand retour au boulot… Quoi qu’il en soit, ce temps de repos fut fort agrĂ©able…

Je ne suis pas de nature à vous montrer des photos de tonton DD à la plage ou la cousine Berth mangeant une galette à la crêperie du port, mais voici tout de même une petite sélection de photos prises cet été.



Bonne reprise Ă  tous.