lundi 30 avril 2018

Modèle de courrier de réclamation pour retard de vol


Voici le modèle de lettre utilisé avec succès pour me faire indemniser la somme le 400 euros suite au retard de 3h35 de mon vol entre Saint Denis de la Réunion et Paris Orly. Vous pouvez l'adapter à votre contexte en modifiant les parties surlignées en jaune et en vérifiant que vous rentrez bien dans l'un des cas d'indemnisation en cas de retard de vol.

VOTRE NOM PRENOM
ADRESSE POSTALE

Service Relations Clientèle
ADRESSE COMPAGNIE AERIENNE

Objet : Indemnisation suite à retard de vol

Vol concerné :
Vol TX6701 opéré par BF701
La Reunion (Saint Denis de la Reunion) (RUN) à Paris (Orly) (ORY)
Le 23/02/2018
Départ : prévu 8h00 effectif 11h55
Arrivée : prévue 16h30 effective 20h05
Retard à l’arrivée 3h35

Au regard de la règlementation (CE) n° 261/2004 relatif à un retard de trois heures ou plus pour tous les vols intracommunautaires de plus de 1 500 km, compte tenu du retard de 3h35 à l’arrivée de mon vol entre Saint Denis de la Réunion et Paris Orly (tous deux situés en communautée européenne), je vous réclame par la présente le versement du dédommagement prévu de 400 (quatre cent) euros par passager exclusivement par chèque à l’ordre de VOTRE NOM ou Virement bancaire sur l’IBAN ci joint conformément au règlement européen n°261/2004 article 7 : “l'indemnisation visée au paragraphe 1 est payée en espèces, par virement bancaire électronique, par virement bancaire ou par chèque, ou, avec l'accord signé du passager, sous forme de bons de voyage et/ou d'autres services”.

Je tiens également à signaler que, contrairement à vos obligations légales, aucune information ne m’a été faite concernant mes droits pour ce retard (au départ comme à l’arrivée), ni à l’enregistrement, ni à l’embarquement, ni pendant le vol ni même à l’arrivée.

Vous trouverez ci joint les documents suivants

  • IBAN
  • carte d’embarquement
  • passeport
  • capture d’écran

En vous remerciant par avance du traitement rapide de cette demande.
Cordialement
VOTRE NOM + SIGNATURE

Avion retardé ? Faites vous rembourser jusqu'à 600€

Récemment, j'ai subit une mésaventure à laquelle, malheureusement, de nombreuses personnes sont confrontées... Arrivée à l'aéroport, attente, avion qui décolle en retard et avion qui atterrit en retard. La journée se rallonge... Le temps de chercher sur Google quels sont mes droits et je tombe sur une multitude de sites qui vous font miroiter jusqu'à 600€ de dédommagement en quelques clics.

3h26 de retard sur un vol La Réunion - Paris

Pour se rémunérer, ces sites prélève une commission d'à peu près 25% sur le dédommagement qu'ils obtiennent... Ce qui vous fait perdre jusqu'à 600€ si vous voyagez à 4 en famille sur un New York - Paris qui arrive avec plus de 4 heures de retard.

En farfouillant un peu, je tombe sur la réglementation européenne et je me rend compte que tout n'est pas si compliqué finalement si l'on souhaite se faire rembourser par ses propres moyens, en quelques clics également et obtenir la totalité de l'indemnisation légale !

Vos droits

La règlement européenne (CE) n° 261/2004 prévoit une indemnisation forfaitaire (sans rapport avec le prix du billet) d'un montant qui dépend de la longueur du vol, de son retard et de son caractère intracommunautaire (départ et arrivé depuis un aéroport situé en union européenne, Suisse comprise)

  • 250€ pour les vols de moins de 1500 kilomètres qui ont au moins 2 heures de retard
  • 400€ pour tous les vols intracommunautaires de plus de 1500 kilomètres et pour tous les autres vols de 1500 à 3500 kilomètres qui ont au moins 3 heures de retard
  • 600€ pour tous les autres vols qui ne relèvent pas des points ci dessus et qui ont au moins 4 heures de retard
Tout cela est valable si votre avion décolle depuis un aéroport situé en Europe (ou Suisse) ou si votre avion atterrit en Europe (ou Suisse) au départ de n'importe quel pays et que le vol est opéré par une compagnie européenne (par exemple, vous n'aurez droit à rien si vous vous avez 6 heures de retards au départ de Vancouver et que vous voyagez avec Air Canada).

La réglementation précise que "l'indemnisation [...] est payée en espèces, par virement bancaire électronique, par virement bancaire ou par chèque, ou, avec l'accord signé du passager, sous forme de bons de voyage et/ou d'autres services". N'acceptez donc pas un bon de voyage ou avoir si vous ne le désirez pas. Le plus simple est d'utiliser le modèle de lettre de réclamation que je vous fournit plus bas.

Faire valoir vos droits

Vous pouvez choisir de passer par les nombreux sites que vous trouverez en effectuant une recherche Google. Sinon, voici comment procéder :
  1. Vérifier que vous entrez dans l'un des cas de retard ci dessus, et faites une capture d'écran sur le site de l'aéroport d'arrivé (ou de départ) ou en utilisant flightstats.com muni de votre numéro de vol pour conserver une trace du retard de votre vol;
  2. Rassemblez les éléments suivants : billets d'avion / cartes d'embarquement, pièces d'identités des voyageurs (scannez les si besoin)
  3. Rendez vous sur le site de la compagnie aérienne opérant le vol. Si vous voyagez entre San Francisco et Amsterdam sur un vol United Airlines opéré par KLM, c'est sur le site de KLM qu'il faudra aller.
  4. Si vous trouvez un formulaire de contact dédié aux réclamations relatives aux retards (Air France), alors vous devriez pouvoir tout faire en ligne, sinon, trouvez l'adresse postale du service client / réclamation et vous aurez un courrier recommandé à envoyer (ce qui peut être fait en ligne également).
Ensuite, vous n'avez plus qu'à utiliser le modèle de lettre de réclamation pour un vol retardé...

Modèle de courrier de réclamation

Il ne reste plus qu'à envoyer le courrier et les pièces nécessaires : copie cartes d'embarquement, copie des pièces d'identité, RIB/IBAN, adresse postale, capture d'écran justifiant du retard...

mardi 16 janvier 2018

Consider this before updating your app in Google Play

Context

There a lot of things happening when you deploy an update of your app on Google Play... One of the bad experiment I had lately was caused by Kaspersky free antivirus, one of the most popular tool for Android.

Looking at comment from people who updated my Bubble Level app, I discovered that Kaspersky free antivirus detected a threat in the latest update...


Kaspersky free antivirus screenshot

Too late, the app was already deployed and the number of bad comments from users were raising...

Uninstall peak after update

So had I to rollback the app version in production.

The problem

You cannot revert an app version in the Google Play console...

The solution(s)

Rebuild the app from the previous version tag from your VCS. But sometimes, it means downloading Gigs of old SDK, build tools, artefacts you don't care anymore... So here is a simple solution.
  1. Download previous apk from your Google Play publisher account
  2. Download apktool
  3. Decompile the app apk using apktool
  4. Update the apktool.yml to increase version code and version number
  5. Recompress the app apk using apktool
  6. Sign it using jarsigner from java distribution
  7. Align it using zipalign from android sdk distribution
  8. Upload your apk in your Google Play publisher account

Lesson learned

Have Kaspersky scan performed before release !
Enjoy !

Update

I oppenned a ticket using the Kaspersky free antivirus app, everything was solve within two days. Kaspersky updated its antivirus database. My app is no longer considered as a false positive...

vendredi 1 janvier 2016

Pack textures and fonts at build time for your LibGDX project

When working with LibGDX and openGL ES we usually need to provide our application with various assets such as :
  • PNG for textures
  • Fonts (whether BitmapFont or FreeTypeFont) for texts
  • Sounds
  • 3D objects
  • etc...
When designing the application, we need to take care of :
  • Reducing the loading time of the assets by reducing the number of required assets
  • Reducing the rendering time of the required assets by packing assets together 
  • Reducing the integration time of the required assets by handling assets generation as part of the automated build process
A way of doing this is to pack all the required PNG for textures into a single TextureAtlas asset. LibGDX provides a TexturePacker utility for that. Some other third party utilities are usefull to generate BitmapFont that can be loaded by the LibGDX runtime.

As an experimented developper, we should expect regular changes among our application design during the development phase which means we should whether re-generate fonts and re-pack textures everytime or work with an application that is not efficient to load and to render (without packed assets and BitmapFont)... As a lazy developper, we might want all the assle of font and texture generation and packing to be handled automagically by the gradle build process.

Here is how we can achieve this...

The big picture

Okay, so let say we want to build an UI that renders a deck of cards using LibGDX :

Card Deck rendered with resources generated at build time

The UI is made of 52 sprites (one for each card) and a BitmapFont to render the label "LibGDX Card Deck"... Everything is laid out with a simple Table. What we want is to be able to change the finest detail with a little effort. For instance :
  • change the red tone used for hearts and diamonds
  • change the shape, the aspect ratio of the card
  • increase the size of the rank
  • decrease the size of the suite
  • change the position of the rank / suit inside the card
  • change the font used for the label

Project layout

When setting up a new LibGDX project you get something like this :

+ rootProject.projectDir
|--+ android
     |--+ assets
     |--+ build

     |--+ res
     |--+ src
     |--+ build.gradle
|--+ core
     |--+ src
     |--+ build.gradle
|--+ desktop
     |--+ src
     |--+ build.gradle
|--+ html

|--+ ios
|--+ resources
|--+ build.gradle

Where the ${rootProject.projectDir}/android/assets directory holds the assets required by the application (whatever the targeted platform : android, desktop, html or ios). So what we are going to do is to create a ${rootProject.projectDir}/resources directory containing the source files used to generate the required assets at build time. Intermediate temporary files will be generated into the ${rootProject.projectDir}/android/build directory.

Design of the cards

To design our card, we are going to use a SVG card pattern wich will define the overall aspect of the card : its shape and the position of the rank and the suit inside the shape. The SVG file will look something like this :


This SVG card pattern pattern use the custom SVGMASK file format defined by the AndroidSvgDrawable library. This allow us to generate all of the 52 combination of card rank x card suit without the need of 52 SVG files...

Then, we need 4 SVG files for suits (one for each card suit) and 13 SVG files for ranks (one for each card rank from 2 to A). Here are the sample files for Heart and King :

  

That's it, let see how we can now generate all of our 52 card textures at build time...

Generating the card textures

To generate the 52 textures, we will use the AndroidSvgDrawable plugin that now integrates better with LibGDX. First, we need to add the plugin dependency to our buildscript classpath in ${rootProject.projectDir}/build.gradle :

Then, we define a custom task in our ${rootProject.projectDir}/desktop/build.gradle file :

This will take the SVG card pattern file we put inside ${rootProject.projectDir}/resources/svg/mask and generate a PNG file for each SVG suit file x SVG rank file we put into ${rootProject.projectDir}/resources/svg/masked :

${rootProject.projectDir}/resources/svg/masked 

${rootProject.projectDir}/android/build/generated/assets

Generating the BitmapFont and the TextureAtlas


In order to generate the BitmapFont and the TextureAtlas at build time, we will rely on the API provided by LibGDX (we must use at least version 1.7.3-SNAPSHOT in order to be able to generate the BitmapFont as mentionned bellow). We should then add the necessary dependencies to our buildscript classpath in ${rootProject.projectDir}/build.gradle :

Most of the time, LibGDX APIs requires the LibGDX runtime to be loaded first, so we must add a specific task in our ${rootProject.projectDir}/desktop/build.gradle file that will load an headless LibGDX runtime for the build purpose :


Generating the BitmapFont

The BitmapFont will be generated from a TrueType font located in the ${rootProject.projectDir}/resources/font directory. A custom task in our ${rootProject.projectDir}/desktop/build.gradle file will generate the BitmapFont for us with the desired parameter :

A BitmapFont is made of 2 files :
  • a .fnt file that will be output in the ${rootProject.projectDir}/android/assets directory directly
  • a .png file that will be output in the ${rootProject.projectDir}/android/build/generated/assets directory because we want to merge it later with the others texture inside our final TextureAtlas...
You can refer to the LibGDX freetype documentation to customize the task to generate the desired font appearence. You can also use a more complexe task to generate BitmapFont of different size, colors, ...

Generating the Atlas

As all the required PNG are now generated inside the ${rootProject.projectDir}/android/build/generated/assets directory, we are now ready to pack them all inside a single TextureAtlas. Once again, we use a custom task in our ${rootProject.projectDir}/desktop/build.gradle file that will do the job for us :

And here is the final skin.png TextureAtlas generated with a default size of 1024 x 1024 that is available in the ${rootProject.projectDir}/android/assets directory along with its skin.atlas descriptor :

skin.png
Once again you can refer to the LibGDX Texture packer documentation for more packing options and a finest control over the generated atlas. Note that LibGDX Texture packer support packing of NinePatch drawable that could be generated at build time with the AndroidSvgDrawable plugin.

Let's build it

In order to chain all of those tasks together, we bind the compileJava task from the java gradle plugin to our custom generateATLAS task :

Here we are, everything is ready, we can just sit and watch gradle work for us :

gradlew desktop:run

:core:compileJava
:core:processResources UP-TO-DATE
:core:classes
:core:jar
:desktop:initHeadlessLibGDX UP-TO-DATE
:desktop:generateFONT
:desktop:generatePNG
:desktop:generateATLAS
assets
Packing.........
Writing 1024x1024: android\assets\skin.png
:desktop:compileJava
:desktop:processResources UP-TO-DATE
:desktop:classes
:desktop:run

BUILD SUCCESSFUL

Total time: 11.758 secs

And if we build it once again, the Gradle magic happens, nothing is re-generated or re-packed because everything is UP-TO-DATE :

gradlew desktop:run

:core:compileJava UP-TO-DATE
:core:processResources UP-TO-DATE
:core:classes UP-TO-DATE
:core:jar UP-TO-DATE
:desktop:initHeadlessLibGDX UP-TO-DATE
:desktop:generateFONT UP-TO-DATE
:desktop:generatePNG UP-TO-DATE
:desktop:generateATLAS UP-TO-DATE
:desktop:compileJava UP-TO-DATE
:desktop:processResources UP-TO-DATE
:desktop:classes UP-TO-DATE
:desktop:run

BUILD SUCCESSFUL

Loading and rendering the assets

Loading the assets requires only a single atlas to be loaded by the application while rendering all the cards and the label will bind a single OpenGL ES texture :

Want to be more optimal ? We can't !

Changing a detail

One more thing ! It's now possible to change the card layout for all our cards by changing only one file. If I modify the SVG card pattern to have the suit in the center of the card and the rank in the upper left corner and the lower right corner as well :

When building the project once again :

gradlew desktop:run

:core:compileJava
:core:processResources UP-TO-DATE
:core:classes
:core:jar
:desktop:initHeadlessLibGDX UP-TO-DATE
:desktop:generateFONT UP-TO-DATE
:desktop:generatePNG
:desktop:generateATLAS
assets
Packing.........
Writing 1024x1024: android\assets\skin.png
:desktop:compileJava
:desktop:processResources UP-TO-DATE
:desktop:classes
:desktop:run

BUILD SUCCESSFUL

Total time: 11.758 secs

Then, the layout has been changed for all of the 52 cards :


Simple isn't it ?

You can find the whole LibGDX project in the sample directory of the AndroisSvgDrawable plugin GitHub project.

samedi 5 décembre 2015

How a rate button can actually improve your mobile app rating

When I decided to redesign my Android Spirit Level this summer, I was wondering wether or not I should add a "Rate" button to invite users to rate the Bubble Level application.


Get it on Google Play

What I was expecting was more feature requests and a better user feadback. I was also concern about how such a button could annoy users... In the long term, would it lead to a better user rating or a lower user rating ? Here is the answer :

Evolution of the app overall rating
Since the update of late august that added the rate button in the app, overall rating of the app increased faster than before... User feedback was also better because of the easy way to provide it when you see something wrong, something missing or something to improove. In the contrary, number of rates per month does not increase as expected :

Rates per month per value and average rating

I'm not sure wether or not this stat reflect rate that get updated by users... But to provide you with more stats, the rate button has a click to rate rate ;-) of 1 generated rate out of 16 clicks... which is quite low but sufficient to increase the overall rating of the app.

mercredi 29 avril 2015

Certificat based client authentication with apache server

This post describe how to create and use a custom certification authority to generate client certificate that will later be used to authenticate users against apache mod_ssl and pass the credential to the underlying server that processes the client requests : Tomcat, JBOSS or anything else... Apache mod_ssl will be configured to use client certificat based strong authentication that only accept requests that comes from clients presenting a certificat signed by a trusted authority.

Creating the certificates

Certification authority

The first step is to generate our own certification authority certificate. This will be done using standard openssl command to generate a RSA key stored under ca.key. This key will be used to generate a self signed certificate under ca.crt :
ca.key
The RSA key of our own authority
ca.crt
The self signed certificate associated with our authority
ca.public.key
The public key of our authority

Server certificate

The server certificate will be used by the server and presented to the client. It will be signed by the certification authority certificate created above. During the certificate signing request, we'll be asked for a Distinguished Name (DN) or Common Name (CN). The value of that field MUST match the ServerName used in the Apache httpd.conf configuration file. The generation of an unprotected key will allow apache to start without the prompt of a passphrase... which might be useful in some cases.

Client certificate

The client certificate is generated like the server certificate. Each client will have its own certificate that uniquely identifies him. It will be signed by the same certification authority. during the creation of the X.509 client certificat, you'll be prompted for Subject informations. Those informations will be used as credentials to authenticate the user on the underlying server that actually processes the request.

Apache server configuration

The Apache server will be configured to only accept requests that comes from clients presenting a client certificate that is signed by our own certification authority. This is done in the httpd.conf by using those directives in the dedicated SSL VirtualHost :

SSLVerifyClient
The require value force the client to provide its own X.509 certificate during the SSL handshake.
SSLVerifyDepth
Specifies the minimum depth that will be scanned by the server to check for trusted certification authority in the client certificate. A value of 0 will only allow self signed certificates. A value of 1 will accept both self signed certificates and certificates signed by an authority known by the server. In our case, we will use a value of 2 that will only accept certificates signed by an authority known by the server.
SSLCACertificateFile
Specifies the trusted certification authorities.
Thus, only the requests signed by our clients will be authorized.

samedi 28 juin 2014

Server provisioning with Vagrant, CoreOS and Docker

In this article, we'll see how easy it is to build a custum Linux image an to deploy it in cloud using modern DevOps tools like Vagrant, CoreOS and Docker and the Amazon Web Services cloud provider.

Setup Vagrant and CoreOS

To build a custom Linux image for Docker we need to run Docker on Linux... ;-) CoreOS is a minimalist Linux distribution that ships with Docker and a few other services. As we want to setup our custom Linux image for Docker locally, let use CoreOS with Vagrant. Vagrant is about provisionning virtual development environment and it's exactly what we need to launch CoreOS quickly on Windows, Mac OS X or Linux. To get all this stuff to work together just follow the Running CoreOS on Vagrant documentation on the CoreOs website.
git clone https://github.com/coreos/coreos-vagrant.git
cd coreos-vagrant
vagrant up
Bringing machine 'core-01' up with 'virtualbox' provider...
==> core-01: Checking if box 'coreos-beta' is up to date...
==> core-01: Clearing any previously set network interfaces...
==> core-01: Preparing network interfaces based on configuration...
    core-01: Adapter 1: nat
    core-01: Adapter 2: hostonly
==> core-01: Forwarding ports...
    core-01: 22 => 2222 (adapter 1)
==> core-01: Running 'pre-boot' VM customizations...
==> core-01: Booting VM...
==> core-01: Waiting for machine to boot. This may take a few minutes...
    core-01: SSH address: 127.0.0.1:2222
    core-01: SSH username: core
    core-01: SSH auth method: private key
    core-01: Warning: Connection timeout. Retrying...
    core-01: Warning: Connection timeout. Retrying...
    core-01: Warning: Connection timeout. Retrying...
    core-01: Warning: Connection timeout. Retrying...
==> core-01: Machine booted and ready!
==> core-01: Setting hostname...
==> core-01: Configuring and enabling network interfaces...
==> core-01: Machine already provisioned. Run `vagrant provision` or use the `--provision`
==> core-01: to force provisioning. Provisioners marked to run always will still run.
You can now SSH to your virtual environnement :
CoreOS (beta)
core@core-01 ~ $

Create a custom Debian image

Once logged into CoreOS, we can see that Docker is available and that no image is available yet :
core@core-01 ~ $ docker images
REPOSITORY          TAG                 IMAGE ID
Let start a Debian Linux with Docker container :
core@core-01 ~ $ docker run -t -i debian:7.4 cat /etc/*-release | grep NAME
PRETTY_NAME="Debian GNU/Linux 7 (wheezy)"
NAME="Debian GNU/Linux"
Now we have the Debian Docker image available localy :
core@core-01 ~ $ docker images
REPOSITORY          TAG                 IMAGE ID
debian              7.4                 e565fbbc6033
As we can see, java is unavailable :
core@core-01 ~ $ docker run -t -i debian:7.4 java -version
2014/06/27 14:01:58 exec: "java": executable file not found in $PATH
So, how can we build a custom debian:7.4 based image with java pre-installed ? Nothing simpler than creating a Dockerfile with the necessary command to install the jdk on a debian distribution :
core@core-01 ~ $ touch DockerFile
core@core-01 ~ $ vi DockerFile
FROM debian:7.4
MAINTAINER Antoine Vianey 

RUN apt-get update
RUN apt-get -f install
RUN export DEBIAN_FRONTEND=noninteractive
RUN apt-get -y install --no-install-recommends openjdk-7-jdk
The docker build command builds the image for us... The -t option allow us to specify the repository + tag that will be associated with the resulting image. Read the Dockerfile reference guide for a full description of what you can do with dockerfile.
core@core-01 ~ $ sudo docker build -t avianey/ojdk7-deb .
If every step runs fine the final image is available under the specified tag. If a step fails, interdmediate steps images are kept to speed up the rebuild after having corrected the failing Dockerfile step.
core@core-01 ~ $ docker images
REPOSITORY          TAG                 IMAGE ID
avianey/ojdk7-deb   latest              54e73307f07e
debian              7.4                 e565fbbc6033
Check that java is installed :
core@core-01 ~ $ docker run -t -i avianey/ojdk7-deb java -version
java version "1.7.0_55"
OpenJDK Runtime Environment (IcedTea 2.4.7) (7u55-2.4.7-1~deb7u1)
OpenJDK 64-Bit Server VM (build 24.51-b03, mixed mode)
Everything is fine, we can tag our custom image :
core@core-01 ~ $ sudo docker tag 54e73307f07e avianey/ojdk7-deb:v1
core@core-01 ~ $ docker images
REPOSITORY          TAG                 IMAGE ID
avianey/ojdk7-deb   latest              54e73307f07e
avianey/ojdk7-deb   v1                  54e73307f07e
debian              7.4                 e565fbbc6033

Use the image in the cloud

Now that we have our custom image setup, we need to push it in the Docker Hub or a private Docker repository to use it from the cloud :
core@core-01 ~ $ sudo docker push avianey/ojdk7-deb
The push refers to a repository [avianey/ojdk7-deb] (len: 2)
Sending image list
...
Pushing repository avianey/ojdk7-deb (2 tags)
...
Pushing tag for rev [54e73307f07e] on {https://registry-1.docker.io/v1/repositories/avianey/ojdk7-deb/tags/latest}
Pushing tag for rev [54e73307f07e] on {https://registry-1.docker.io/v1/repositories/avianey/ojdk7-deb/tags/v1}
Everyone can now start a Docker container running the avianey/ojdk7-deb:v1 image. That what we are going to do with a CoreOS Amazon Machine Image :
Using username "core".
Authenticating with public key "imported-openssh-key"
CoreOS (beta)
core@ip-172-31-25-84 ~ $ docker run -t -i avianey/ojdk7-deb:v1 java -version
Unable to find image 'avianey/ojdk7-deb:v1' locally
Pulling repository avianey/ojdk7-deb
54e73307f07e: Download complete
511136ea3c5a: Download complete
405cce5cd17d: Download complete
e565fbbc6033: Download complete
782079a3e1cf: Download complete
3be917c2a827: Download complete
11311a0d3731: Download complete
b4754115da81: Download complete
java version "1.7.0_55"
OpenJDK Runtime Environment (IcedTea 2.4.7) (7u55-2.4.7-1~deb7u1)
OpenJDK 64-Bit Server VM (build 24.51-b03, mixed mode)
That's it, enjoy !

mercredi 19 février 2014

JSP, JS, CSS hot-deployment with Maven in Eclipse WTP

Eclipse WTP use Adtaper to provide hot deploy fonctionnalities with JEE application servers or web containers. Depending on the configuration, the adapter may reload the whole .war or .ear and take several seconds when not minutes to do so.

While WTP adatpers hot deployment is a time-saver as it rely on the Eclipse incremental compiler and does not pass through all the maven build phase to package the final .war or .ear, this is not the good choice when you work with resources like .jsp, .js, .css, .html, .tag, ...

For those static resources that don't need the whole application context to be reloaded a faster way is to copy themn automatically to the application server work directory. Some benefits are :
  • save time : no .war or .ear undeploy/redeploy
  • use [F5] to reload your resource instantly
    • the session is kept
    • the context is alive (jBPM, Spring web flow, DROOLS)
  • no more OutOfMemory or PermGenSpace when redeploying...
Next lines will show you how to set it up under JonAS. This HowTo is based on JonAS 5.2.4, Sun JKD 1.7, Maven 3.1.1, Windows 7 and Eclipse Juno. This should work on other OS as long as you go with Maven 3 and might be ported to other application servers...

WTP Adapter configuration

First of all, you need to tell JonAS WTP adatper not to publish automatically. The option is available when you double-click on the application server icons in the Eclipse "Servers" view :


Choose "Never publish automatically"... You'll then need to undeploy/deploy manually (remove and publish from the Eclipse "servers" view) when you want a code change to be taken in account or setup Cargo and configure the cargo:deploy goal to publish changes for you.

JonAS configuration

By default, JonAS will create a new directory each time an EAR or WAR is deployed. What we want is JonAS to use the same directory each time it deploys the same file, so we need to set the jonas.development property to false in the jonas.properties configuration file :

#  Set to true in order to execute the JOnAS Server in development mode.
#
#  WAR archive deployment case in development mode (for single or EAR packaged WARs):
#  Each modified WAR archive will be unpacked in the working directory of the 
#  JOnAS Server in a different folder to avoid file locks. 
#  This is especially useful in a Windows environment.
jonas.development    false
JonAS will then use a directory named against Eclipse project name.

Maven settings.xml configuration

As of Maven 3.0, profiles in the POM can also be activated based on properties from active profiles from the settings.xml.
As we want this trick to be a per user configuration we are going to rely on a property defined in the user's settings.xml to activate the static resource hot deployment :
<profile>
    <id>project-static-resources-hot-deploy</id>
    <activation>
        <activeByDefault>true</activeByDefault>
        <file>
            <exists>D:\PROJECT\jonas-full-5.2.4</exists>
        </file>
    </activation>
    <properties>
        <project.static.resources.hot.deploy.path>D:\PROJECT\jonas-full-5.2.4\work\webapps\jonas\single\{directory}</project.static.resources.hot.deploy.path>
    </properties>
</profile>
The {directory} part of the property must point to the WTP adapter deploy path for the desired Eclipse project.

Project configuration

Then we just need to add a profile activated based on the property defined in the user settings.xml that will trigger the use of the maven-resources-plugin to copy selected static resources to the application deployment path under JonAS. The copy is executed each time a static resource is saved in Eclipse and rely on the Maven Integration (m2e) for Eclipse.
<profile>
    <id>static-resources-hot-deploy</id>
    <activation>
        <property>
            <name>project.static.resources.hot.deploy.path</name>
        </property>
    </activation>
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-resources-plugin</artifactId>
                <version>2.6</version>
                <executions>
                    <execution>
                        <id>static-resources-hot-deploy</id>
                        <phase>validate</phase>
                        <goals>
                            <goal>copy-resources</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${project.static.resources.hot.deploy.path}</outputDirectory>
                            <resources>
                                <resource>
                                    <directory>src/main/webapp</directory>
                                    <!-- if you use filtering in your build use true -->
                                    <filtering>false</filtering>
                                    <!-- whatever extension you want to copy -->
                                    <includes>
                                        <include>**/*.css</include>
                                        <include>**/*.jsp</include>
                                        <include>**/*.js</include>
                                        <include>**/*.tag</include>
                                    </includes>
                                </resource>
                            </resources>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</profile>

Troubleshooting

Sometimes, Eclipse ignore user settings.xml and does not activate project profiles based on settings.xml properties. As a workaround, you can :
  1. verify that Eclipse points to the correct user settings.xml in the following Eclipse menu Settings -> Maven -> Installations (you may need to restart Eclipse after changing this setting).
  2. add the profile that set the property directly in the project pom. 

samedi 9 mars 2013

Generate Android image resources from SVG with Maven

I recently wrote the AndroidGenDrawable Maven plugin for Android that allow you to generate density specific PNG drawable from SVG (scalable vector graphics) at build time for your Android projects. Here is a brief presentation.

Fragmentation

Fragmentation is an actual problem when speaking of Android development. Specially when programmers need to maintain density specific raster graphics image (bitmaps) to target all of the possible Android device screens. The very first example is the Launcher icon of an Android application that should be resized depending on the generalized screen density (see link) :

ldpi generalized density
mdpi generalized density
hdpi generalized density
xhdpi generalized density

androidgendrawable-maven-plugin

The androidgendrawable maven plugin allow you to work on a unique SVG version of your assets and to generate the density specific PNG versions required by the Android runtime at build time. The SVG artwork are automatically scaled and transcoded to PNG for you during the maven build. The plugin rely on apache batik to transcode the SVG to PNG. You just have to add the plugin declaration and its configuration to your pom.xml :
<plugin>
 <groupId>fr.avianey.modjo</groupId>
 <artifactId>androidgendrawable-maven-plugin</artifactId>
 <version>1.0-SNAPSHOT</version>
 <configuration>
  <from>${project.basedir}/svg</from>
  <to>${project.basedir}/res</to>
  <rename>
   <level>icon</level>
  </rename>
  <createMissingDirectories>true</createMissingDirectories>
  <targetedDensities>
   <density>ldpi</density>
   <density>mdpi</density>
   <density>hdpi</density>
   <density>xhdpi</density>
  </targetedDensities>
  <fallbackDensity>mdpi</fallbackDensity>
  <skipNoDpi>true</skipNoDpi>
 </configuration>
 <executions>
  <execution>
   <phase>initialize</phase>
   <goals>
    <goal>gen</goal>
   </goals>
  </execution>
 </executions>
<plugin>
Required resources are then generated during the initialize phase of the Maven build :
[INFO] ------------------------------------------------------------------------
[INFO] Building level 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- androidgendrawable-maven-plugin:1.0-SNAPSHOT:gen (default) @ level ---
[INFO] Transcoding level-xhdpi.svg to drawable
[INFO] Transcoding level-xhdpi.svg to drawable-hdpi
[INFO] Transcoding level-xhdpi.svg to drawable-ldpi
[INFO] Transcoding level-xhdpi.svg to drawable-xhdpi
You can fork the plugin on github here and read the documentation on the associated github page here.

mardi 5 février 2013

The Facebook Android API v3.0 on Maven

For those of you that might be interrested, I just created a Maven repository that hosts my Maven port of the Facebook Android API in its latest v3.0 version. You just need to reference the GitHub pages hosted repository in you Android Maven project pom.xml :
<repositories>  
  ...  
  <repository>  
    <id>The mavenized Facebook Android API</id>  
    <url>http://avianey.github.com/facebook-api-android-maven/</url>  
  </repository>  
</repositories>
...and to import the facebook-android-api as a dependency :
<dependencies>
  ...
  <dependency>
    <groupId>com.github.avianey</groupId>
    <artifactId>facebook-android-api</artifactId>
    <version>3.0.0</version>
    <type>apklib</type>
  </dependency>
</dependencies>
I picked the groupId to avoid conflict with other ports one might find on the Internet. As usual, you can fork this mavenized Facebook Android API on GitHub.

samedi 15 décembre 2012

Run background process for your Maven integration tests

The Maven Failsaif plugin makes it very simple to run integration test written with JUnit or TestNG. This example shows how to use the Maven Failsafe Plugin to run Integration Tests that properly starts and stop a Jetty server during both the pre-integration-test phase and the post-integration-test phase. This solution can be easyly derivated to start and stop any background process that is well integrated as a Maven plugin :
<plugin>
    <groupId>${plugin.groupId}</groupId>
    <artifactId>${plugin.artifactId}</artifactId>
    <version>${plugin.version}</version>
    <configuration>
        <anything>...</anything>
    </configuration>
    <executions>
        <execution>
            <id>do-it-before</id>
            <phase>pre-integration-test</phase>
            <goals>
                <goal>${plugin.start.goal}</goal>
            </goals>
            <configuration>
                <something>...</something>
            </configuration>
        </execution>
        <execution>
            <id>do-it-after</id>
            <phase>post-integration-test</phase>
            <goals>
                <goal>${plugin.stop.goal}</goal>
            </goals>
            <configuration>
                <whatever>...</whatever>
            </configuration>
        </execution>
    </executions>
</plugin>
Sometimes, there is no plugin or maven integration that you can use to start and stop the background process(es) required by your intergation test case to run. You can start and stop the desired process(es) manually but let see how to do this properly with Maven.

Maven exec plugin

The Maven exec plugin provides 2 goals to help execute system and Java programs. However, the programs execution are blocking. It is thus impossible to run tests during the intergation-test phase with running programs started during the pre-integration-test phase. Hopefully, the Maven antrun plugin will help us...

Maven antrun plugin

The Maven antrun plugin provides the ability to run Ant tasks from within Maven. It can do anything you can put into an ant build.xml script. In particular, it is possible to use the Ant exec task with all its parameters. The solution to our problem is the spawn parameter of the exec task that will run the specified executable asynchronously in its own process :
<exec executable="command-to-run"
      dir="base/dir/for/the/command"
      spawn="true"> <!-- run it asynchronously and in background baby -->
    <arg value="arg"/>
    <arg value="arg"/>
    ...
    <arg value="arg"/>
</exec>
Okay but now, we want to start third parties programs with the Maven antrun plugin during the pre-integration-test phase, keeping them running during the integration-test phase and to shut them down during the post-integration-test phase. Assuming we have plateform dependent scripts to start and stop Zookeeper, Kafka or anything else... our pom.xml will look like this :
<plugin>
    <artifactId>maven-antrun-plugin</artifactId>
    <version>1.6</version>
    <executions>
        <execution>
            <id>start-third-parties</id>
            <phase>pre-integration-test</phase>
            <configuration>
                <target>
                    <exec executable="${run.command}"
                          dir="${basedir}/../scripts"
                          spawn="true">
                        <arg value="${run.command.additionnal.arg}"/>
                        <arg value="${basedir}/../scripts/${zookeeper.start.script}"/>
                    </exec>
                    <exec executable="${run.command}"
                          dir="${basedir}/../scripts"
                          spawn="true">
                        <arg value="${run.command.additionnal.arg}"/>
                        <arg value="${basedir}/../scripts/${kafka.start.script}"/>
                    </exec>
                </target>
            </configuration>
            <goals>
                <goal>run</goal>
            </goals>
        </execution>
        <execution>
            <id>stop-third-parties</id>
            <phase>post-integration-test</phase>
            <configuration>
                <target>
                    <exec executable="${run.command}"
                          dir="${basedir}/../scripts"
                          spawn="false">
                        <arg value="${run.command.additionnal.arg}"/>
                        <arg value="${basedir}/../scripts/${zookeeper.stop.script}"/>
                    </exec>
                    <exec executable="${run.command}"
                          dir="${basedir}/../scripts"
                          spawn="false">
                        <arg value="${run.command.additionnal.arg}"/>
                        <arg value="${basedir}/../scripts/${kafka.stop.script}"/>
                    </exec>
                </target>
            </configuration>
            <goals>
                <goal>run</goal>
            </goals>
       </execution>
    </executions>
</plugin>
There is no need to spawn the shutdown of our third parties programs, but it's possible too...

Okay but what if I want to use both Linux and Windows ?

No problem ! Maven profiles are here to help you. You just have to define two profiles wich <activation> relies on the os family like this :
<profile>
    <id>windows-properties</id>
    <activation>
        <os>
          <family>Windows</family>
        </os>
    </activation>
    <properties>
        <run.command>cmd</run.command>
        <run.command.additionnal.arg>/c</run.command.additionnal.arg>
        <zookeeper.start.script>start-zookeeper.bat</zookeeper.start.script>
        <zookeeper.stop.script>stop-zookeeper.bat</zookeeper.stop.script>
        <kafka.start.script>start-kafka.bat</kafka.start.script>
        <kafka.stop.script>stop-kafka.bat</kafka.stop.script>
    </properties>
</profile>
<profile>
    <id>linux-properties</id>
    <activation>
        <os>
          <family>unix</family>
        </os>
    </activation>
    <properties>
        <run.command>sh</run.command>
        <run.command.additionnal.arg></run.command.additionnal.arg>
        <zookeeper.start.script>start-zookeeper.sh</zookeeper.start.script>
        <zookeeper.stop.script>stop-zookeeper.sh</zookeeper.stop.script>
        <kafka.start.script>start-kafka.sh</kafka.start.script>
        <kafka.stop.script>stop-kafka.sh</kafka.stop.script>
    </properties>
</profile>
Et voila, the start and stop scripts properties will be set correctly depending on the runtime OS.

Okay but I don't want to run whole intergation tests all the time ?

This time again, you can use a Maven profile but without <activation>. Plugins will be activated only if you specify the profile inside the maven command :
mvn clean install -P integration-tests
<profiles>
    <profile>
        <id>integration-tests</id>
        <build>
            <plugins>
                <plugin>
                    <artifactId>maven-failsafe-plugin</artifactId>
                    <version>2.12.2</version>
                    <executions>
                        <execution>
                            <goals>
                                <goal>integration-test</goal>
                                <goal>verify</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
                <plugin>
                    <artifactId>maven-antrun-plugin</artifactId>
                    <version>1.6</version>
                    <executions>
                        <execution>
                            <id>start-third-parties</id>
                            <phase>pre-integration-test</phase>
                            <configuration>
                                <target>
                                    <!-- ANT stuff -->
                                </target>
                            </configuration>
                            <goals>
                                <goal>run</goal>
                            </goals>
                        </execution>
                        <execution>
                            <id>stop-third-parties</id>
                            <phase>post-integration-test</phase>
                            <configuration>
                                <target>
                                    <!-- ANT stuff -->
                                </target>
                            </configuration>
                            <goals>
                                <goal>run</goal>
                            </goals>
                       </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    </profile>
</profiles>

About the stop scripts

Stop scripts are sometimes not easy to write... but there is always a way to kill a process ! The examples bellow are made for Kafka (replace kafka.Kafka by anything that can identify the process you started) :

on Linux

ps ax | grep -i 'kafka.Kafka' | grep -v grep | awk '{print $1}' | xargs kill -SIGTERM
You may have to pay to run it on Mac OS X indeed...

on Windows

wmic process where (commandline like "%%kafka.Kafka%%" and not name="wmic.exe") delete
You only need to double '%' if you want the command to be executed within a .bat file.

Conclusion

This solution might work for a lot of third parties appliations that you might want to run in background in order to pass integration tests on your whole application layers :
  • run a queue like Kafka or ZeroMQ that doesn't provide Maven integration yet
  • run a database like MySQL, Cassandra (Maven plugin available btw...) or HBase
  • run an independent instance of anything : Memcached, ElasticSearch or Solar for example
Tell me if you use it for something else ;-)

jeudi 1 novembre 2012

Un simulateur de crédit à emporter

Aujourd'hui je vous fait partager un petit développement personnel effectué afin de tester les possibilités offertes par le framework jQuery mobile. Il s'agit d'un petit utilitaire permettant de simuler un emprunt quelconque (prêt immobilier, crédit à la consommation, ...) en précisant le montant et la durée d'emprunt, le taux d'intérêt et d'éventuelles charges additionnelles (prîmes d'assurances ou autres).

Le résultat est présenté de manière synthétique sous forme de popup avec le montant de la mensualité, le total des intérêts, le taux effectif global et le coût total du crédit. Une vue détaillée par mensualité permet de visualiser le détail des intérêts, du montant remboursé et du montant restant à rembourser. Voici le résultat :


Vous pouvez également faire le test sur votre smartphone ou tablette

dimanche 23 septembre 2012

Mahout Taste walkthrough (initiation par l'exemple)

Ce post à pour objectif de défricher le fonctionnement du moteur de recommandation d'Apache Mahout Taste en étudiant les projets d’exemples fournis avec la version 0.7 d'Apache Mahout (L'API est susceptible d'évoluer en profondeur tant que la MileStone 1 n'est pas atteinte).
<dependency>
    <groupId>org.apache.mahout</groupId>
    <artifactId>mahout-core</artifactId>
    <version>0.7</version>
</dependency>

<dependency>
    <groupId>org.apache.mahout</groupId>
    <artifactId>mahout-examples</artifactId>
    <version>0.7</version>
</dependency>

Concepts

Mahout Taste permet de fournir des recommandation d'Items à des User. Users et Items étant tous deux représentés par des entiers. Afin de fournir des recommandations, le framework s'appuie sur un DataModel constitué de préférences. Une préférence est un nombre flottant représentant une affinité entre un User et un Item.


Le moteur de recommandation repose sur l'interface Recommender. Les implémentations de cette interface permettent de :
  • Récupérer une liste d'Items recommandées pour un User
  • D'estimer l'affinité entre un User et un Item
  • De modifier des préférences à la volée

Un exemple simple : ItemAverageRecommender

ItemAverageRecommender est une implémentation de l'interface Recommender qui estime l'affinité potentielle entre un User et un Item comme la moyenne des affinités des User ayant exprimés une préférence pour pour cet Item. Elle permet ainsi d'obtenir des recommandations indiférenciées par User.

Le BookCrossingRecommender

Un peu plus intéressant, le BookCrossingRecommender est un exemple concret de Recommender qui s'appuie sur un jeu de données réel :
public final class BookCrossingRecommender implements Recommender {

    private final Recommender recommender;

    public BookCrossingRecommender(DataModel bcModel) throws TasteException {
        UserSimilarity similarity = new CachingUserSimilarity(
                new EuclideanDistanceSimilarity(bcModel), bcModel);
        UserNeighborhood neighborhood = new NearestNUserNeighborhood(10, 0.2, similarity, bcModel, 0.2);
        recommender = new GenericUserBasedRecommender(bcModel, neighborhood, similarity);
    }
}
En regardant de plus près le code de ce BookCrossingRecommender on remarque la présence des concepts suivants :
UserSimilarity
qui représente la ressemblance entre deux User.
UserNeighborhood
qui représente le voisinage d'un User; les voisins étant déterminés en fonction de leurs ressemblance.
Des implémentations diverses de ces deux concepts sont disponibles par défaut dans Mahout Taste. Le BookCrossingRecommender utilise la classe EuclideanDistanceSimilarity comme implémentation de la ressemblance. Celle-ci permet de classer les Users selon la distance euclidienne entre leurs affinités communes (chaque Item pour lequel ils ont chacun exprimé une préférence étant une dimension).

Une fois la notion de ressemblance posée, il est alors possible de définir le voisinage d'un User. Dans le cas du BookCrossingRecommender, le voisinage d'un User est constitué des 10 Users qui lui sont le plus ressemblant. La classe NearestNUserNeighborhood permet de fixer un seuil minimal en dessous duquel la ressemblance entre deux Users leur interdit d'être voisins.

Enfin, le GenericUserBasedRecommender est utilisé afin de proposer des recommandations à un User en considérant les Items ayant l'affinité moyenne la plus grande parmi son voisinage...

Comment choisir (construire) une bonne implémentation

Si Taste propose une API simple permettant de monter rapidement un système de recommandation sur un jeux de données quasi quelconque, comment savoir si la notion de ressemblance retenue est la bonne, si le voisinage n'a pas été choisi trop vaste ou trop restreint et si la méthode de sélection des recommandations est pertinente ?

Quelques requêtes sur Google permettent de se rendre compte que de nombreuses recherches plus ou moins compréhensibles (plutôt moins que plus) ont été menées sur le sujet.

Pour le commun des mortels, Mahout Taste est livré avec un RecommenderEvaluator sui, comme son nom l'indique, permet d'estimer la qualité d'un Recommender. A partir d'un DataModel, le RecommenderEvaluator va construire le Recommender à évaluer en utilisant une partie du jeu de données : le "training percentage". Il va ensuite évaluer le Recommender sur un sous ensemble du jeu de données appelé "evaluation percentage" et retourner une note. Plus la note retournée est basse, plus le Recommender a proposé des recommandations proches des préférences réelles de l'"evaluation percentage". Une note de 0 indiquant des résultats identiques entre les recommandations du Recommender et l'"evaluation percentage".

vendredi 13 avril 2012

Introducing jQuery dice plugin

jQuery dice plugin is a jQuery plugin that ease the inclusion of dice inside your jQuery-based website. It is based on CSS3 and Javascript and allow you to draw 2D dice of any size without using any image.


dice build using jQuery dice plugin

How to use

Include both the css and the javascript plugin into your html page :


You can then turn any <DIV> into a die by calling the dice function :
$("#die").dice({
    size: 100, // in pixels
    val: 3, // 1, 2, 3, 4, 5, 6
    rotation: 0 // O to 359 deg
});
The dice function accepts three options :
size :
The dimensions of the die in pixels (height and width are equals)
default : 100px
val :
The face of the die (1, 2, 3, 4, 5 or 6)
default : random
rotation :
The rotation of the die in degrees. The anchor point is the middle of the die.
default : 0
Test it with the jQuery mobile demo page bellow :



Only the following browser are supported yet :
  • Firefox
  • Chrome (including Android 2.3+)
  • Safari (including iPhone and iPad)
Fork me on GitHub