Custom lego Transformers, built during holidays

Lego fun !

Spring is (almost) here again… Right time for a new post !

Yesterday I had to transfer a big file (8Gb) from one machine to another one.

As always : a simple scp command… But it failed at 94% : ‘stalled’ (probably because of my bad network quality).

I tried again : and it failed again.

I had a look at Stackoverflow, as everyone does… And after reading a few pages I had the solution : using rsync.

Here it the command:

rsync --partial --progress --rsh=ssh src-file host:target-file

And you know what ? It’s faster than using scp, and safer as well because in case of network failure, you only have to launch the command again to resume.

Writing a simple command line tool in Java can be a bit boring…

Especially when an external library is needed: you always end up with your code (.java), some libraries (.jar) and probably a build script (ant, maven, gradle…).

That is a lot for a ‘simple command line’!

Hopefully, Groovy is here to help your script fit in one single file and then bringing Ghost4j features to the command line becomes fairly easy.

Here is a script to analyze a PDF file:

// A simple Groovy script using Ghost4J to perform PDF document analyzing (page count, font report, ink coverage)
// The script expects a single argument: a PDF filename or URL
@GrabResolver(name='ghost4j', root='')
@Grab(group='org.ghost4j', module='ghost4j', version='0.5.1-SNAPSHOT')
import org.ghost4j.analyzer.AnalysisItem
import org.ghost4j.analyzer.FontAnalyzer
import org.ghost4j.document.PDFDocument
import org.ghost4j.analyzer.InkAnalyzer

// Parse arguments
def filename
if (this.args.length < 1) {
    println 'Error: no file name or URL provided'
} else {
    filename = args[0]

// Open or download PDF
def file
if (filename.startsWith('http:')) {
    file = new File('tmp.pdf') 
    file << new URL(filename).openStream()
} else {
    file = new File(filename)

// Load document
def document = new PDFDocument()

// Print page count
println "----------------- PAGE COUNT ----------------"
println document.getPageCount()

// Analyze fonts and print results
println "-------------------- FONTS ------------------"
def fontAnalyzer = new FontAnalyzer()
fontAnalyzer.analyze(document).each {it ->

// Analyze ink coverage and print results
println "--------------- INK COVERAGE ----------------"
def inkAnalyzer = new InkAnalyzer()
inkAnalyzer.analyze(document).each {it ->

// Delete temp.pdf
if (filename.startsWith('http:')) {

The script can be found as a Gist here.

The following command:

groovy pdfreport.groovy myfile.pdf

Will output something like this:

----------------- PAGE COUNT ----------------
-------------------- FONTS ------------------
Helvetica-Oblique: EMBEDDED SUB_SET
Helvetica-Bold: EMBEDDED SUB_SET
--------------- INK COVERAGE ----------------
Page 1 C: 0.03081 M: 0.04687 Y: 0.04687 K: 0.06261
Page 2 C: 0.08096 M: 0.08096 Y: 0.07645 K: 0.08151

Screensaver #IRL


After months of silence: I’m back !

This time, I would like to talk about how to get involved in open source projects (why and how) based on my own experience.

Why doing open source ?

If you read this blog, you are probably a developer or someone close to the IT business.

So you probably asked this question to yourself already… And maybe did not find a satisfying answer.

As a matter of fact: you will probably never earn money (enough to quit your job at least) with open source, and you don’t really feel like ‘working at home’ during your evenings.

Those are good reasons to not get you involved into open source… But have you ever think about reasons that will actually get you involved ?

I found several myself:

  1. Improve your skills and become better at work: an open source project is a big sandbox where you can do anything you want for fun. and that is the best way to learn.
  2. Give yourself a personal goal: doing something, even if it is quite modest, will help you realize yourself.
  3. Meet interesting people from around the world.

A first try

Well… Let’s say you decided to dive into the big open source pool: what to do next ?

Actually it really depends on your skills. Maybe you have a very interesting an unique skill or knowledge and know how to share it…

But most of the time: you need to find yourself a simple goal as a ‘warm up’.

You can, for example, start by contributing to an existing project. This is a common situation: you use a wonderful open source library but there is just this little feature missing: why not adding it ?

If you prefer to start a project from scratch: that is OK too! But you need to find a valuable idea. Not necessary something unique, wonderful and that everyone will love but something that might get a little interest (feedback is really important to help you keep going!) so avoid writing another web application framework for instance: it’s long, there are already many of them and many are backed by big companies (and you can’t compete with tem).

I’m talking about a web framework because I did the mistake myself: when I decided to get involved into open source I tried to start a web framework on top of the Spring framework: that was a stupid idea and I stopped it all as soon as I realized my mistake.

As a second try, however, I found something that was reachable: I got the idea of writing a small Java library wrapping the native Ghostscript C API. The idea came to me as I read an article about JNA (and I already had a background on printing and Postscript). It took me only a couple of weeks to release the first version. This project is named Ghost4J and still maintained :)

To sum up:

  1. You can start by a small contribution to an existing project.
  2. If you start a project from scratch: make sure your idea is valuable and will help the community.
  3. Choose a goal you can reach soon to keep you motivated.

When to work

Good things take time…

You will need several hours of work before releasing a first basic version of your project: knowing when and how to work is important.

If you don’t set some limits, you might end up spending all your free time working on your idea, or on the contrary: you will never find enough motivation to work on it.

That is why you should consider your ‘open source time’ as a classic scheduled week day activity like fitness, jogging, scrabble club or whatever…

I think 2 evenings per week is good enough, more than 3 is probably too much.

However if you decide to work on your project, you need to work at least 3 hours on it to be efficient. If less: you will not have the time to really get into it, if more: you will get exhausted soon.

When to work? I like working from 10pm to 1am, but it’s up to you.

To sum up:

  1. Scheduling your working evenings is important.
  2. Working 2 evenings per week is enough, more than 3: too much.
  3. Work at least 3 hours in a row to be efficient.

Spending time on ‘valuable’ things

When working on a personal open source project, optimizing each minute is important, so you need to stay focused on what is ‘valuable’.

What is valuable:

  • New features and bug fixes
  • Communication (with the community): forums, documentation…

What is not valuable:

  • The rest

A good example of ‘not valuable’ task is the action of publishing or uploading items to the repository: it is important, but it takes time and is repetitive.

To avoid such a loss of time consider automating the most this kind of tasks: use Continuous Integration, tools and plugins as much as possible to make your life easier and save time.

Also working on new features is important: but don’t get lost! You need to set priorities, and with open source, priorities are often led by your community.

If you spend time on the most requested features or fixes: you will get a good feedback. That will give you motivation and make your community grow.

Sometimes people ask me to add some features on my projects, but those features are often valuable to them only: of course I set their priority to low, but even better: I encourage them to add the requested features themselves.

To sum up:

  1. Stay focus on valuable tasks.
  2. Automate repetitive tasks.
  3. Let the community drive feature priorities.
  4. Try to implcate your users into the project.

I hope you enjoyed this post !

Chocolate !

Moving Ghost4J to GitHub gave me motivation… So, I decided to go a step further with Ghost4J !

And some weeks later: here comes Ghost4J 0.5.0 !

So what’s new ?

Many things ! Here is the full list (release notes):

  • Added antialiasing property on SimpleRenderer.
  • Added extract method on Document to allow extraction of a range of pages to a new document.
  • Added append method on Document to allow appending a document to the current one (may not be working in all cases with PostScript file, when document use different resources).
  • Added explode method on Document to build one new document for each page of the current document.
  • Upgraded xmlgraphics-commons to 1.4.
  • Upgraded jna to 3.3.0.
  • Added PaperSize class to manipulate paper sizes.
  • Added device property to PSConverter, used to determine the Ghostscript device used for conversion. By default ps2write is now used if available in Ghostscript (see, thanks BXCY).
  • Added SafeAppenderModifier, a modifier (new kind of component) able to append a document (any kind) to another (any kind) in a safe way (compared with the append method on Document class, that may not work when documents resources are different).
  • Added InkAnalyzer, an analyzer in charge of retrieving CMYK ink coverage (in %) of each pages of a document.
  • Added examples in org.ghost4j.example package.

What are the benefits ?

SimpleRender is now rendering nice antialiased images.

PSConverter is now more reliable as it uses Ghostscript ps2write device (when available) to generate PostScript files.

PS and PDF documents can now be mixed / splited thanks to the new extract, append and explode Document methods. SafeAppenderModifier can also be used to do the job (when PS files come from a different spool).

And last but not least : the InkAnalyzer can tell you how much of Cyan Magenta Yellow or Black (CMYK) ink will be used to print each page of a document.

Like that :

// load PS document
PSDocument document = new PSDocument();
document.load(new File(""));

// create analyzer
InkAnalyzer analyzer = new InkAnalyzer();

// analyze
List<AnalysisItem> coverageData = analyzer.analyze(document);

// print result
for (AnalysisItem analysisItem : coverageData) {

Find it interesting ? Then checkout more examples on the Ghost4J website at

And don’t forget you can contribute by forking the project on GitHub, here:

Happy new year to everyone !

To start 2013, I decided to move Ghost4J from sourceforge to GitHub !


Why moving ?

When I started Ghost4J, 4 years ago I chose to host it on sourceforge : I already knew the platform and it felt confortable for me: SVN, FTP access for the web site… Classical tools.

At the time I didn’t know GitHub (and not even git - the scm tool) at all, and even when I got to know it, it took me some time to understand the benefits of such a platform.

Then, last month I read a very interesting article (in french : A celui qui a fait Twitter Bootstrap), in few words : how a successful open source project can swallow your life and some things you should never do with open source.

Of course, Ghost4J is not Twitter Bootstrap (and will never be), but here are some lessons this article taught (or reminded) me:

  • The open source project you started can’t (and must not) stay yours forever: if you decide to give it to a community, then the community must own the project at some point. As the founder, your role is to invite and help people to contribute. The sooner you do it, the most successful the project will become.
  • An open source project should not be centralized: of course at the beginning you do everything by yourself, but if someone is interested in helping you: you must accept it and give him the ‘keys’ to your project (access to tools, share the roadmap with him…).

Why GitHub ?

After that I realized that GitHub was the tool that could help me : with sourceforge I had to copy/paste or patch the code contributed by users by myself as GitHub provides the fork / pull request mechanism, probably the best way to integrate contributions.

GitHub is a social network… For coders, and this is very important : it is easier to get in touch with other developers, and the stars / forks give you a good mesure of involvement of others around your project, as sourceforge only gives you the number of binaries downloaded per day and a user rating mechanism that nobody uses anyway…

GitHub has also better (more recent) tools than sourceforge : git, issue tracking, general site looking (much clearer than sourceforge, even if it got better last year).

So what’s new ?

The web site for the project is now (yes: I bought the domain!) and it is managed by the gh-pages feature of GitHub (and can be re-published with a single maven command !).

The site is still generated by the maven site plugin, but I decided to update the documentation and it uses the fluido skin now (form a Bootstrapped look !).

The GitHub page for the project is

I even set up a repository for maven artifact releases and snapshots (check the web site out for instructions).

Hi everyone,

Some weeks ago I decided to have a closer look to Sencha Touch.

The framework is quite complete as it exposes a full MVC in Javascript (where jQuery Mobile handles only rendering out of the box).

With Sencha Touch every piece of code is made of Javascript : models, controllers and even views.

However, as complete as it is, the framework does not provide any way to localize strings. By googling around it is possible to find different solutions, but if you are used to Java .properties for localization, a single file is enough.

Here is a solution I came up with…

A simple I18n utility class

That is the code :

Ext.define('MyApp.util.I18n', {
    singleton : true,

    config : {
    	defaultLanguage : 'en',
        translations : {
        	'en' : {
        		'signIn' : 'Sign in',
        		'name' : 'Name',
        		'hello' : 'Hello {0} !',
                        'enOnly' : 'English only !'
        	'fr' : {
        		'signIn' : 'Identifiez-vous',
                        'name' : 'Nom',
                        'hello' : 'Bonjour {0} !'

    constructor: function(config) {
    translate: function (key) {
    	// Get browser language
    	var browserLanguage = window.navigator.userLanguage || window.navigator.language;
    	// Is it defined ? if not : use default
    	var language = this.getTranslations()[browserLanguage] === undefined ? this.getDefaultLanguage() : browserLanguage;
    	// Translate
    	var translation = "[" + key + "]";
    	if (this.getTranslations()[language][key] === undefined) {
    		// Key not found in language : tries default one
    		if (this.getTranslations()[this.getDefaultLanguage()][key] !== undefined) {
    			translation = this.getTranslations()[this.getDefaultLanguage()][key];
    	} else {
    		// Key found
    		translation = this.getTranslations()[language][key];
    	// If there is more than one argument : format string
    	if (arguments.length > 1) {
    	    var tokenCount = arguments.length - 2;
            for( var token = 0; token <= tokenCount; token++ )
    	    	translation = translation.replace( new RegExp( "\\{" + token + "\\}", "gi" ), arguments[ token + 1 ] );
    	return translation;

The code above is a simple Ext class. It defines a default language defaultLanguage and a map of translations translations by language code and key / string.

It also provides a translation method that is in charge of retrieving the string matching the provided key. Note that the method also supports arguments in strings.


In order to use the class, just add it to your project in the app/util with the name I18n.

Then declare it in the requires of your app.js.

Now you should be able to call it from anywhere like this :



Given the data used in the class above, here is how the translation behaves if browser locale is set to french (fr):

// Gives 'Identifiez-vous'

MyApp.util.I18n.translate('hello', 'Gilles'); 
// Gives 'Bonjour Gilles !'

// Gives 'English only !' (defaults to en, as the key is not defined for fr)

// Gives '[missing]' (the key is never defined, so it is returned into brackets)

Hope this will help !