14 janvier 2012

ClassGrapher



I have developped a small utility command line application able to generate simple class diagrams out of any set of namespaced PHP files. The goal being to have a quick way to figure out how some PHP classes were structured without browsing too much code. This is not very accurate but give you a quick big picture of the code structure.

The code can be found on github:
https://github.com/sixty-nine/ClassGrapher

The PHP parser

The class grapher does not use PHP reflection to gather inheritance information about the classes. Indeed, in order to work, PHP reflection needs to be able to instanciate the classes it loads. This is not possible if you have missing dependencies in your project.
The goal of the grapher was to draw the structure of any PHP files.
Thus I implemented a simple recursive parser for only the parts of the PHP language that were needed for the grapher (basically any "use", "namespace", "class" and "interface" statement).

Using composer to download vendors libraries

Composer is a PHP utility used to manage project dependencies.
See composer website.

The idea is simple.

You download the composer.phar binary to the root of your project, then create a composer.json file describing the dependencies of the project and finally run the command:

./composer.phar install

This will automatically download the dependencies as well as create an autoload file for your project.

Example of composer.json file

The grapher project uses the smyfony/console component from the Symfony2 framework. Additionnaly we would like to autoload the files of the project.

The corresponding composer.json file looks as follow:

{
    "require": {
     "symfony/console": "2.0.7"
    },

    "autoload": {
        "psr-0": {
            "LazyGuy\\ClassGrapher": "src"
        }
    }
}

This file will indicate to composer that the library "symfony/console" version "2.0.7" must be downloaded to the project directory. Furthermore any class in the namespace "LazyGuy\ClassGrapher" will be searched in the "src" directory.

Be carefull, this is JSON, you cannot add extra coma at the end of a list if there is no successor in the list (in PHP you can).

Using travis for continuous integration

Travis is a free, lovely continuous integration online service that provides seamless integration with github.

All you need to do is:
  1. Register to travis
  2. Go to github and enable the travis hook
  3. Create a .travis.yml file to indicate to travis how to run the tests of your app
This will cause any github commit in your project to trigger a build on the travis continuous integration server. Travis will run your tests in two PHP environments:
  • PHP 5.3
  • PHP 5.4

The .travis.yml file

This file must indicate to the travis server how to build your project.

In our case, travis must download the dependencies with composer and then run the tests

language: php
php:
  - 5.3
  - 5.4

before_script:
  - wget http://getcomposer.org/composer.phar
  - chmod +x composer.phar
  - ./composer.phar install

script: phpunit -c src/LazyGuy/ClassGrapher/Tests/

The language section indicates which is the language of the project. The "php" key lists the PHP versions to run the tests against. The section "before_script" tells to travis what to do before running the tests (here it will download composer and then run the install command). Finally the "script" section indicates the command to run the tests.

Once you configured travis, any commit to github will cause travis to build the project, run the tests, and report success or failure.

Isn't that lovely?

8 décembre 2011

Experiments with the Arduino - Multiplexed leds

Introduction

In a previous experiment I was controlling 5 leds using 5 outputs of the Arduino. With the help of a 4051 multiplexer it is possible to control up to 8 leds using only 3 outputs.

Basically a multiplexer is an electronic device that can send it's single input to one of it's height outputs. The active output is selected by sending a binary number from 000 to 111 to the three control pins of the multiplexer.

Wikipedia will tell you everything you ever wanted to know about multiplexers.

The schematic

This image was generated with the awesome Fritzing application.

The code

int pinA1 = 8;
int pinA2 = 9;
int pinA3 = 10;

void setup() {                

  for(int i = 1; i <= 10; i++) {
    pinMode(i, OUTPUT);
    digitalWrite(i, LOW);
  }

  digitalWrite(2, LOW);  // Ground
  digitalWrite(3, HIGH); // Power
  digitalWrite(4, HIGH); // Mux input to send to the leds
}

void ledOn(int nr)
{
  int r0 = nr & 0x01;
  int r1 = (nr >> 1) & 0x01;
  int r2 = (nr >> 2) & 0x01;

  digitalWrite(pinA1, r0);
  digitalWrite(pinA2, r1);
  digitalWrite(pinA3, r2);
}

void loop() {
  for (int j = 0; j < 8; j++) {
    ledOn(j);
    delay(50);
  }
  for (int j = 7; j >= 0; j--) {
    ledOn(j);
    delay(50);
  }
}


Demo

1 novembre 2011

Website screenshots with PhantomJS

Introduction

PhantomJS is an headless (i.e. without frontend) web browser based on Webkit with a Javascript API. It is mainly used for headless testing of webpages. It also allows the capture of a webpage into PNG, JPEG, and PDF files.

Compiling PhantomJS

Please follow the instructions here.

sudo apt-get install libqt4-dev libqtwebkit-dev qt4-qmake
  git clone git://github.com/ariya/phantomjs.git && cd phantomjs
  git checkout 1.3
  qmake-qt4 && make

Rasterize a website

The script to render a website to a file is provided as an example of PhantomJS. The code and explanations can be found here.

var page = new WebPage(),
    address, output, size;

if (phantom.args.length < 2 || phantom.args.length > 3) {
    console.log('Usage: rasterize.js URL filename');
    phantom.exit();
} else {
    address = phantom.args[0];
    output = phantom.args[1];
    page.viewportSize = { width: 600, height: 600 };
    page.open(address, function (status) {
        if (status !== 'success') {
            console.log('Unable to load the address!');
        } else {
            window.setTimeout(function () {
                page.render(output);
                phantom.exit();
            }, 200);
        }
    });
}

Now run:

bin/phantomjs rasterize.js http://aventures-logicielles.blogspot.com test.png

And magically you will see the file test.png appear on your disk.

This is absolutely awesome, we just created a screen capture of the website. However this will capture the whole page, and that means for a blog, a very long image. The above will produce an image of 1000 pixels per 15'000+ pixels (2.3Mb).

Getting only the head of the page

With a small modification to the script we can render only the first part of the page. This is possible by setting the clip rectangle before rendering the page. Let's use the page.clipRect function just before calling render as explained on StackOverflow.

var page = new WebPage(),
    address, output, size;

if (phantom.args.length < 2 || phantom.args.length > 3) {
    console.log('Usage: rasterize.js URL filename');
    phantom.exit();
} else {
    address = phantom.args[0];
    output = phantom.args[1];
    page.viewportSize = { width: 800, height: 600 };
    page.open(address, function (status) {
        if (status !== 'success') {
            console.log('Unable to load the address!');
        } else {
            window.setTimeout(function () {
  // ----- CHANGE HERE -------------------------------------------
  page.clipRect = { top: 0, left: 0, width: 800, height: 600 };
  // -------------------------------------------------------------
                page.render(output);
                phantom.exit();
            }, 200);
        }
    });
}

This will produce images of 800 x 600 pixels with an acceptable size (here 360Kb).

Here we go

Let's try the script on my three blogs.







First observation, the third screenshot contains a big grey area where there was originally a youtube video. Apparently the rasterize script is not able to grab it.

Create a screenshot from Apache


The next step is to try to grab a screenshot from within a php script running in Apache. The following snippet searches for the PhantomJS binary and the rasterize script on the same path as the PHP file.

$phantomjs = __DIR__.'/phantomjs';
$script = __DIR__.'/rasterize.js';
$url = 'http://http://aventures-logicielles.blogspot.com';
$outfile = 'webss_' . uniqid() . '.png';

$command = "$phantomjs $script $url $outfile 2>&1";
$output = shell_exec($command);
header('Content-Type: image/png');
echo file_get_contents($outfile);

If you try to run the above script you will not get any result. To understand what's going on you have to var_dump the $output of the shell_exec command. You will get the following error message: "phantomjs: cannot connect to X server".

Strange, isn't PhantomJS supposed to be a headless web browser? The reply can be easily found by googleing the error string. There is an open issue with PhantomJS on *nix systems, Ariya Hidayat, the creator of PhantomJS says: "PhantomJS is not 'pure headless' yet. On Unix, it still needs X Server for font stuff, etc.".

Fortunately there is a quite simple workaround using XVFB. See here for the full explanation.

Once you have set XVFB up following the above explanations, you can modify the PHP script to use XVFB as X server.

$phantomjs = __DIR__.'/phantomjs';
$script = __DIR__.'/rasterize.js';
$url = 'http://http://aventures-logicielles.blogspot.com';
$outfile = 'webss_' . uniqid() . '.png';

$command = "DISPLAY=:0 $phantomjs $script $url $outfile 2>&1";
$output = shell_exec($command);
header('Content-Type: image/png');
echo file_get_contents($outfile);


The sequel


I wanted to play a bit more with PhantomJS and the rasterize script so I created a small Symfony2 bundle using it to create web pages screenshots on the fly. You will find the sources on github.

Take a look here !


Portability


The above code works well on my Ubuntu workstation but a friend of mine just reported the following facts:

  • The rasterize script causes a segmentation fault on my mac
  • On Debian 5 (lenny) the QT libraries are too old to use the rasterize script
  • On Debian 6 (squeeze) everything runs fine

Links

21 septembre 2011

Experiments with the Arduino - Led Matrix

This one was way harder to implement, I wanted to simulate a led matrix with my Arduino.

The circuit


The circuit is not so difficult, basicaly you connect the anode of each row of leds to the same digital output of the Arduino and the cathode of each column of leds to the same digital output. Each led is then connected to a unique pair of digital output.


To turn a led on you just need to set the digital output for the correct row to HIGH and the output for the correct column to LOW.

This means that you can turn on several leds of the same row at the same time but you cannot turn on leds of different rows at the same time. Indeed if you set several rows to HIGH and several columns to LOW, all the intersecting pixels will be turned on, and this is not what we want.

A workaround for this problem is to use a technique named Row Scanning.

The idea is to turn on the leds of each row alternatively. If this is done fast enough, we will not perceive any flickering and we will have the feeling that all the pixels are on at the same time.



The code


The Row Scanning mechanism described above is not so difficult to implement. I decided to use a buffer to store the actual state of the pixels. The demo does not try to change the state of the digital outputs directly. Instead it changes the state of the pixels in the buffer. Then I added a refreshScreen routine that is responsible actually set the state of the digital outputs in a loop.

The problem is that the refreshScreen routine must be called periodically. This is not a problem if we don't have any delay statement in our code, because the delay statement will stop the screen refresh. Unfortunately to create a led matrix demo we definitely want to use some delay so that the user can actually see something on the led matrix.

The solution is to use an interrupt library (TimerOne) that allows to set a routine as callback for a periodic interrupt. So we set refreshScreen as the callback and we have no more problems.

#include "TimerOne.h"

const int XMIN = 2;
const int XMAX = 4;

const int YMIN = 8;
const int YMAX = 10;

int screen[3][3] = 
{
  { 0, 0, 0 },
  { 0, 0, 0 },
  { 0, 0, 0 }
};

int patterns1[][3][3] = {

  {
    { 1, 0, 0 },
    { 0, 0, 0 },
    { 0, 0, 0 }
  },
  {
    { 0, 1, 0 },
    { 1, 0, 0 },
    { 0, 0, 0 }
  },
  {
    { 0, 0, 1 },
    { 0, 1, 0 },
    { 1, 0, 0 }
  },
  {
    { 0, 0, 0 },
    { 0, 0, 1 },
    { 0, 1, 0 }
  },
  {
    { 0, 0, 0 },
    { 0, 0, 0 },
    { 0, 0, 1 }
  },
  {
    { 0, 0, 0 },
    { 0, 0, 0 },
    { 0, 0, 0 }
  },
};

int patterns2[][3][3] = {

  {
    { 0, 0, 0 },
    { 0, 1, 0 },
    { 0, 0, 0 }
  },
  {
    { 1, 1, 1 },
    { 1, 0, 1 },
    { 1, 1, 1 }
  },
  {
    { 0, 0, 0 },
    { 0, 1, 0 },
    { 0, 0, 0 }
  },
  {
    { 0, 0, 0 },
    { 0, 0, 0 },
    { 0, 0, 0 }
  },
};

int patterns3[][3][3] = {

  {
    { 0, 0, 0 },
    { 0, 0, 0 },
    { 0, 0, 0 }
  },
  {
    { 1, 1, 1 },
    { 1, 1, 1 },
    { 1, 1, 1 }
  },
};

int patterns4[][3][3] = {

  {
    { 1, 0, 0 },
    { 1, 0, 0 },
    { 1, 0, 0 }
  },
  {
    { 0, 1, 0 },
    { 0, 1, 0 },
    { 0, 1, 0 }
  },
  {
    { 0, 0, 1 },
    { 0, 0, 1 },
    { 0, 0, 1 }
  },
  {
    { 0, 0, 0 },
    { 0, 0, 0 },
    { 0, 0, 0 }
  },
};


// ----- MATRIX MANAGEMENT --------------------

void refreshScreen()
{
  for(int i = 0; i <= 3; i++) { // For each row
  
    digitalWrite(i + XMIN, HIGH);

    for(int j = 0; j <= 3; j++) { // For each column
    
      if (screen[i][j] == 1) {
        digitalWrite(j + YMIN, LOW);
      } else {
        digitalWrite(j + YMIN, HIGH);
      }
      
      digitalWrite(j + YMIN, HIGH);
    }
    
    digitalWrite(i + XMIN, LOW);
  }

}

void setPixel(int i, int j, int value = 1) {
  screen[i][j] = value;
}

void clearMatrix() {
  for(int i = 0; i < 3; i++) {
    for(int j = 0; j < 3; j++) {
      setPixel(i, j, 0);
    }
  }
}

void showPattern(int pattern[3][3]) {
  for(int i = 0; i < 3; i++) {
    for(int j = 0; j < 3; j++) {
      setPixel(i, j, pattern[i][j]);
    }
  }
}

// ----- DEMO FUNCTIONS -----------------------

void walkMatrixH(int wait, int repeat = 1) {
  for(int k = 0; k < repeat; k++) {
    for(int i = 0; i < 3; i++) {
      for(int j = 0; j < 3; j++) {
        clearMatrix();
        setPixel(i, j);
        delay(wait);
      }
    }
  }
}

void walkMatrixV(int wait, int repeat = 1) {
  for(int k = 0; k < repeat; k++) {
    for(int i = 0; i < 3; i++) {
      for(int j = 0; j < 3; j++) {
        clearMatrix();
        setPixel(j, i);
        delay(wait);
      }
    }
  }
}

void animatePattern(int wait, int patterns[][3][3], int steps, int repeat = 1) {

  for(int k = 0; k < repeat; k++) {
    for(int i = 0; i < steps; i++) {
      showPattern(patterns[i]);
      delay(wait);
    }
  }
}

// ----- MAIN PROGRAM -------------------------

void setup() {               
  
  for(int i = XMIN; i <= XMAX; i++) {
    pinMode(i, OUTPUT);
  }
  for(int i = YMIN; i <= YMAX; i++) {
    pinMode(i, OUTPUT);
  }
  clearMatrix();

  Timer1.initialize(10);
  Timer1.attachInterrupt(refreshScreen);
}

void loop() {
  
  // -------------------------------------------
  animatePattern(10, patterns3, 2, 3); // Flash

  walkMatrixH(10, 2);
  walkMatrixV(10, 2);
  
  // -------------------------------------------
  animatePattern(10, patterns3, 2, 3); // Flash
  animatePattern(10, patterns4, 4, 5);

  // -------------------------------------------
  animatePattern(10, patterns3, 2, 3); // Flash
  animatePattern(10, patterns1, 6, 5);

  // -------------------------------------------
  animatePattern(10, patterns3, 2, 3); // Flash
  animatePattern(10, patterns2, 4, 5);
}

Demo


18 septembre 2011

Experiments with the Arduino - Controlling 5 LEDs

The circuit


The code

void ledOn(int nr, int high = HIGH, int low = LOW) {

  for(int j = 1; j <= 5; j++) {
    if (nr == j) {
      digitalWrite(j, high);
    } else {
      digitalWrite(j, low);
    }
  }
}

void ledsOn(
  int wait,
  int l1 = LOW, 
  int l2 = LOW, 
  int l3 = LOW, 
  int l4 = LOW, 
  int l5 = LOW) {

  digitalWrite(1, l1);
  digitalWrite(2, l2);
  digitalWrite(3, l3);
  digitalWrite(4, l4);
  digitalWrite(5, l5);
  delay(wait);
}

void backAndForth(int nr, int wait, int high = HIGH, int low = LOW) {

  for(int t = 1; t <= nr; t++) {
    for(int i = 2; i <= 5; i++) {
      ledOn(i, high, low);
      delay(wait);          
    }
    for(int i = 4; i >= 1; i--) {
      ledOn(i, high, low);
      delay(wait);          
    }
  }
}

void fallingBrick(int wait, int high = HIGH, int low = LOW) {

  for(int i = 1; i <= 5; i++) {
    for(int j= 1; j <= 6 - i; j ++) {
      ledOn(j, high, low);
      for(int k = 7 - i; k <= 5; k++) {
        digitalWrite(k, high);
      }
      delay(wait);
    }
  }  
}

void boing(int nr, int wait) {
  
  for(int i = 1; i < nr; i++) {
    ledsOn(wait, 0, 0, 1, 0, 0);
    ledsOn(wait, 0, 1, 1, 1, 0);
    ledsOn(wait * 2, 1, 1, 1, 1, 1);
    ledsOn(wait, 0, 1, 1, 1, 0);
    ledsOn(wait, 0, 0, 1, 0, 0);
    ledsOn(wait * 2, 0, 0, 0, 0, 0);
  }
}

void wave(int nr, int wait) {
  
  for(int i = 1; i < nr; i++) {
    ledsOn(wait, 1, 0, 0, 0, 0);
    ledsOn(wait, 1, 1, 0, 0, 0);
    ledsOn(wait, 1, 1, 1, 0, 0);
    ledsOn(wait, 1, 1, 1, 1, 0);
    ledsOn(wait * 2, 1, 1, 1, 1, 1);
    ledsOn(wait, 1, 1, 1, 1, 0);
    ledsOn(wait, 1, 1, 1, 0, 0);
    ledsOn(wait, 1, 1, 0, 0, 0);
    ledsOn(wait * 2, 1, 0, 0, 0, 0);
  }
}

void setup() {                
  for(int i = 1; i <= 5; i++) {
    pinMode(i, OUTPUT);
  }
}

void loop() {
  
  int baf_wait = 50;
  int fb_wait = 100;

  wave(5, 50);
  delay(1000);
  backAndForth(5, 50);
  delay(1000);
  fallingBrick(100);
  delay(1000);
  backAndForth(5, 50, LOW, HIGH);
  delay(1000);
  fallingBrick(100, LOW, HIGH);
  delay(1000);
  boing(5, 50);
  delay(1000);
}

The result

Experiments with the Arduino

Lately I became the happy owner of an Arduino Sidekick Basic Kit.

I will post here some experiments with this lovely device.

What is the Arduino


Arduino is a tool for making computers that can sense and control more of the physical world than your desktop computer. It's an open-source physical computing platform based on a simple microcontroller board, and a development environment for writing software for the board.

Arduino can be used to develop interactive objects, taking inputs from a variety of switches or sensors, and controlling a variety of lights, motors, and other physical outputs. Arduino projects can be stand-alone, or they can be communicate with software running on your computer (e.g. Flash, Processing, MaxMSP.) The boards can be assembled by hand or purchased preassembled; the open-source IDE can be downloaded for free.

The Arduino programming language is an implementation of Wiring, a similar physical computing platform, which is based on the Processing multimedia programming environment.

Playing with a tricolor LED


The circuit



The code


void fade(int r1, int g1, int b1, int r2, int g2, int b2, int steps, int wait)
{
  float dr = (float)(r2 - r1) / steps;
  float dg = (float)(g2 - g1) / steps;
  float db = (float)(b2 - b1) / steps;
  
  float r = r1; float g = g1; float b = b1;
  
  for(int i = 0; i < steps; i++) {
    analogWrite(9, r);         
    analogWrite(10, g);         
    analogWrite(11, b);
    
    r = r + dr;
    g = g + dg;
    b = b + db;
    
    delay(wait); 
  }
}

void setup()  { 
} 
 
void loop()  {

 fade(255, 0, 0, 0, 255, 0, 100, 50);
 delay(1000);
 fade(0, 255, 0, 255, 0, 0, 100, 50);
 delay(1000);
}

The result




Conclusion


I'm an absolute beginner in electronics, but I already felt in love with this micro-controller board. Looking forward to experiment and understand some more :-)

20 mai 2011

Resign Patterns

For all the design patterns lovers...

http://fuzz-box.blogspot.com/2011/05/resign-patterns.html