No more del.icio.us on Tempe.st

I have decided to remove the daily del.icio.us post with my links, it created too much noise and diluted good content.

Google News Italia Spammed

I’m about to go on holiday for a few days, here’s a screenshot I just took from Google News Italia, it seems like the service has been spammed…

Here’s a search for web2.0 

google news spammed

How to ease Drupal development with Capistrano

Drupal is a great piece of software, unfortunately it stores so much stuff in the db that people struggle keeping in sync the development server/box and a staging server to show their customers how the work is proceeding.

Today I will share the Capistrano tasks I use to sync my development box with the staging server. What I basically do is dumping the development db, sending it to the server via capistrano and then use the dump to replace the server’s database.

The following tasks should be used together with the tasks in my Deploying drupal with Capistrano article. I took advantage of deploy:cold not being needed with Drupal, and added a callback to it, so if you want to do a deploy that also updated the database you should use deploy:cold.

You should also have two settings files (usually stored in drupal_root/sites/default), one called settings.development.php, with your local database setup and one called settings.production.php with the remote database setup, the capistrano tasks will take care of choosing the correct one.

# Callbacks
before 'deploy:start', 'drupal:db:import:production'
before 'deploy:restart', 'drupal:configure:production'
before 'deploy:start', 'drupal:configure:production'
before 'deploy:cold', 'drupal:db:dump:development'
 
# DB Stuff
set :mysqldump, "/path/to/mysqldump"
set :local_db_user, "local_mysql_username"
set :local_db_password, "local_mysql_password"
set :local_db_name, "local_db_name"
set :db_user, "remote_mysql_username"
set :db_password, "remote_mysql_password"
set :db_name, "remote_db_name"
 
namespace :drupal do
  namespace :configure do
    task :production do
      sudo "cp #{latest_release}/sites/default/settings.production.php #{latest_release}/sites/default/settings.php"
    end
 
    task :development do
      sudo "cp #{latest_release}/sites/default/settings.development.php #{latest_release}/sites/default/settings.php"
    end
  end
 
  namespace :db do
    namespace :dump do
      task :development do
        raise RuntimeError.new("failed dump") unless system "#{mysqldump} -u #{local_db_user} --password=#{local_db_password} #{local_db_name} > dump.sql"
      end
    end
 
    namespace :import do
      task :production do
        ENV["FILES"] = "dump.sql"
        deploy::upload
        run "mysql -u #{db_user} --password=#{db_password} #{db_name} < #{latest_release}/dump.sql"
      end
    end
  end
end

Deploying Drupal with Capistrano

Mikamai, the company I work for, has just released Montalbano.tv, the companion site to one of the most successful TV shows in Italy.

I was the technical director of this Drupal based project, and while I was happy we chose Drupal, because it allowed us to deliver all the features they needed on time, I almost panicked when they told us the production setup would have two servers, both with database and web serving duties.

The database replication was standard MySql master-master setup, but I had to develop a strategy to keep the two code-bases on the two servers synchronized.

Being a Ruby programmer at heart, I selected the only tool that never fails me in circumstances like the one we had: Capistrano.

Unfortunately, while Capistrano is all easy to use with Rails, I had to write a custom Drupal-tailored Capfile.

Here it is, in its entirety, in case you ever need to deploy Drupal with cap (now I always deploy Drupal with cap, since I have the recipe ready :)):

load 'deploy' if respond_to?(:namespace) # cap2 differentiator
 
# Standard configuration
set :user, "username"
set :password, "password"
set :application, "application.name"
 
# I like to deploy the code in /var/apps
# and then link it to the webserver directory
set :deploy_to, "/var/apps/#{application}"
 
# SCM Stuff configure to taste, just remember the repository
# here I used github as main repository
set :repository,  "git@github.com:username/project.git"
set :scm, :git
set :branch, "master"
set :repository_cache, "git_master"
set :deploy_via, :remote_cache
set :scm_verbose,  true
 
# Two servers, double fun
# You really don't need app, web and db here,
# but I used all of them just to be sure.
# Usually only web is ok.
role :app, "first.server.address.com"
role :app, "second.server.address.com", :primary => true
role :web, "first.server.address.com"
role :web, "second.server.address.com", :primary => true
role :db, "first.server.address.com"
role :db, "second.server.address.com", :primary => true
 
after 'deploy:setup', 'drupal:setup' # Here we setup the shared files directory
after 'deploy:symlink', 'drupal:symlink' # After symlinking the code we symlink the shared dirs
 
# Before restarting the webserver we fix all the 
# permissions and then symlink it to production
before 'deploy:restart', 'mikamai:permissions:fix', 'mikamai:symlink:application'
 
 
namespace :drupal do
  # shared directories
  task :setup, :except => { :no_release => true } do
    sudo "mkdir -p #{shared_path}/files"
    sudo "chown -R #{user}:#{user} #{deploy_to}"
  end
 
  # symlink shared directories
  task :symlink, :except => { :no_release => true } do
    sudo "ln -s #{shared_path}/files #{latest_release}"
  end
end
 
namespace :deploy do
  # adjusted finalize_update, removed non rails stuff
  task :finalize_update, :except => { :no_release => true } do
    sudo "chmod -R g+w #{latest_release}" if fetch(:group_writable, true)
  end
 
  task :restart do
    # nothing to do here since we're on mod-php
  end
end
 
namespace :mikamai do
  # symlinking to production
  namespace :symlink do
    task :application, :except => { :no_release => true } do
      sudo "rm -rf /var/www/montalbano"
      sudo "ln -s #{latest_release} /var/www/montalbano"
    end
  end
 
  # change ownership
  namespace :permissions do
    task :fix, :except => { :no_release => true } do
      sudo "chown -R www-data:www-data #{latest_release}"
    end
  end
 
end

New tempe.st, new performance, new server

If you’re a regular reader you will have noticed the new layout and the all-new top-notch site performance.

I’ve been looking for a new theme for a long time, because I needed a wider content column, and I’ve also implemented the superfast lighttpd + wp-supercache setup I described in a previous post.

I hope you’ll enjoy your stay on the new Tempest of Thoughts.

Techtalk Italia 2008

Last year Netwo organized  a  whole weekend with the most interesting experiences on the web Italian arena. This year we’re back to announce Techtalk Italia 2008!

Techtalk is an event originally organized by Martin Varsavsky for the best european/world web2.0 entrepreneurs. The whole weekend spent together, during a few sessions everyone participating will give a short presentation of her/his activity. Our families will be with us and we will take the time to have fun all together.

We think this is a really good formula, so with a few friends we decided to bring it to Italy. 

For the second year in a row we will spend a whole weekend (from july 4th to july 6th) with the top Italian web entrepreneurs, discussing our projects but also having a great time together in a wonderful villa in Tuscany.

We will post more info shortly on the netwo blog, if you want to come, please write me.

Here are a few photos from the last edition.

firenzuola techtalk

Firenzuola, the wonderful Tuscan town there the Techtalk is held

firenzuola techtalk

The swimming pool is surrounded by a forest

firenzuola techtalk

Saturday morning session

firenzuola techtalk

Saturday night dinner

 

Getting Exif data using ImageScience

In my current rails project I need to upload photos and save some exif data taken from them. I use attachment_fu as uploading system that let me choose which image processor to use. Using rmagick and mini_magick I can extract exif data with the following code:

# rmagick
image = Magick::ImageList.new(filename).first
puts image['EXIF:Model'] # The camera model used to take the picture

# mini_magick
image = MiniMagick::Image.from_file(filename)
puts image["EXIF:Model"]

The problem is that I can’t do the same thing with image_science, because it has no methods that return exif data, so I want to add a method to the ImageScience class to do that.
Looking the FreeImage documentation I found some helpful functions, FreeImage_GetMetadata and FreeImage_TagToString. With these 2 functions I’m able to get an exif tag and convert it to a readable string. Each one of the available tags belongs to one of the following meta models:

FI_ENUM(FREE_IMAGE_MDMODEL) {
  FIMD_NODATA         = -1,
  FIMD_COMMENTS       = 0,	// single comment or keywords
  FIMD_EXIF_MAIN      = 1,	// Exif-TIFF metadata
  FIMD_EXIF_EXIF      = 2,	// Exif-specific metadata
  FIMD_EXIF_GPS       = 3,	// Exif GPS metadata
  FIMD_EXIF_MAKERNOTE = 4,	// Exif maker note metadata
  FIMD_EXIF_INTEROP   = 5,	// Exif interoperability metadata
  FIMD_IPTC           = 6,	// IPTC/NAA metadata
  FIMD_XMP            = 7,	// Abobe XMP metadata
  FIMD_GEOTIFF        = 8,	// GeoTIFF metadata
  FIMD_ANIMATION      = 9,	// Animation metadata
  FIMD_CUSTOM         = 10	// Used to attach other metadata types to a dib
};

Ok, now I can extract the model of the camera:

FreeImage_GetMetadata(FIMD_EXIF_MAIN, bitmap, "Model", &tag);
printf(FreeImage_TagToString(FIMD_EXIF_MAIN, tag, NULL));

As you can see, I need to pass the model of the “Model” tag. But if I don’t know which model to use, I can loop through all of them until the returned value of the FreeImage_GetMetadata function is not NULL:

for(model = 0; model < 11; model++) {
  if(FreeImage_GetMetadata(model, bitmap, tagName, &tag))
    return rb_str_new2(FreeImage_TagToString(model, tag, NULL));
}

Finally I can write a ruby module that extends ImageScience and adds the ability to get an exif tag:

module ImageScienceExifData

  def [](key)
    if key =~ /^EXIF:(\w+)?/
      get_exif($1)
    end
  end

  inline do |builder|
    if test ?d, "/opt/local" then
      builder.add_compile_flags "-I/opt/local/include"
      builder.add_link_flags "-L/opt/local/lib"
    end
    builder.add_link_flags "-lfreeimage"
    builder.add_link_flags "-lstdc++" # only needed on PPC for some reason. lame
    builder.include '"FreeImage.h"'

    builder.prefix <<-"END"
      #define GET_BITMAP(name) FIBITMAP *(name); Data_Get_Struct(self, FIBITMAP, (name)); if (!(name)) rb_raise(rb_eTypeError, "Bitmap has already been freed")
    END

    builder.c <<-"END"
      VALUE get_exif(char *tagName) {
        GET_BITMAP(bitmap);
        FITAG *tag = NULL;
        const char *value;
        int model;

        for(model = 0; model < 11; model++) {
          if(FreeImage_GetMetadata(model, bitmap, tagName, &tag))
            return rb_str_new2(FreeImage_TagToString(model, tag, NULL));
        }

        return Qnil;
      }
    END

  end
end
ImageScience.send(:include, ImageScienceExifData)

ImageScience.with_image(filename) do |img|
  puts img["EXIF:Model"]
end

The output with the picture I used is the following :

NIKON
COOLPIX S3
2006:12:10 12:09:17

It doesn’t work with all the exif names but for now it’s ok for my needs. The next step is to add the code above in my rails application and use it with attachment_fu. I’ll write another post about that soon.

Moving to github

The github revolution has hit me too. I’m moving all my Radiant extension to my account on github.  Follow me and fork my projects :)!

The fall of muni-wifi projects

The NYT posted an interesting article about what seems to be the fading point of municipal wireless projects: many cities are rolling back their projects, as it seems there are no more hopes of revenues that can help sustain the infrastructure.

The problem was in the original approach that many cities had towards the creation of such projects:

“The entire for-profit model is the reason for the collapse in all these projects” says Sascha Meinrath on the NYT’s article. Many companies have seen those projects as a new way to enter the ISPs market. Obviously that market is pretty crowded, revenues are already fading away for traditional ISPs, and newcomers are having bad days.

Wireless technologies (both wifi and wimax) raise many infrastructure problems (radio signal issues, compatibility problems, small coverage range, ..) and many networks aren’t profitable at all (in most cases they represent a big loss for both companies and cities).
As a result of this situation many companies are pulling out from projects they were involved in (as Earthlink did in Philadelphia and other cities). This is a problem for cities who need solid partners to build such services. Residents are also concerned, especially low-income families who were expecting municipal networks as a way to get cheaper connections. This is particularly important for children, as Internet connection is tightly tied to their education.

Fortunately a new approach could be the solution to those issues.

Meraki jumped in the market with a different strategy: they are selling cheap devices that plugs into existing home connections
extending them with public wifi signal. Additionally they sell cheap devices to be used outside (mainly on light poles). As you probably know Fon has a very simlar approach since almost two years: they are offering cities free (or almost free) wifi routers for residents, that would allow the inhabitants to build their own networks. Routers installed on DSL connections at home team up to create a public network that could cover the entire city.
This grassroot approach could be a way to overcome failures. The fon city project is already active in five cities across Europe, while many others are interested in such projects.

Many ISPs do not allow their customers to share DSL connections, so this kind of networks could face a new problem in the near future.
While cities are still trying to find the right approach someone is already thinking about giving free wifi routers to homeless people, who can then sell connections to people who are around them for a small tip.

Radiant Newsletter extension has stats

Some weeks ago Casper Fabricius sent me a patch for the Radiant Newsletter extension. He added a statistics system to track how many times sent emails are opened. I have finally found the time to apply it and make a commit to my repository. Thank you very very much for your work Casper! I’ll write an article about this extension as soon as possible.