A long weekend with Ubuntu

Written on 20 May 2013, 10:49pm

Tagged with: ,

Getting out of your comfort zone is difficult. That’s why I decided to try it in a variety of ways. Becoming platform independent is one of it.
Since the first time I touched a computer, I worked with Windows. Then, in the university, I kind of had to work in Linux. I remember having Red Hat 7.3 for a brief period of time. Working in the web development put me in the situation to SSH to a remote web server in order to make changes in the server configuration. And that’s pretty much all my non-Windows experience. Oh, that and the time I spent in the Apple Stores trying out the MBAs. Which I loved, but never really thought buying one because of the price and lack of need.
Fast forward to this weekend – I decided to give Ubuntu a try. Except for my free time, nothing else was necessary.
Before I started, I was aware that it would be almost impossible to switch everything from Windows to Ubuntu. For instance – photography manipulation and backup, iDevices synchronization, play content to TV via allShare, bluetooth streaming to my home theater, and probably a few others which I don’t realize at the moment. But hey, small steps. For now, the goal was to move my PHP side-project environment from Windows to Ubuntu. Spoiler: it worked! πŸ™‚
List of steps I performed:
– downloaded and wrote the Ubuntu 13.04 iso image on a bootable USB drive
– while downloading, learned about the Ubuntu release code names πŸ™‚
– tried to install it two times from the bootable USB drive with persistent space
– encountered an unknown (for me) error:
DAFB4BFC-050F-4E7E-A753-CEAABFB3C95A 97574283-6879-446D-951A-0BE9C25C8F04
– messed up the Grub boot loader while formatting the Ubuntu partition in Windows:
grub rescue
– using another computer (luckily I had one), I created again the bootable USB drive, this time without persistent space
– installed Ubuntu for the 3rd time:
911F84BF-2857-4FE7-946C-7E48CB0E1EBB
– this time it worked, only to find out that it installed a wrong driver for my wireless network card
– plugged in the network cable and spent a couple of hours on some geeky unix/ubuntu forums searching for the correct driver to install
– [end of day 1]
– turns out, trying to install Google Chrome on Ubuntu 13.04 is not a piece of cake. One must know the differences between Chromium and Google Chrome. Then, installing the official Google Chrome failed because of an error. Some more time to find out that the error is solved in the unstable, dev version. Install it and synchronize my Google Chrome account. Felt in a better place πŸ™‚
– installed Vlad’s Roaring Railtail wallpaper. Felt in an even better place πŸ™‚
vladstudio_raring_ringtail_blue_800x600_signed
– played for a little bit with the other usual suspects: Rhythmbox for music, VLC player for video, Shotwell for pictures, Transmission, GEdit, etc
– next – Sublime Text. No problems here, except for the general remark that instead of the familiar Windows ‘download-install-enjoy’ workflow, there is a ‘search-hack-pray-enjoy’ one.
– speaking of software installation and workflow – I only managed to use the Ubuntu Software Center to install Dropbox and Wine. For the rest, I either had to apt-get install, or add a PPA repository (Personal Package Archive).
– spent more than one hour trying to find an alternative to TortoiseSVN. I gave RabbitCVS a chance, but the installation process did not work as expected. It failed when trying to sudo apt-get install rabbitvcs-thunar: “The following packages have unmet dependencies:
rabbitvcs-thunar : Depends: thunarx-python (>= 0.2.0) but it is not installable
E: Unable to correct problems, you have held broken packages.
“. Unfortunately, the Internets ran out of obscure/geeky/ubuntu forums to correct this problems and I gave up 😐
– I settled for a non-graphical SVN client instead: Sublime SVN. This guy is a genius, and not for this handy plugin, but for the Package Control itself.
[end of day 2]
installing the Lampp environment was easier than expected. Changing the default DocumentRoot was also fairly easy.
– after getting over some annoying PHP error reporting problems in PHP 5.4, I was able to do my first commit from Ubuntu and deploy it using DeployHQ
– felt like cheating for using Wine for Total Commander and Beyond Compare πŸ™‚
– finally, installed Dropbox from the Ubuntu Software Center. Didn’t try Ubuntu One; Dropbox, Google Drive and Crashplan fulfill all my cloud needs πŸ™‚

Documentation:
Ubuntu-Manual.org
The Official Ubuntu Book (2012)

Still to be done:
mouse buttons configuration: I am using for more than 5 years a Logitech VX Nano (actually I have 3 pieces πŸ™‚ ) and I really got used to the ‘minimize’ button shortcut. Logitech does not provide Ubuntu drivers, and a quick search for ‘xinput set button map’ did not help. Still digging – but if I can’t make it work, it’s ok. Stepping outside the confort zone even more πŸ™‚ Moreover, the middle button still works.
Google Chrome mouse gestures: I am using this Chrome extension for the mouse gestures. It works fine in Windows, but it fails miserably in Ubuntu
install Skype
find a dlna server as alternative to allShare (serviio?)
find a bluetooth streaming Ubuntu alternative

Conclusions:
– the software distribution and installation in Ubuntu is a pain. I’m not saying that the ‘download-install-autoupdate-enjoy’ Windows workflow is perfect, but the current Ubuntu alternative needs improvements (to say the least). I personally think that this is the main reason why it keeps people away. Installing a web browser should be a task that can be accomplished by a 10-years old, not by an an adult with reasonable computers experience digging some obscure forums to install an unstable release.
OS installation is generally ok (I tend to believe that my problems were caused from my local setup). This is a one-time process and people are more forgiving in this case, but…
– the driver detection can be improved. Installing Ubuntu only to find out that it doesn’t recognize your wireless card is a no-no. Both Linux and Windows worlds are, by design, pretty far from the ‘walled-garden’ and its ‘it just works’ mantra
– so far I have mixed feelings about my Ubuntu experience. One one hand I appreciate the general look and feel, speed and, well, price. On the other hand, I find it intimidating, especially when installing new things. But one thing is clear: I am not giving up. And for the moment I don’t feel the need to go back to Windows.

Multiple languages in a CakePHP 2.* application in 5 steps

Written on 1 August 2012, 10:21pm

Tagged with: , ,

Below is a solution that I implemented in a CakePHP project needing internationalization (i18n).
It involves showing the language in the URL (so the URLs will look like app.com/:lang/:controller/:action/...) and storing it in the Session + Cookies.
It is basically the implementation described on http://nuts-and-bolts-of-cakephp.com. I only added some minor changes to make it work under CakePHP 2.* (the solution in the link above was implemented in November 2008, for CakePHP 1.3).
The implementation below was tested on CakePHP 2.2 (1 August 2012).
Feel free to add your comments/questions in the form below.

Comments inline:


// Step 1: app/Config/routes.php
Router::connect('/:language/:controller/:action/*',
                       array(),
                       array('language' => '[a-z]{3}'));

//Step 2: app/Config/core.php
Configure::write('Config.language', 'eng');

//Step 3: create app/View/Helper/MyHtmlHelper.php
App::uses('HtmlHelper', 'View/Helper');
class MyHtmlHelper extends HtmlHelper {
	public function url($url = null, $full = false) {
        if(!isset($url['language']) && isset($this->params['language'])) {
          $url['language'] = $this->params['language'];
        }
        return parent::url($url, $full);
   }
}

//Step 4: app/Controller/AppController.php
class AppController extends Controller {
	public $components = array('Cookie','Session');
	//set an alias for the newly created helper: Html<->MyHtml
	public $helpers = array('Html' => array('className' => 'MyHtml'));

	public function beforeFilter() {
          $this->_setLanguage();
        }

	private function _setLanguage() {
	//if the cookie was previously set, and Config.language has not been set
	//write the Config.language with the value from the Cookie
	    if ($this->Cookie->read('lang') && !$this->Session->check('Config.language')) {
	        $this->Session->write('Config.language', $this->Cookie->read('lang'));
	    } 
	    //if the user clicked the language URL 
	    else if ( 	isset($this->params['language']) && 
		($this->params['language'] !=  $this->Session->read('Config.language'))
	    		) {
	    	//then update the value in Session and the one in Cookie
	        $this->Session->write('Config.language', $this->params['language']);
	        $this->Cookie->write('lang', $this->params['language'], false, '20 days');
	    }
	}

	//override redirect
	public function redirect( $url, $status = NULL, $exit = true ) {
		if (!isset($url['language']) && $this->Session->check('Config.language')) {
			$url['language'] = $this->Session->read('Config.language');
		}
		parent::redirect($url,$status,$exit);
	}
}

//add the links to the languages:
//Step 5: app/View/...
echo $this->Html->link('English', array('language'=>'eng')); 
echo $this->Html->link('Français', array('language'=>'fre')); 

Update August 3rd 2012: Added ‘private’ visibility for the _setLanguage function
Update September 28th 2012: Modified the first step (app/Config/routes.php), adding more restrictive rules for the languages. Before, if the user somehow loaded an URL like /css/foo/bar – then ‘css’ was incorrectly considered a language.


	Router::connect('/:language/:controller/:action/*',
                       array(),
                       array('language' => 'eng|fre'));

	Router::connect('/:language/:controller',
                       array('action' => 'index'),
                       array('language' => 'eng|fre'));	

	Router::connect('/:language',
                       array('controller' => 'welcome', 'action' => 'index'),
                       array('language' => 'eng|fre'));

A little bit about Fusion Tables

Written on 22 May 2011, 10:49pm

Tagged with: , , ,

Google Fusion Tables is a modern data management and publishing web application that makes it easy to host, manage, collaborate on, visualize, and publish data tables online.

So as far as an user is concerned, a Fusion Table is a virtual table stored in the cloud, on which he can perform the regular CRUD operations. Here comes the nice part: the language on which you can perform these operations is SQL-like. The API is designed so that you can use URLs like
http://www.google.com/fusiontables/api/query?sql=select+*+from+1234567
The output of this request is a CSV text, with the contents of the selected table.

Let’s assume that you have a Fusion table where you store some physical addresses for some items. Below is a very simple PHP script which reads the contents of the fusion table, parses it, extracts the address, then performs a geocoding request using the geocoding API, parses the JSON object and outputs the latitude and longitude of the given address.

<?php
//run sql query to get data from fusion table
$url = 'http://www.google.com/fusiontables/api/query?sql=select+*+from+822057';
$lines = file($url);

$i = 0;
foreach ($lines as $line_num => $line) 
{
	//parse csv line
	$csv = str_getcsv($line);

	//extract the address
	$address	= $csv[7];
	
	if($address)
	{
		//we need to geocode the address to get the latitude and longitude
		$url_address = urlencode ($address);
		$geocode_url = "http://maps.google.com/maps/api/geocode/json?address=$url_address&sensor=false";
		$geocode = file_get_contents($geocode_url);
		$output = json_decode($geocode);

		$latitude = $output->results[0]->geometry->location->lat;
		$longitude = $output->results[0]->geometry->location->lng;

		//sleep for a second
		sleep(1);

		//do something nice with all this data

	}
}

?>