Libellés

dimanche 14 août 2011

Javascript et les objets : héritage, prototype, constructor, ...


Javascript n'est pas un langage orienté objet, mais à l'aide des
prototypes nous pouvons quand même nous en sortir.


### Création d'un objet

Le Js est un langage fonctionnel, ce qui signifie que les fonctions
sont au centre du langage. Et donc, pour créer l’équivalent d'une
classe en js, nous allons commencer par créer son constructeur : une fonction.

   var myClass = function(){
     this.name = 'Romain';
   }


Puis ensuite nous allons instancier cet objet :

   var o = new myClass();
   console.log(o.name);


L'instanciation va se dérouler en plusieurs étapes. Tout d'abord un
objet o tout vide va être créé. Ensuite le constructeur myClass va
être appelé sur cette objet. Le this.name va permettre de créer
l'attribut name dynamiquement.


### Le prototype

Le prototype est le dénominateur commun entre toute les instances d'une même classe.

Si j'ajoute un attribut(ou une méthode) sur le prototype de myClass, alors cet attribut (ou méthode) sera present sur toute les instances de myClass.

   myClass.prototype.age = 25;
  
   console.log(o.age);



### Lien entre le prototype et le constructor.

Comme nous l'avons vu tout à l'heure myClass est une fonction qui va permettre de créer l'objet. C'est le constructeur.

  console.log(typeof myClass) //function


A partir de cette fonction nous pouvons accéder au prototype :

  console.log(myClass.prototype) //{ age: 25 }



Et à partir du prototype nous pouvons retrouver le constructeur. Ce qui signifie qu'à partir de n'importe quel objet, nous pouvons retrouver le constructeur car comme nous l'avons vu précédemment toutes les methodes et attributs d'un prototype sont accessible dans les instances.

   console.log( myClass.prototype.constructor === myClass)
   console.log( o.constructor === myClass)



### L'héritage en javascript

Comme chaque instance hérite de son prototype, il suffit de chainer les prototypes pour faire de l'héritage.

Voici un exemple complet :

    /*
     * On créé le constructeur de l'objet A.
     * Ce constructeur va ajouter automatiquement un attribut name à l'objet.
     */
    var A = function(){
      this.name="Romain";  
    };

    A.prototype.sayHello = function(){
       return "Hello "+this.name;  
    };

    /* On fait de même pour l'objet B */
    var B = function(){
      this.age= 25;  
    };

    /* Maintenant on dit que B hérite de l'objet A */
    B.prototype = new A();

    /* Pour ne pas perdre la référence vers constructeur de B */
    B.prototype.constructor = B;


    /* On vérifie que ça marche */
    var o = new B();
    console.log(o.name);             //Romain
    console.log(o.age);              //25
    console.log(o.sayHello());       //Hello Romain
    console.log(o instanceof B);     // true
    console.log(o instanceof A);     //true
    console.log(o instanceof Object);//true

    /* Et pour le fun, on vérifie que les constructeurs sont logiques */
    console.log(B.prototype.constructor === B);  //true
    console.log(A.prototype.constructor === A);  //true


    /* On peut même recréer un objet à partir d'un autre */
    var p = new o.constructor();
    console.log(p.name);  //Romain
    console.log(p.age);   //25

samedi 13 août 2011

Jaxrs client avec Jersey

Ce n'est souvent pas évident de trouver un client Jaxrs. Jersey vous en propose un, et voici comment l'utiliser.  Par défaut j'ai rajouté les logs des requêtes HTTP :


  @Grab('com.sun.jersey:jersey-client:1.8')
  @Grab('com.sun.jersey:jersey-core:1.8')
  @Grab('com.sun.jersey.contribs:jersey-apache-client4:1.8')

  import com.sun.jersey.api.client.*;
  import com.sun.jersey.api.client.filter.LoggingFilter;
  import javax.ws.rs.core.*;
  import com.sun.jersey.client.apache4.ApacheHttpClient4;

  Client client = ApacheHttpClient4.create();
  client.addFilter(new LoggingFilter());
  def resource = client.resource("http://geek-du-soir.blogspot.com").path("/feeds/posts/default")
  resource.accept("application/xml+atom").get(String.class);

jeudi 11 août 2011

Logguer les requettes HTTP de Jersey Client

Pour logguer les requêtes HTTP éffectuées par Jersey Client il suffit de rajouter :

client.addFilter(new LoggingFilter());


Voici un exemple complet :


@Grab('com.sun.jersey:jersey-client:1.8')
@Grab('com.sun.jersey:jersey-core:1.8')
@Grab('com.sun.jersey.contribs:jersey-apache-client4:1.8')

import com.sun.jersey.api.client.*;
import com.sun.jersey.api.client.filter.LoggingFilter;
import javax.ws.rs.core.*;


Client client = create();
client.addFilter(new LoggingFilter());
def resource = client.resource("http://geek-du-soir.blogspot.com").path("/feeds/posts/default")

resource.accept(MediaType.APPLICATION_XML).get(String.class);



import org.apache.http.client.HttpClient;
import org.apache.http.conn.ssl.AllowAllHostnameVerifier;
import org.apache.http.conn.ssl.SSLSocketFactory;
import com.sun.jersey.client.apache4.ApacheHttpClient4;
import com.sun.jersey.client.apache4.config.DefaultApacheHttpClient4Config;

ApacheHttpClient4 create() {
DefaultApacheHttpClient4Config config = new DefaultApacheHttpClient4Config();
ApacheHttpClient4 jerseyClient = ApacheHttpClient4.create(config);
HttpClient httpClient = jerseyClient.getClientHandler().getHttpClient();
SSLSocketFactory sf = (SSLSocketFactory) httpClient.getConnectionManager().getSchemeRegistry().getScheme("https").getSchemeSocketFactory();
sf.setHostnameVerifier(new AllowAllHostnameVerifier());
return jerseyClient;
}

mercredi 10 août 2011

getter et setter avec nodeJs : EcmaScript 5


NodeJs permet d'écrire du code en ECMA Script 5, nous pouvons donc profiter des getter et setter :


/*jslint es5: true */

function MyClass() {
    var name;

    return {
        get name() {
            return name;
        },
        set name(value) {
            name = 'Mr ' + value;
        }
    };
}

var obj = new MyClass();

obj.name = "Romain";   //call the setter
console.log(obj.name); //call the getter

/* print 'Mr Romain' */

mardi 9 août 2011

Commencer nodeJs avec npm, cloud9 et vows sur Archlinux

J'ai la chance de pouvoir tester nodeJs actuellement, je vais donc essayer de vous en faire profiter via mon blog.

Si vous êtes sous windows passez votre chemin. Désolé :-)

Pour les utilisateurs de Linux, je vais surtout vous expliquer comment j'ai installé mon environnement de développement sous Archlinux, mais il est également assez facile de le faire avec Ubuntu (via les ppa)


### Installer nodeJs

NodeJs est le JsDK basé sur le moteur javascript V8 de google, qui vous permettra de coder vos applications en JavaScript.

Contrairement à Java, nodeJs démarre très vite et ne prend pas beaucoup de RAM. C'est très agréable !!!

Le paquet nodejs se trouve dans community, pour l'installer il vous suffit donc de tapper :

pacman -S nodejs

### Installer npm

NPM comme node package manager, correspond au maven java, au gem ruby, ... c'est le gestionnaire de paquet.

Npm se trouve sur AUR, si vous avez yaourt vous pouvez l'installer comme ceci :

yaourt -S nodejs-npm


### Installer cloud9

Cloud9 est un IDE node réalisé en node. C'est un exemple vivant de ce que l'on peut faire avec nodeJs. Je vous conseil de l'installer rien que pour ça.

Le paquet AUR de cloud9 est moins bien conçu que les autres (mais cloud9 n'est simplement pas évident à installer)

yaourt -S cloud9

Puis éditer le PKGBUILD pour appliquer ce patch :

git clone $gitroot $gitname
cd $gitname
- git checkout $gittag
+ #git checkout $gittag
git submodule update --init --recursive


For x86 users, the build fails. You have to remove the 64 bit files :

package() {
+ find -name *linux64* | while read file; do
+ rm $file
+ done
install -d $pkgdir/opt/cloud9


### Installer vows

Vows est la librairie de test nodeJs. Il permet d'écrire des specifications de son code au format bdd. Pour plus d'info : http://vowsjs.org/

Pour l'installer sur votre système, il faut maintenant se reposer sur npm. C'est npm qui va se charger d'installer vows dans /usr

sudo npm install -g vows

sudo pour lui donner les accès root
-g pour qu'il l'installe dans /usr/bin/vows


### Démarrer cloud9

Cloud9 est un serveur web, vous accéderez à l'IDE via votre navigateur web, cool n'est-ce pas :) Et en plus c'est plus léger qu'un IDE lourd !

Bien évidemment Cloud9 n'est actuellement pas l'équivalent de Netbeans mais il propose déjà des corrections de syntaxe, la coloration syntaxique, la mise en forme automatique du code, une console et un debugger (qui ne marche actuellement pas chez moi).

Le meilleurs IDE Js est à mon avis IntelliJ mais il est payant. Sinon NetBeans fonctionne plutôt bien.

Pour lancer cloud9, il faut se placer dans le répertoire de son projet js et lancer la commande :

$ cd myProject
$ cloud9 &
...
Point your browser to http://127.0.0.1:3000


### Premier projet js

Créons la structure du projet :

$ touch index.js #main file
$ mkdir lib/ #sources
$ mkdir test/ #tests


Créons notre premier module :

$ cat lib/Playground.js

//Je déclare un classe, qui sera instanciée en tant qu'objet plus tard
function myClass(){
this.name= "Romain";
this.age=25;
this.getAge= function(){ return this.age; };
this.setAge= function(age){ this.age=age; };
}

//Puis je l'exporte pour pouvoir l'utiliser dans mes tests et dans mon projet
exports.myClass = myClass;



Et le test associé :

var vows = require('vows'),
assert = require('assert'),
playground = require('../lib/Playground');

var myClass = playground.myClass;

vows.describe('play with prototype').addBatch({
'given an object': { //je commence ma description au format BDD
topic: new myClass(), //topic sera l'objet de mon test

'when age is changed': {
topic: function (obj) { //obj === topic
obj.setAge(20);
return obj; //et je redéfinie topic pour qu'il reste === obj
},

'then I get the new age': function (obj) {
assert.equal(21, obj.getAge());
}
}
}
}).exportTo(module); //obligatoire pour utiliser vows comme cli.


Et maintenant si on run vows (soit via cloud9, soit via le cli) :

$ vows test/*.js

given an object when age is changed
✗ then I get the new age
» expected 20,
got 21 (==) // TestPlayGround.js:18

✗ Broken » 1 broken (0.015s)

Sympa le format de sortie :)

jeudi 21 juillet 2011

Ecrire un DSL en Groovy

Récemment j'ai écrit un DSL en Groovy pour WRO4J, et je vais vous expliquer comment y arriver soi même.

Voici à quoi ressemble au final le DSL :

groups {
g1 {
js "/static/app.js"
css "/static/app.css"
}
"an-other-group" {
js("classpath:com/application/static/app.js")
css(minimize: false, "http://www.site.com/static/app.css")
}
}

https://github.com/Filirom1/wro4j/blob/master/wro4j-extensions/src/test/resources/ro/isdc/wro/extensions/model/factory/Wro.groovy

Si l'on analyse un plus le DSL, on retrouve :

- une closure groups englobant l'ensemble du dsl
- deux closures g1 et an-other-group ayant des noms personnalisées
- deux methodes js et css, pouvant prendre 1 ou deux arguments : js(Map params = [:], String uri)


Maintenant pour construire ce DSL nous allons partir de la fin, les méthodes js et css.
Voici le code source, regarder la signature des méthodes :

class ResourceDelegate {
List resources = new ArrayList()

void css(Map params = [:], String name) {
def resource = Resource.create(name, ResourceType.CSS)
if (params.get("minimize") == false) resource.minimize = false
resources.add(resource)
}

void js(Map params = [:], String name) {
def resource = Resource.create(name, ResourceType.JS)
if (params.get("minimize") == false) resource.minimize = false
resources.add(resource)
}
}

Le premier paramètre params est facultatif. Nous pouvons donc utiliser ces méthodes comme ceci :

def resourceDelegate = new ResourceDelegate()

//avec params
resourceDelegate.js([minimize: true, key: value], "js/script.js")
resourceDelegate.js(minimize: true, key: value, "js/script.js")

//et sans params
resourceDelegate.js([:], "js/script.js")
resourceDelegate.js("js/script.js")
resourceDelegate.js "js/script.js"


Maintenant il nous faut intégrer ces méthodes dans une closure pour pouvoir écrire un DSL comme celui là :

myGroup{
js "script.js"
js(minimized: true, "script2.js")
}


Je défini ici une méthode myGroup prenant comme seul paramètre une closure et qui exécute cette closure.

class GroupDelegate {
def myGroup(Closure cl){
cl()
}
}

Je peux donc appeler cette méthode de différentes façons :

myGroup({
println "inside the closure"
})
myGroup {
println "inside the closure"
}

Je vais choisir la deuxième façon qui est plus joli pour un DSL.

Je modifie cette closure pour déléguer tout les appels se passant à l'interieur de cette closure vers une instance de ResourceDelegate (défini dans la première partie)

class GroupDelegate {
List groups = new ArrayList()

def myGroup(Closure cl){
cl.delegate = new ResourceDelegate()
cl.resolveStrategy = Closure.DELEGATE_FIRST
cl()
groups.add(new Group(name: 'myGroup', resources: cl.resources))
}
}

Et maintenant je peux écrire :

@Test
public void testGroupDelegate() {
//setup:
def groupDelegate = new GroupDelegate()

//when:
groupDelegate.myGroup {
js("/js/script.js")
css("/css/style.css")
}

//then:
assert 1 == groupDelegate.groups.size()
assert "myGroup" == groupDelegate.groups[0].name
assert 2 == groupDelegate.groups[0].resources.size()
}


Notre DSL commence à prendre forme, mais nous ne pouvons créer qu'un seul groupe. L'idée maintenant serait de pouvoir écrire plusieurs groupes comme ci dessous :

groupDelegate.g1 {
js("/js/script.js")
css("/css/style.css")
}
groupDelegate.'second-group' {
js("/js/script.js")
css("/css/style.css")
}


Rien de plus simple en groovy, il suffit d'utiliser la méthode def methodMissing(String name, args).
La méthode methodMissing est appelée quand groovy ne trouve aucune méthode correspondant. La variable name nous donne le nom de la méthode appelée et args la liste des arguments passés à la méthode.

Voici cette fois la classe GroupDelegate utilisant methodMissing :

class GroupDelegate {
List groups = new ArrayList()

def methodMissing(String name, args) {
def cl = args[0]
cl.delegate = new ResourceDelegate()
cl.resolveStrategy = Closure.DELEGATE_FIRST
cl()
groups.add(new Group(name: name, resources: cl.resources))
}
}


On approche de la fin, maintenant il nous faut intégrer les différents groupes à l'intérieur d'une closure comme ceci :

wroModelDelegate.groups {
g1 {
js("/js/script.js")
css("/css/style.css")
}
'second-group' {
js("/js/script2.js")
}
}

Comme nous avons déjà réalisé cette tâche précédemment, je vous donne directement la solution (il faut déléguer les appels se passant à l’intérieur de la closure vers une instance de GroupDelegate) :

class WroModelDelegate {
WroModel wroModel = new WroModel()

void groups(Closure cl) {
cl.delegate = new GroupDelegate()
cl.resolveStrategy = Closure.DELEGATE_FIRST
cl()
wroModel = new WroModel(groups: (Collection) cl.getProperty("groups"))
}

}

Courage on approche de la fin. Maintenant on aimerait pouvoir écrire notre DSL dans un fichier dsl.groovy, parser ce fichier et récupérer la valeur.
Pour cela nous allons travailler avec la classe Script de groovy.

def dsl = """
groups {
g1 {
js("/js/script.js")
css("/css/style.css")
}
g2 {
js("/js/script2.js")
}
}
"""

Script dslScript = new GroovyShell().parse(dsl)
dslScript.metaClass.mixin(WroModelDelegate)
dslScript.run()

Ce script (dslScript) contient une liste d'instruction dont la première est d'appeler la methode groups(Closure). Sauf que cette méthode n'est pas connu naturellement dans dslScript.
C'est pour cela que nous faisons appel à dslScript.metaClass.mixin(WroModelDelegate).
Nous mixons le script avec WroModelDelegate, ce qui correspond à ajouter toute les méthodes et les attributs de WroModelDelegate dans le dslScript.

Maintenant il suffit d'executer le script et c'est gagné :D
dslScript.run()



L'ensemble du code source se trouve ici : https://github.com/Filirom1/wro4j/blob/master/wro4j-extensions/src/main/groovy/ro/isdc/wro/extensions/model/factory/GroovyWroModelParser.groovy

Et les tests là :
https://github.com/Filirom1/wro4j/blob/master/wro4j-extensions/src/test/groovy/ro/isdc/wro/extensions/model/factory/TestGroovyWroModelParser.groovy


Une version testable et modifiable en ligne est également disponible ici :
http://groovyconsole.appspot.com/script/516002

Amusez vous bien !!!

PS : je me suis fortement inspiré de http://groovy.dzone.com/news/groovy-dsl-scratch-2-hours

GroovyClassLoader charger et exécuter un Script

Lorsque l'on travaille avec Groovy il est assez facile de charger une classe avec GroovyClassLoader#loadClass

Mais comment faire pour charger et exécuter un script comme celui ci :

[romain@dahu tmp]$ cat MyScript.groovy
println ">>>>>>>>>>>>>>>> It works"
println 10 + 2


En fait c'est assez simple, il suffit de charger la classe, de l'instancier puis de la caster en Script.

[romain@dahu tmp]$ ls
MyScript.groovy Runner.groovy


[romain@dahu tmp]$ cat Runner.groovy
def clazz = this.getClass().getClassLoader().loadClass("MyScript")
def script = (Script) clazz.newInstance()
script.run()


Et ça fonctionne :

[romain@dahu tmp]$ groovy Runner.groovy
>>>>>>>>>>>>>>>> It works
12

lundi 18 juillet 2011

Xrandr forcer la résolution de son écran

J'ai acheté un écran : Packard Bell Maestro 221W qui est sensé supporter la résolution 1680x1050 mais Linux ne la reconnait pas.

Mais grace à xrandr, nous pouvons forcer la résolution.

Sans parametre xrandr affiche les résolutions disponibles : 
[romain@dahu ~]$ xrandr 
Screen 0: minimum 320 x 200, current 1024 x 768, maximum 8192 x 8192
DVI-I-1 disconnected (normal left inverted right x axis y axis)
DVI-I-2 connected 1024x768+0+0 (normal left inverted right x axis y axis) 0mm x 0mm
   1024x768       60.0* 
   800x600        60.3     56.2  
   848x480        60.0  
   640x480        59.9

Nous voyons bien ma résolution 1680x1050 n'est pas reconnue.
Ma carte graphique a deux sorties DVI,  et nous remarquons que c'est la sortie DVI-I-2 qui est utilisée . Important pour la suite.

Je vais maintenant ajouter le mode 1680x1050.

[romain@dahu ~]$ xrandr --newmode "1680x1050" 146.25 1680 1784 1960 2240 1050 1053 1059 1089 -hsync +vsync

Mais comment connître tout ces paramètres lorque l'on ne connait que la résolution de son écran ??? En fait c'est assez simple, il suffit d'utiliser la commande cvt :

[romain@dahu ~]$ cvt 1680 1050
# 1680x1050 59.95 Hz (CVT 1.76MA) hsync: 65.29 kHz; pclk: 146.25 MHz
Modeline "1680x1050_60.00"  146.25  1680 1784 1960 2240  1050 1053 1059 1089 -hsync +vsync

Il suffit de copier coller les paramètres à la suite de 
xrandr --newmode "1680x1050" ......

Maintenant nous allons associer ce mode, à la sortie de notre carte graphique. Nous avions repéré précédemment que nous utilisions la sortie DVI-I-2.
[romain@dahu ~]$ xrandr --addmode DVI-I-2 "1680x1050"

Et maintenant nous allons utiliser ce mode
[romain@dahu ~]$ xrandr -s 1680x1050

Normalement c'est gagné, votre écran vient de changer de résolution.

Ces commandes seront à executer à chaque fois que vous redémarrez votre ordinateur. 

mercredi 13 juillet 2011

Benchmark d'une classe, d'une méthode, ... en Groovy

Pour mesurer le temps d'exécution d'une méthode en Java, on utilise de l'AOP ou des println à la main.

EN Groovy, je viens de découvrir un projet qui s'appelle GBench qui permet de mesurer des temps d’exécutions.

On peut mesurer les temps d’exécutions de toutes les méthodes d'une classe :


@Grab(group='com.googlecode.gbench', module='gbench', version='11.07.05')
import gbench.*

@Benchmark()
class Klass {
def foo() {
Thread.sleep(10)
}
def bar() {
Thread.sleep(5)
}
}

def k = new Klass()

println "call foo"
k.foo()

println "call bar"
k.bar()

Klass void (): 14999053 ns
call foo
Klass java.lang.Object foo(): 14887245 ns
call bar
Klass java.lang.Object bar(): 5129355 ns



Seulement d'une méthode (et regarder comment spécifier le format d'affichage) :

@Grab(group='com.googlecode.gbench', module='gbench', version='11.07.05')
import gbench.*

class Klass {

@Benchmark({println("${method} of ${klass}: ${(time/1000000) as long} ms")})
def foo() {
Thread.sleep(10)
}
def bar() {
Thread.sleep(5)
}
}

def k = new Klass()

println "call foo"
k.foo()

println "call bar"
k.bar()


call foo
java.lang.Object foo() of Klass: 14 ms
call bar



Ou faire des comparaisons sur 1000 exécutions.
Dans cet exemple je compare le Parseur JSON de Groovy 1.8 avec celui de Jackson :


@Grab(group='com.googlecode.gbench', module='gbench', version='11.07.05')
@Grab(group='org.codehaus.jackson', module='jackson-mapper-asl', version='1.8.3')

import gbench.*
import groovy.json.JsonSlurper
import org.codehaus.jackson.map.ObjectMapper;

def slurper = new JsonSlurper()
def mapper = new ObjectMapper();

def jsonString = '{"name": "Romain", "age": 25}'
class Personn{ String name; int age }

def bench = new BenchmarkBuilder()
bench.run(times: 1000){
with 'Groovy JSON', {
Personn p = slurper.parseText(jsonString)
assert p.name == "Romain"
assert p.age == 25
}
with 'Jackson', {
Personn p = mapper.readValue(jsonString, Personn.class)
assert p.name == "Romain"
assert p.age == 25
}
}

println bench


time
Groovy JSON 179218175
Jackson 66699800

Singleton en Groovy

Rien de plus simple que de faire un Singleton en Groovy. Cela se résume à annoter une classe par ​@Singleton, puis à utiliser l'instance via le getter getInstance()

Je vous donne un exemple, testable ici:


​@Singleton
class Personn {
String name
int age
}

​def ​p = Personn.instance;
​p.name = "Romain"
p.age = 25

assert p == Personn.instance;



Si jamais vous tentez d'utiliser le constructeur par défaut, une exception sera lancée.


java.lang.RuntimeException: Can't instantiate singleton Personn. Use Personn.instance
at Personn.(Script1.groovy)
at Script1.run(Script1.groovy:9)




Par contre si vous créez un constructeur (même privé), ça ne marche plus.


@Singleton class Personn {

private Personn(){
println "toto"
}

String name

int age
}

def p1 = new Personn();
def p2 = new Personn();

assert p1 == p2

Assertion failed:

assert p1 == p2
| | |
| | Personn@1ee0563
| false
Personn@1a3e311

jeudi 7 juillet 2011

UglifyJs en Java

UglifyJS est une librairie javascript qui permet de minifier des fichiers javascripts.

Normalement UglifyJs est utilisé avec Node.js, mais si vous voulez appeler UglifyJs depuis un environnement Java vous pouvez le faire à l'aide du projet Wro4J

Vous allez surement me demander pourquoi utiliser UglifyJS en Java alors que Google Closure répond exactement à ce problème ? Vous auriez raison, mais c'est tellement plus drôle d'essayer de faire tourner du Javascript dans une JVM !!!

Aller je vous un bout de code codé en Groovy qui utilise UglifyJS :


@Grab(group = 'ro.isdc.wro4j', module = 'wro4j-extensions', version = '1.3.8')

import ro.isdc.wro.extensions.processor.algorithm.uglify.*

def uglify = UglifyJs.uglifyJs()
uglify.process(new File("/home/romain/plugin/web/web-app/lib/route.js").text);


Wro4J utilise Rhino pour exécuter le Javascript.
Les sources sont ici :
https://github.com/alexo/wro4j/blob/master/wro4j-extensions/src/main/java/ro/isdc/wro/extensions/processor/algorithm/uglify/UglifyJs.java

mardi 5 juillet 2011

Maven : créer un projet multi-module

Maven, le très célèbre outil de build et gestionnaire de dépendances nous offre quelques possibilités bien sympatique.

Vous connaissez sûrement les projets multi-modules, qui permettent de découper un projet pour plus de modularité.

Par exemple vous construisez un projet P. Ce projet est constitué de plusieurs sous-projet A, B, C ayant comme dépendances respectives :

P :
  - A (A1, O)
  - B (O)
  - C (C1, A)

Comme vous le voyez, C dépend de A, mais pas de B. De plus la dépendance O est partagée entre plusieurs sous-projet.

Maven va bous permettre de gérer ses trois sous projet en réduisant le nombre de lignes de code copiées collées.



Voici le pom de P, le projet coordinateur :

<project ....>

    <groupId>org.groupId</groupId>
    <artifactId>P</artifactId>
    <packaging>pom</packaging>
    <version>1.0.0</version>
    <modelVersion>4.0.0</modelVersion>
    
    <modules>
        <module>A</module>
        <module>B</module>
        <module>C</module>
    </modules>
</project>


Il faut remarquer deux choses :
 
  - le packaging == pom, qui nous dit que ce projet n'aura pas de code source
  - la section modules qui représente notre structure.


Ensuite à la racine de ce projet, nous allons créer les 3 sous projets : A, B, C

/my-project
|--pom.xml
|--A
|  `--pom.xml
|--B
|  `--pom.xml
`--C
   `--pom.xml     



Voici le pom du sous-projet A  :

<project ...>
    <parent>
        <artifactId>P</artifactId>
        <groupId>org.groupId</groupId>
        <version>1.0.0</version>
    </parent>
    
    <modelVersion>4.0.0</modelVersion>
    <artifactId>A</artifactId>
    
....


Dans la balise parent, on défini la dépendance vers notre projet parent P.

Nous remarquons que pour A, il n'y a pas de balise groupId ni de balise version à définir A.
En effet, ces valeurs sont héritées du pom parent, pratique !!!!



Maintenant prenons le cas où certains sous-projets aient des dépendances en commun. A et B dépendent de O.

On pourrait tout a fait déclarer dans A et dans B les dépendances complètes (avec la version) :
<dependencies>
    <dependency>
        <groupId>com.aProject</groupId>
        <artifactId>O</artifactId>
        <version>5.6.7</version>
    </dependency>
</dependencies>


Mais le jours, on l'on changera la version de O ( 5.6.7 ---> 5.6.8 ) dans A, on oubliera sûrement de changer la version de O dans B, et l'on se retrouvera avec un pom dégelasse avec plein de dépendances différentes.

La solution consiste donc à ne pas déclarer les versions dans les poms des sous-projets, mais dans le pom parent.


Je vous donne un exemple :

<project ....>

    <groupId>org.groupId</groupId>
    <artifactId>P</artifactId>
    <packaging>pom</packaging>
    <version>1.0.0</version>
    <modelVersion>4.0.0</modelVersion>
    
    <modules>
        <module>A</module>
        <module>B</module>
        <module>C</module>
    </modules>
    
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>commons-io</groupId>
                <artifactId>commons-io</artifactId>
                <version>2.0.1</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.8.2</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>




Dans le pom d'un sous-projet, la section de dépendance ressemblera à :
<dependencies>
    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

Cool, on a supprimé la version !!!!



Maintenant voyons le cas où C dépend de A, c'est à dire étudions les dépendances entre sous-projets.

Voici la section de dépendance de C :
<dependencies>
    ....
    <dependency>
        <groupId>${parent.groupId}</groupId>
        <artifactId>A</artifactId>
        <version>${parent.version}</version>
    </dependency>
    ....
</dependencies>


On est obligé de spécifier la version, mais regardez bien, nous faisons référence à une variable interne : ${parent.version}, de même pour la balise groupId. Zéro problème pour maintenir ce pom !!!


Et maintenant nous pourrions avoir envie de créer nos propres variables dans le pom parent et d'utiliser n'importe où.
Aussitôt dit, aussitôt fait. Editez votre pom parent et ajoutez la section :
<properties>
    <foo.bar>FooBarValue</foo.bar>
</properties>

Maintenant on peut utiliser cette valeur de partout ce cette façon : ${foo.bar}

Il y a bien sur une limite, la section parent ne peut être défini à partir de variable défini dans le pom parent. Sinon ce n'est pas évident pour deviner qui est le parent quand on lit le pom d'un sous-projet.

mardi 28 juin 2011

Compiler des fichers less -> css en Groovy

Less-css est un CSS amélioré.

Pour citer quelques exemples on peut :
- créer des variables et les réutiliser partout
- imbriquer des blocs css, dans d'autre bloc css.
- ...

Par exemple :

@import "global.less";

@size: 14px;

#col{

.odd{
color: red;
font-size: @size;
}

.even{
color: blue;
font-size: @size;
}

}


Les fichiers less sont transformés en CSS par un script js. Ce qui permet de tester en live sur son site web, mais la conversion less/css est plutôt lente.

Il est donc préférable de compiler les fichiers less avant la prod.

Je vous livre donc un code groovy qui permet très facilement de convertir un fichier less en CSS. A vous de le transformer en JAVA et de l'intégrer dans votre environnement de développement.

Pour info, il existe lessc, le compilateur less officiel qui repose sur nodeJS. Si vous ne voulez pas installer node.js, cette version Java vous plaira (elle utilise Rhino).


@Grab(group='com.asual.lesscss', module='lesscss-engine', version='1.0.43')
@GrabResolver(name='asual', root='http://www.asual.com/maven/content/repositories/releases')

import com.asual.lesscss.*

new LessEngine().compile(new File("/home/romain/Bureau/less/root.less"),new File("/home/romain/Bureau/less/root.css"));

lundi 27 juin 2011

Groovy et l'immutabilité

Depuis la version 1.8, Groovy permet de rendre des classes entièrement immutables, c'est à dire des classes qui ne peuvent pas changer d'état.

Ceci peut être pratique pour écrire du code thread safe.

Voici un exemple de classe immutable en Groovy.
PS : ne surtout pas oublier le import groovy.transform.Immutable, sinon c'est l'ancien groovy.lang.Immutable qui est utilisé (Cf : http://comments.gmane.org/gmane.comp.lang.groovy.user/55021)


import groovy.transform.Immutable

@Immutable
final class Punter {
String first
String last
Map params
}

@Immutable
final class PunterWrapper {
String name
Punter punter
}


def wrapper = new PunterWrapper(
name: 'hi',
punter: new Punter(
first: 'Foo',
last: 'Bar',
params: [k: 'value']
)
)


println wrapper

try{
wrapper.punter.params.toto = 3
}catch(Exception e){
println('Exception catched ')
}

try{
wrapper.punter.last = 'Tutu'
}catch(Exception e){
println('Exception catched ')
}

try{
wrapper.name = 'Toto'
}catch(Exception e){
println('Exception catched ')
}

PunterWrapper(name:hi, punter:Punter(first:Foo, last:Bar, params:[k:value]))
Exception catched
Exception catched
Exception catched




Mais écrire des classes immutables en Groovy peux s'avérer complexe à gérer.

Pour éviter récrire le constructeur complet de l'objet à chaque fois que l'on souhaite modifier une valeur, voici une solution que j'ai trouvé :


println new PunterWrapper(wrapper.properties + [
name: 'Titi',
punter: new Punter(wrapper.punter.properties + [
first: 'Mickael'
])
])​

PunterWrapper(name:Titi, punter:Punter(first:Mickael, last:Bar, params:[k:value]))



Un nouvel objet est créé à partir des attributs modifiés de l'ancien objet.



On peut également travailler avec les Collections de la même façon :

def list = [a: 1,b: 2,c: 3].asImmutable()
println list

try{
list​.d=4
}catch(Exception e){
println 'Exception catched'
}


def list2 = (list + [d:4]).asImmutable()
​println list2


def listMutable = list2 + [e:5]
listMutable.f = 6
println listMutable


[a:1, b:2, c:3]
Exception catched
[a:1, b:2, c:3, d:4]
[a:1, b:2, c:3, d:4, e:5, f:6]



Mais il ne faut pas oublier le asImmutable() à chaque modification de la collection.


Groovy nous donne donc quelques possibilités pour travailler dans un environnement immutable, mais ce n'est pas encore très pratique.

Scala est mieux sur ce point là.

lundi 20 juin 2011

JAVA et Groovy

Groovy est un langage de programmation, basé sur Java et s'intégrant très bien avec tout son écosystème.

Pour vanter quelques mérites de Groovy voici des exemple Groovy VS Java :



JAVA
--------
String name "World"
System.out.println("Hello " name);

GROOVY
-----------
def name "World"
println "Hello $name"


JAVA
--------
Map<StringStringparams new HashMap<StringString>();
params.put("key""value")
System.out.println(params.get("key"))

GROOVY
-----------
def params [key"value"]
println params.key



JAVA
--------
public class Customer {

    private String name;

    private int age;

    Customer({
    }

    Customer(String nameint age{
        this.age age;
        this.name name;
    }

    public String getName({
        return name;
    }

    public void setName(String name{
        this.name name;
    }


    public int getAge({
        return age;
    }

    public void setAge(int age{
        this.age age;
    }

    @Override
    public boolean equals(Object o{
        if (this == oreturn true;
        if (== null || getClass(!= o.getClass()return false;

        Customer customer (Customero;

        if (age != customer.agereturn false;
        if (name != null !name.equals(customer.namecustomer.name != nullreturn false;

        return true;
    }

    @Override
    public int hashCode({
        int result name != null name.hashCode(0;
        result 31 result age;
        return result;
    }

    @Override
    public String toString({
        return "Customer{" +
                "name='" name '\'' +
                ", age=" age +
                '}';
    }

    public static void main(String[args{
        Customer toto new Customer("Toto"7);

        Customer toto2 new Customer();
        toto2.setName("Toto");
        toto2.setAge(7);

        System.out.println(toto.equals(toto2));
    }
}


GROOVY
-----------
import groovy.transform.

def toto new Customer(name'Toto'age7)

def toto2 new Customer()
toto2.name 'Toto'
toto2.age 7

assert toto == toto2

@ToString 
@EqualsAndHashCode 
class Customer{

  String name

  int 
age


}






Comme vous le voyez, Groovy permet d'avoir une syntaxe bien plus concise que l'équivalent en Java.

Moins de code à écrire == plus facile à développer == plus facile à lire (une fois que l'on a l'habitude) == plus facile à maintenir...


Et la liste est longue des Groovyness utilisables : 
  - la gestion des collections : filtrage, trie, modification, .... (simplifié grâce à la programmation fonctionnelle) : http://groovy.codehaus.org/Collections
  - la gestion des dates : http://groovy.codehaus.org/JN0545-Dates
  - la création de script dépendant de librairies présent sur Maven : http://groovy.codehaus.org/Grape
  - éviter les null pointer exceptions avec les opérateurs ?. et ?: : http://docs.codehaus.org/display/GROOVY/Operators#Operators-ElvisOperator%28%3F%3A%29
  - la gestion des fichiers : http://groovy.codehaus.org/JN2015-Files
  - toute les exceptions sont gérées comme des RuntimeException
  - ...

Groovy est un langage qui évolue vite, actuellement nous sommes à la version 1.8. Cette version ci rajoute un certain nombre de fonctionnalités intéressantes comme le support natif du JSON, l’annotation @Log qui permet d'injecter un logger (slf4j, log4j, ...), @ToString et @EqualsAndHashCode que je viens de vous montrer et encore pleins d'autres choses merveilleuses à découvrir ici : http://docs.codehaus.org/display/GROOVY/Groovy+1.8+release+notes






Depuis plus d'un an que j'utilise groovy tous les jours, je n'ai toujours pas rencontré de bug. Nous l'avons utilisé pour des scripts, des tests et des applications en production (http://www.grails.org/). C'est un langage que je recommande vraiment. Pour un développeur Java, c'est vraiment une bouffé d'air frais.

Il n'y a pas que des avantages, Groovy est lent, mais je trouve que le temps gagné lors de la phase de développement en vaut la chandelle.

Groovy est dynamique et n'est pas fortement typé, ce qui nécessite d'écrire plus de test unitaire. C'est peut être là sont plus gros défaut. 

Néanmoins, ces problèmes disparaîtront peut être un jours car les performance de Groovy ne font que s'améliorer avec le temps. De plus groovy++ est un projet prometteur car il ajoute un typage statique et des performances équivalentes à celles de Java. Mais je ne l'ai encore jamais testé.

L'intégration avec les IDE n'est pas forcement parfaite : 
  Netbeans -> moyen, 
  IntelliJ -> excellent, équivalent à Java

Mais l'integration avec Maven ne pose aucun problème : http://docs.codehaus.org/display/GMAVEN/Building+Groovy+Projects

Concernant les tests je conseille le framework Spock, sinon un simple JUnit fait très bien l'affaire. Pour du BDD, on peut utiliser EasyB, mais je préfère quand même Spock.

Come Java, Groovy ne favorise pas l'immutabilité (contrairement à scala) est c'est bien dommage pour les applications multi-threadées.

GPars a été intégré avec Groovy depuis la version 1.8 pour simplifier la programmation multi-threadée, mais j'ai encore un peu de mal à l'utiliser. Je ne trouve pas l'API intuitive. Mais bon je vais surement m'y habitué.

Pour avoir également testé Scala quelques jours, Groovy est peut être moins puissant mais est plus facile à prendre en main lorsque l'on est habitué à Java. Mais Scala semble quand même plus robuste et plus simple pour tout ce qui concerne le développement d'applications multi-threadées, tolérantes aux pannes et scalable  : http://akka.io/

lundi 6 juin 2011

TopCoder Arena

Ce soir je vais sur le site de recrutement de Google, et dans la section Préparation de l'entretien, Google nous conseil de s’entraîner sur TopCoder Arena.

Aller je tente.

Après un processus d'enregistrement super chi..., où l'on me demande ma couleur de peau (merci les Etats-Unis) je peux enfin avoir des accès.

Top Coder Arena est une Applet Java qui affiche des problèmes informatiques à résoudre. On se croirait en cours pendant un TD d'info. L'appli permet de compiler et de tester son code avant de le soumettre.

J'ai commencé facile avec un problème à 150 points. Je vous le donne :


Problem Statement
    
***Note: Please keep programs under 7000 characters in length. Thank you


Class Name: HowEasy
Method Name: pointVal
Parameters: String
Returns: int

TopCoder has decided to automate the process of assigning problem difficulty
levels to problems. TopCoder developers have concluded that problem difficulty
is related only to the Average Word Length of Words in the problem statement:

If the Average Word Length is less than or equal to 3, the problem is a 250
point problem.
If the Average Word Length is equal to 4 or 5, the problem is a 500 point
problem.
If the Average Word Length is greater than or equal to 6, the problem is a 1000
point problem.

Definitions:
Token - a set of characters bound on either side by spaces, the beginning of
the input String parameter or the end of the input String parameter.
Word - a Token that contains only letters (a-z or A-Z) and may end with a
single period. A Word must have at least one letter.
Word Length - the number of letters in a Word. (NOTE: a period is NOT a letter)

The following are Words :
"ab", "ab."

The following are not Words :
"ab..", "a.b", ".ab", "a.b.", "a2b.", "."

Average Word Length - the sum of the Word Lengths of every Word in the problem
statement divided by the number of Words in the problem statement. The
division is integer division. If the number of Words is 0, the Average Word
Length is 0.

Implement a class HowEasy, which contains a method pointVal. The method takes
a String as a parameter that is the problem statement and returns an int that
is the point value of the problem (250, 500, or 1000). The problem statement
should be processed from left to right.

Here is the method signature (be sure your method is public):
int pointVal(String problemStatement);

problemStatement is a String containing between 1 and 50 letters, numbers,
spaces, or periods. TopCoder will ensure the input is valid.

Examples:

If problemStatement="This is a problem statement", the Average Word Length is
23/5=4, so the method should return 500.
If problemStatement="523hi.", there are no Words, so the Average Word Length is
0, and the method should return 250.
If problemStatement="Implement a class H5 which contains some method." the
Average Word Length is 38/7=5 and the method should return 500.
If problemStatement=" no9 . wor7ds he8re. hj.." the Average Word Length is 0,
and the method should return 250.
Definition
    
Class: HowEasy
Method: pointVal
Parameters: String
Returns: int
Method signature: int pointVal(String param0)
(be sure your method is public)
    


Et je vous donne ma solution.


import java.util.regex.*;

public class HowEasy{

Pattern regex = Pattern.compile("[a-zA-Z]+\\.?$");

public int pointVal(String problemStatement){
String[] words = problemStatement.split(" ");
int matchingWords = 0;
int wordLength=0;
for(String word: words){
Matcher m =regex.matcher(word);
if(m.matches()){
matchingWords++;
wordLength+=word.length();
}


}

if(matchingWords==0) return 250;

int avgWordLength = wordLength / matchingWords;
if(avgWordLength<=3){
return 250;
}else if(avgWordLength==4){
return 500;
}else if(avgWordLength==5){
return 500;
}else{
return 1000;
}


}

}


150 points / 250, c'est pas terrible, je peux mieux faire.
Je pense que j'ai oublié d'enlever les points pour calculer la longueur des mots.

A vous !!!

lundi 16 mai 2011

Expo Soufflez du vert à Paris

Une petite info qui n'a rien à voir avec l'informatique pour une fois.

Aux tuileries du 25 au 29 mai aura lieu une exposition sur les jardins et les designs extérieurs.

Voici une des expositions à découvrir absolument :


http://soufflez-du-vert.github.com/ (site prochainement accessible)

Et oui le site est hébergé par Github ;)

lundi 9 mai 2011

Dig en Java

DNSJava est une API JAVA permettant de faire des résolutions de domaines.

DNSJava offre également une implémentation équivalente à dig (voir les sources)

Si vous souhaitez parser le contenu d'un DIG en Java pour récupérer les IPs des serveurs, je vous conseil plutôt d'utiliser l'API de DNSJava.
Vous aurez une représentation objet du DIG qui vous permettra de ne récupérer que ce qui vous intéresse vraiment.

Voici un exemple écrit en groovy qui fait l'équivalent d'un 'dig google.com'


import org.xbill.DNS.*;

@Grab(group='dnsjava', module='dnsjava', version='2.1.1')

SimpleResolver res = new SimpleResolver();
Record rec = Record.newRecord(Name.fromString("google.com", Name.root), Type.A, DClass.IN);
Message query = Message.newQuery(rec);
Message response = res.send(query);
println("----------------------------------------------------------");
for (Record record : response.getSectionArray(1)) { // ANSWER SECTION
println(record.rdataToString());
}
println("----------------------------------------------------------");
println(response.toString()); //THE WHOLE DIG


Et voici le résultat affiché :

--------------------------------------------------------
209.85.227.106
209.85.227.103
209.85.227.105
209.85.227.104
209.85.227.99
209.85.227.147
--------------------------------------------------------
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 53158
;; flags: qr rd ra ; qd: 1 an: 6 au: 0 ad: 0
;; QUESTIONS:
;; google.com., type = A, class = IN

;; ANSWERS:
google.com. 300 IN A 209.85.227.106
google.com. 300 IN A 209.85.227.103
google.com. 300 IN A 209.85.227.105
google.com. 300 IN A 209.85.227.104
google.com. 300 IN A 209.85.227.99
google.com. 300 IN A 209.85.227.147

;; AUTHORITY RECORDS:

;; ADDITIONAL RECORDS:

;; Message size: 124 bytes

vendredi 15 avril 2011

Grails thumbnail : Reduire une image dans grails en gardant une bonne qualité

En java ce n'est pas forcement facile de trouver une librairie pour réduire des images en gardant une bonne qualité.

Heureusement il existe le projet Java Image Scaling qui a sa librairie sur maven.
http://code.google.com/p/java-image-scaling/


Maintenant voici comment intégrer Java Image Scaling dans grails : un jeu d'enfant :)

Ajouter la dépendance suivante dans grails-app/conf/BuildConfig.groovy


runtime 'com.mortennobel:java-image-scaling:0.8.5'


Dans votre controller ajoutez le bout de code suivant :


/**
* Return the content of screen shot
*/
def viewScreen = {
File img = new File("myImage.png")
response.contentType = 'image/png'
if(params.thumbnail){
BufferedImage inputImage = ImageIO.read(img);
BufferedImage rescaledImage = new MultiStepRescaleOp(DimensionConstrain.createMaxDimension(355,500)).filter(inputImage, null);
def outputStream = new ByteArrayOutputStream()
ImageIO.write(rescaledImage, "png", outputStream);
response.outputStream << outputStream.toByteArray()
}else{
response.outputStream << img.bytes
}
}

jeudi 14 avril 2011

Firefox4 (Iceweasel4) sur Debian Squeeze

La méthode est simple il suffit de saisir les commandes suivantes sous root :


echo "deb http://mozilla.debian.net/ squeeze-backports iceweasel-4.0" > /etc/apt/sources.list.d/firefox.list

apt-get update

apt-get install iceweasel

Selenium JUnit4 et Maven

Voici un exemple de test Junit qui démarre un Serveur Selenium puis execute un ensemble de tests.

Je prefère ce type de configuration, plutôt que d'écrire 50 lignes de XML dans maven afin de lancer un serveur selenium : http://blog.xebia.fr/2011/02/18/automatiser-les-tests-selenium-avec-maven/

import com.thoughtworks.selenium.DefaultSelenium;
import org.junit.*;
import org.openqa.selenium.server.SeleniumServer;

import static org.junit.Assert.*;


public class DemoTest {

private static SeleniumServer server;
private DefaultSelenium selenium;

@BeforeClass
public static void startSeleniumServer() throws Exception {
System.out.println("START Selenium Server");
server = new SeleniumServer();
server.start();
}

@Before
public void fixture() {
selenium = new DefaultSelenium("localhost", 4444, "*firefox" , "http://google.fr/");
selenium.start();
}

@Test
public void testWhatYouWant() throws Exception {
...
}

@Test
public void testWhatYouWant2() throws Exception {
...
}

@After
public void tearDown() throws Exception {
selenium.stop();
}

@AfterClass
public static void stopSeleniumServer() throws Exception {
server.stop();
}
}



Voici mes dépendances maven :


<dependencies>
<dependency>
<groupid>junit</groupid>
<artifactid>junit</artifactid>
<version>4.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupid>org.seleniumhq.selenium</groupid>
<artifactid>selenium-server</artifactid>
<version>2.0b3</version>
</dependency>
<dependency>
<groupid>org.seleniumhq.selenium</groupid>
<artifactid>selenium-remote-control</artifactid>
<version>2.0b3</version>
</dependency>
</dependencies>

jeudi 24 mars 2011

Script SQL en Groovy

Voici un exemple de script Groovy se connectant sur une base de donnée MySQL avec Groovy Grape :


import org.springframework.jdbc.datasource.SimpleDriverDataSource;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource;

@GrabConfig(systemClassLoader=true)
@Grab(group='mysql', module='mysql-connector-java', version='5.1.6')
@Grab(group='org.springframework', module='spring-jdbc', version='3.0.5.RELEASE')


DataSource dataSource = new SimpleDriverDataSource(
Class.forName("com.mysql.jdbc.Driver").newInstance(),
"jdbc:mysql://localhost:3306/myDatabase",
"login",
"password");

JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
println jdbcTemplate.queryForList( """SELECT 1;""" )


C'est très pratique pour debugguer les erreurs du type :

Caught: org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure

Last packet sent to the server was 0 ms ago.
at test.run(test.groovy:19)

jeudi 10 mars 2011

Parcellite copier-coller : synchroniser la selection avec le presse papier

Dans linux il existe deux espaces pour faire des copier coller :
  - la selection du curseur pour copier et clique du miileu (ou Shift Inser) pour coller
  - et le presse papier : Ctrl + C pour copier et Ctrl + V pour coller

Mais si on se trouve sur un portable avec l'impossibilité de faire un clique du milieu pour coller la selection et l'impossibilité de faire un Ctrl + C pour copier on se retrouve bien coincé.

Le cas typique est celui de coller dans un navigateur web un selection faite sous xterm . Xterm ne permet pas de copier dans le presse papier, et google-chrome comme firefox ne colle pas le contenu de la selection lors d'un Shift - Inser.

La solution existe. Il suffit d'utiliser parcellite :

apt-get install parcellite


Ensuite il suffit simplement de configurer parcellite :

$ cat .config/parcellite/parcelliterc

[rc]
use_copy=true
use_primary=true
synchronize=true
save_history=true
history_limit=25
hyperlinks_only=false
confirm_clear=false
single_line=true
reverse_history=false
item_length=50
ellipsize=2
history_key=H
actions_key=A
menu_key=P




Puis de le lancer en tache de fond

parcellite &

Debian : Nodm pour lancer X avec autologin

Avec une Debian Squeeze, si l'on souhaite lancer une session X au démarrage sans saisir de mot de passe, soit on utilise un display manager (gdm, kdm, lxdm, ...) soit un utilise nodm.

Nodm ne demande rien, il demarre juste xinit au démarrage sous un utilisateur particilier.

Pour installer nodm :

apt-get install nodm


Et pour l'activer il faut éditer le fichier :

cat /etc/default/nodm


# nodm configuration

# Set NODM_ENABLED to something different than 'false' to enable nodm
NODM_ENABLED=true

# User to autologin for
NODM_USER=romain

# xinit program
NODM_XINIT=/usr/bin/xinit

# First vt to try when looking for free VTs
NODM_FIRST_VT=7

# X session
NODM_XSESSION=/etc/X11/Xsession

# Options for the X server
NODM_X_OPTIONS='vt7 -nolisten tcp'

# If an X session will run for less than this time in seconds, nodm will wait an
# increasing bit of time before restarting the session.
NODM_MIN_SESSION_TIME=60



Maintenant afin de lancer un window manager (par exemple wmfs), il faut editer le fichier : ~/.xsession

$ cat .xsession

#!/bin/sh
wmfs

lundi 7 mars 2011

Selenium Perl et Debian (ou Ubuntu)

Selenium IDE : http://seleniumhq.org/projects/ide/ permet de créer des scripts selenium et de les exporter sous différents langage : Java, C#, Groovy, Python, Ruby et Perl pour les sysadmins


Ce qui nous intéresse ici c'est d'utiliser perl!


Tout d'abord il faut installer les paquets suivant :

apt-get install perl libtest-exception-perl libtest-www-selenium-perl


Ensuite il faut créer un script selenium sous Selenium IDE et l'exporter au format Perl.

Voici un script selenium bidon exporté en Perl :

use strict;
use warnings;
use Time::HiRes qw(sleep);
use Test::WWW::Selenium;
use Test::More "no_plan";
use Test::Exception;

my $sel = Test::WWW::Selenium->new( host => "localhost",
port => 4444,
browser => "*chrome",
browser_url => "http://fr.yahoo.com/" );

$sel->open_ok("/");
$sel->click_ok("link=Jacques Chirac aux portes du tribunal pour un procès?");
$sel->wait_for_page_to_load_ok("30000");
$sel->click_ok("link=Villepin souhaite que Chirac soit jugé, s'oppose à un report");
$sel->wait_for_page_to_load_ok("30000");


Maintenant si on lance le script perl on obtient l'erreur suivante :

Error requesting http://localhost:4444/selenium-server/driver/?cmd=getNewBrowserSession&1=*chrome&2=http%3A%2F%2Ffr.yahoo.com%2F:
500 Can't connect to localhost:4444 (connect: Connexion refusée)
# Looks like your test died before it could output anything.
zsh: exit 255 perl perl.pl

Ce qui signifie qu'il n'y a pas de serveur selenium de lancé.


Pour lancer un serveur selenium, il y a plusieurs méthodes :

1 - On télécharge le jar de selenium-server et on le lancer en java

firefox http://seleniumhq.org/download/
java -jar selenium-server.jar


2 - Sinon, on exécute le script groovy suivant (Il s'occupe de télécharger et lancer Selenium Server)

import com.thoughtworks.selenium.*
import org.openqa.selenium.server.*

@Grab(group='org.seleniumhq.selenium.server', module='selenium-server', version='1.0.1')

def server = new SeleniumServer()
server.main(new String[0])
println("Started")