Pixelastic

You can cut our wings but we will always remember what it was like to fly.

Blog

Working on Wednesday #10 : Mercurial improved

Today I enjoyed the nice blue sky and moved to the park at the end of my street to finish reading the Mercurial guide.

I skipped the last chapters about patches and queues. I know this would be useful, but I'd rather get back to them when I'll need them instead of try them without any real world example.

Tweaking Mercurial

I updated my .hgrc to configure it as best as I could.

I set vimdiff to handle the conflicted merge. vim is quite hard to get (but it is coming easier the more you use it), but it seems so powerful that I'm willing to spend some time learning it.

I've also added a cm alias to commit -Am. This basically is the same as calling hg addremove; hg commit which I happen to do all the time before.

I've create two simple styles and matching templates for my new two aliases peek and hist that repectively display a peek at the last 4 commits, and display the latest 10 commits in history in a concise way. I still have to manage to find how I could add coloring to those.

I've also added a discardlocal alias to remove all local commit and get the repo back as it is on the remote repo. I never actually had to use it, but I found the code on Stack Overflow and thought I might need it later.

I finally wrote a custom resurect method. It will bring back a deleted file (obviously, the file needs to be tracked by hg). I simply find the changeset that deleted the file, and then revert the file to the parent changeset of that changeset. I might post the exact code later as I'm quite happy with the result.

A note on laptop screens

Also, I've spent the last few weeks working on my netbook when at home. This is very tiny thing, the screen is really small (compared to my two 21" at work for example). But (and I was the first surprised of it), you actually get accustomed to it after a while.

Now that I'm writing this post on my 13" other laptop, I feel like it's huge. The more I use the netbook, the more I like it. I didn't quite use it back when it was running Windows because it was way too slow. Now with Ubuntu on it, it's a whole new story !

Next week

I still have some zsh to learn. I still don't quite get the quote and double quote differences, and a few other quirks (arithmetic, arrays, etc).

I've kinda dropped the Rails tutorial. I liked it. Really, I liked it a lot. But I'm not sure I want to start again learning a framework for making websites. I've made a living doing websites for clients, I still do partly that today, and I'd like to change.

I have a lot of personnal project on my mind that I'd like to achieve. Almost all of them could be achieved using the traditional way of making websites that both cake and Rails would allow. But one of them might need another way to look at things. And for this one, I might better need node.

So.. maybe I'll start learning node next week. This is actually something I'd love to do, so this might happen. I'm currently refactoring the JS code of my work app in Backbone at the moment, so I guess there's no perfect time for some JS practice.

Working on Wednesday #9 : Mercurial

I'm feeling like I'm getting more and more behind schedule for what I intended to do at first. I still haven't tried Rails more than that and have gone on different learning side projects.

I've been reading the Mercurial : Definite Guide the past few days to get a correct grasp of the soft.

I've been using Mercurial for the pas two years, but through a GUI and without using any "advanced" features. I never branched a project, and always worked alone.

Commands

Now that I'm working on a Linux machine every day, I can use hg through the command line.

hg commit -Am "commit message" is the same as hg addremove; hg commit -m "commit message".

hg rollback will remove the last local commit. Useful if you forgot files in the commit, or if you inserted a typo in your commit message

hg revert can revert a file or set of files to the state they were at the last commit. This can also cancel a hg add or hg remove

hg backout can "forget" a commit in the history. It will not really forget the commit (ie. will not let you alter the history). Instead, it will create a new commit where the specified changeset is removed (through a merge). It can easily backout the tip, but may involve more merge work if we want to backout an old changeset.

Automation

Also, I've learned about two great tools of Mercurial.

hg bisect let you isolate a specified commit in your history where you introduced a specific bug. You write a piece of code that, given a changeset, returns true or false based on the bug presence, and hg bisect will cleverly scan the history to find the revision that introduced the bug.

hooks where also very interesting. One can script automatic command on specific hg command like commit, pull, push. Or even before those commande to refuse the command if something does not work as expected.

The classical examples where running a build process after a commit, refusing a commit if no bug id where specified, or if the tests didn't pass. Another use case would be to push changes to a remote server on commit.

Git

Why am I learning Mercurial while all the cool guys are using git ?

Well, I've read a lot of papers comparing hg to git. What I've read the more is that git is an awesome toolbox that lets you do whatever you want with your version control, through its 100+ tools.

On the other hand, Mercurial is far easier to learn and has built-in command for the day to day work. As I was already quite familiar with Mercurial, I stick with it, but know that I'll learn git also eventually.

 

Creating a readonly mysql user

I wanted to give access to a database to a colleague, so he can connect and extract some useful stats from our database.

As I didn't want to give him nor the root, nor my access nor even an access with writing permission to avoid potential issues, I created a readonly user.

First, connect to the mysql server :

mysql --user=root -p

And type your password when asked

Now that you are in the mysql prompt, create the 'readonly' user and give him SELECT permission on all tables

CREATE USER 'readonly'@'%' IDENTIFIED BY 'your_password';
GRANT SELECT ON *.* TO 'readonly'@'%';

Also note that once connected with root, you can see the list of users by running :

SELECT host,user,pass FROM mysql.user;

Nothing fancy here, everything was found after a few minutes of googling.

Also, if you ever need to delete the user :

DROP USER 'readonly'@'%';

 

Working on Wednesday #8 : Custom zsh scripts for housekeeping

I made a break of the Ruby/Rails learning this week. Instead I learned a bit more about the basic Linux command, and made a few scripts to help me in my day to day work (and fun) with my Linux environment.

I currently use two laptops. One is a tiny netbook while the other a Dell XPS. I mostly use the XPS for everything work related (like posting this), while the netbook is dedicated to casual use : browsing, playing, etc.

Last week, during my vacations, I only took the netbook with me, and while not strictly speaking working on it I still had to code a little bit. I installed ScummVM, CortixTH and managed to run Carmageddon 2 under wine. I also downloaded and tried a few old emulator games on my Dingoo.

As you may have guessed, I wrote a bunch of scripts during that week to help me in some of the more tedious aspects of this task.

Dingoo deployment

Downloading roms, copying them to the Dingoo, and then testing the games to make sure they are working was tedious. I wrote a little script that automatically mount the Dingoo when plugged to the computer, and copy my games to it, removing old version along the way while still keeping my saved games.

I had to parse dmesg (thanks to grep, tail and sed) as well as use rsync for the copy.

Sansa Clip cleaning

I also wrote a simple script to clean my Sansa Clip of all the useless files I had put on it. As I only have a text screen, I don't need the jpg covers, torrent txt files, auto-generated m3u files and other thumbs.db and .DS_Store useless files.

Here, find to the rescue with some zsh scripting, and here we go.

Shared config files

As I'm working on several computers (two laptops and the one at work at least), I found myself spending time reconfiguring stuff multiple times.

Here, thanks to Dropbox and some clever ln -s calls, I managed to replicate the same config on the 3 machines easily.

From my freelance time, I also have a pretty big /etc/hosts and ~/.ssh/config file. At work, I have another one for the work servers. But I sometimes had to connect to the work server from home.

So once again, thanks to Dropbox, some ln -s once more and cat I wrote two functions to regenerate those two files based on config files. That way, whenever I change one of those files, it is updated on the other machines too.

That was it. It took most of my day.

Being able to script those little repetitive tedious task is something I really appreciate on Linux. I am no longer dependent on the UI my OS gave me, and can now really understand how things work. It requires some time to learn, but this is not going to drastically change from one version to another like it does on each Windows new release.

Working on Wednesday #6-#7 : Correctly installing Ruby on Rails

This post spans two weeks because I couldn't manage to have a clean Ruby/Rails install on my first try. I read a lot, installed ruby using various methods, but finally managed to get it to work corretly.

Cleaning up

First of all, you have to remove any ruby version you might have already installed, just to be sure.

sudo apt-get remove ruby && sudo apt-get autoremove

Installing RVM

Then, you have to install RVM before installing Ruby. My biggest mistake in my various shots at installing Ruby was to install RVM last.

RVM is a very important part of the whole Ruby process. This is a little piece of genius that allow you to create Ruby sandboxes. You can install various Ruby versions side by side, even various gem versions and you simply tell RVM which sandbox you want to use.

If you are absolutly positive that you will never ever work on more than one Ruby project in your entire life, you can skip installing RVM and simply install Ruby globally on your system. But you know that this will never happen, so, avoid future troubles and install RVM first.

To install RVM, simply execute the following command

bash < <(curl -s https://rvm.beginrescueend.com/install/rvm)

This will download and execute the install script. Once it's finished, edit your .bashrc or .zshrc to include the rvm config file whenever a shell is launched.

[[ -r $HOME/.rvm/scripts/rvm ]] && source $HOME/.rvm/scripts/rvm

Just to sure to have the latest version, I also ran

rvm get head
rvm reload 

Updating your system

RVM depends on some binaries to work, so be sure to install them all. They are listed when running rvm notes, but as the time of writing this was the list for me :

sudo apt-get install build-essential bison openssl libreadline6 libreadline6-dev curl git-core zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-0 libsqlite3-dev sqlite3 libxml2-dev libxslt-dev autoconf libc6-dev ncurses-dev

Installing Ruby

Once RVM is installed, installing the latest (1.9.2 as the time of writing) Ruby version is as easy as :

rvm install 1.9.2

This will take some time, downloading and compiling Ruby. Next, tell RVM that this is the version we are gonna use.

rvm use 1.9.2

You can always switch back to your system-wide ruby install by doing

rvm use system

Creating a gemset

Plugins in Ruby world are named gems. They can easily be installed/uninstalled to a project to provide advanced features. Rails itself is a gem.

The traditional way of using gem is to simpy using the RubyGem command gem.

When using RVM and its sandboxed mode however, the best way is to create a gemset, and install gems in that gemset. This will allow us in the future to switch between multiple gemset easily.

I suggest creating a gemset for each project you start. You can also install gems in the global gemset so they get available to each project. As I'm new to the Ruby world and still don't really know which gems ar "must-have", I'll skip this part for now.

Let's create a new gemset for our new project. I'll name mine pixelastic, but change the name to fit your project name

rvm gemset create pixelastic
rvm gemset use pixelastic 

You'll be now using the gemset pixelastic. You can list all available gems in your current gemset by doing

gem list

Or list all the available gemsets by doing :

rvm gemset list

The one you are currently using will be prefixed by "=>"

What is Rake ?

You might have noticed that your new gemset contains only one gem, named Rake. You do not need too spend to much time on that. You simply have to know that Rake is more or less the Ruby compiler. Your Ruby code will go through this gem to became a running app.

Installing Rails

As I said above, Rails is a gem like many other, so you can simply install it by doing :

gem install rails

Note that because we are using RVM, the gem will only be installed in this gemset and not globally. If you switch gemset, rails will no longer be available.

If we weren't using RVM, the gem would have been installed globally. RVM is actually wrapping itself around the gem command to sandbox it inside its own gemset.

Handling dependencies with Bundler

Installing Rails will install a bunch of other gems. One of them is Bundler.

Bundler is a Rails specific gem dependencies handler. Its features seems to overlap thoses of RVM. At the time of writing, I haven't yet used it, but its main use still seems to be its gemfile.

The goal of a gemfile (located in your project directory) is to list all the gems your project will need (along with respective versions if provided). Then, whenever you drop your project in a new environment, Bundler will be able to download and install your gems for you.

If said environment uses RVM, then the gems will be saved in the gemset, if not they will be installed globally. Bundler is absolutly not linked to RVM and can be used independently.

The syntax of a gem file will not be discussed here as I have no previous experience with them, but the command to read the gemfile and update the project accordingly is :

bundle install

Automatic switching gemset

One nice bit of RVM is that it is able to automatically detect the gemset to use on a per project basis. You simply have to create a .rvmrc file in a project, and RVM will execute it.

For example, to use my pixelastic gemset and Ruby 1.9.2, simply add the following to your .rvmrc

rvm use 1.9.2@pixelastic

References

I read a lot on the subject, to finally get it right. Here are the various sources :

Update : Sqlite3

If you got error complaining about Sqlite3 missing, just

sudo apt-get install libsqlite3-0 libsqlite3-dev

Testing Facebook Credits in a local environment

Testing Facebook API has always been a pain for me. Their documentation is still crappy and examples are wrong or/and outdated. Things don't exactly work the same way when you're testing with "Test account" or real accounts.

One of the things that helped me much was to create a test application and set its canvas url to a local server. As the iframe call is done through the client, I can test local code without the need to upload stuff to an online server.

I could even test Requests and Streams through this method as it's the Javascript SDK that does all the AJAX calls. The only tiny issue was with Stream images as Facebook requests them server-side before displaying them, I had to put some placeholder images online.

But today, with the testing of the new Facebook Credits API, new horizon of pains arised. Facebook will make no less than three calls to one of my server callback url, but does not make them client-side.

I still don't want to upload my code to a debug server just to test this feature, so I decided to put in place a little IP/port forwarding. Thanks to tips from my colleague Léo, this was done in a matter of minutes.

Setting up the DNS/port forwarding

First, we'll need a url that Facebook will call. I want this url to point to my local server. So all I had to do was to create a simple DNS redirect at dyndns.com that point to my local IP.

Let it be http://customname.dyndns-office.com/

Paste this url in the "callback url" field of your Facebook Credits config page.

Then, I'll assign a fixed internal IP to my computer so that it won't change on each reboot. My router can do that just fine, by assigning a fixed internal IP based on the MAC adress.

Let it be 192.168.0.51

Now, we'll redirect every call on the router through port 80 (http) to that url. My router admin panel can also do that just fine, in its DHCP configuration.

Finally, we'll have to update the server virtualhost config to point all incoming requests matching customname.dyndns-office.com to the server files.

A side note

There is one last little gotcha to be aware of.

It does not seem to be possible to access one of your network computer from an external IP (as we just configured) FROM one of your network computer.

In other words, if you would like to test your config, do not type http://customname.dyndns-office.com/ in your browser on one of the computers sharing the same network as 192.168.0.51.

Instead, use a free wifi connection, a ssh tunnel or curl from an external server you own.

In my case, locally testing http://customname.dyndns-office.com/ always brought me to my router admin panel and did not forward the port correctly. Doing a curl http://customname.dyndns-office.com/ from one of my online servers correctly returned what I wanted.

Back to Facebook

Back to our Facebook example, you still won't be able to see any outputs from the calls Facebook is making to your app. Your best bet is to have a logging system that will write on disk or in the DB so your can track the calls.

Also note that you have to load the page in the iframe canvas, even for your tests. You can't simply load an html page and call FB.ui({method:"pay"}), this will result in error 1151. Always load in the whole FB page.

Working on Wednesday #5 : Rails documentation and Zombies

Today I continue on my Rails for Zombie learning. Actually, I wake up kind of late (11am), had to deal with noisy neighbors and make some shopping before being really able to start working. It's 2pm now, and I just open my browser.

Back to Zombies

I like the clean syntax Ruby provides. I like being able to pass custom parameters without having to care about the order. This could be achieved in cakePHP using array for options, but is much more clean the Ruby way, using truncate(zombie.graveyard, :length => 10, :omission => '')

Also the link_to and new_{Model}_path, edit_{Model}_path are clever and allow easy access to the link you always use. This force you to logically organise your app.

The way Rails controllers pass vars to the view (using @) is also cleaner than the cakePHP set method. I love those little things the language permits.

before_filter also seems more powerful than in cake world, being able to define several of them and restrict them to certain action. Could be extended (I guess) to an ApplicationController that could check on show, edit, etc that the specified id exists and display an error message if not.

I didn't quite get the various respond_as for JSON and XML. Why should I have to pass the @tweet while I don't have to for the html view ?

Also, the Rails routings system is more appealing to me than its cakePHP counterpart. I would have loved to have such a nice tutorial for cake when I learned it. Routing is very well explained in Rails for Zombies.

After completing the Zombie tutorial, I headed to the famous blog tutorial every web language should have. Once again, I started reading the doc and a few things caught my attention as very promising :

Command line interface

I like the way one can create a new app simply with one command line. Such feature is also provided by cakePHP but I never managed to make it work the way I wanted to. That might have been influenced by the fact that I was working on Windows at that time.

Directory structure

I also note that a Rail application seems greatly structured : there are spaces defined for documentation, tests, database migration, dependencies, logs, deployment scripts and so on.

Databases

This is great that Rails directly provides two distinct DB configurations : development and production. I will no longer have to do it myself.

Rails also uses SQLite3 as the default database for development. As I wasn't very familiar with this technology, I made some researchs. Turns out that SQLite is a very simple DB system, perfectlynsuited for the development period as it does not require a DB server.

Using environment vars in lighttpd config files

Our game is hosted on a farm of servers behind a load balancer. All servers are identical except for their names (prod-01, prod-02, etc) and virtual IP addresses.

In PHP, if I try to access $_SERVER['SERVER_NAME'], I only got the domain name "prod.game.com". Actually, this was exactly the same var as the $_SERVER['HTTP_HOST'].

For logging purposes, I needed to know the name of the server that my script was currently running on. So I updated my lighttpd.conf

Lighty has a feature called include_shell that you can use in its config files. It will basically run a shell script and add its output to your file.

So I wrote a simple shell script to define a var.serverName (this is a custom value, name it as you want, but keep the var prefix) and then re-use when needed.

#!/bin/bash
echo 'var.serverName="'$(uname -n)'"'

Then, I included it in my lighttpd.conf file using include_shell "/etc/lighttpd/scripts/serverName.sh"

To define the PHP SERVER_NAME value :

setenv.add-environment = (
"SERVER_NAME" => var.serverName
)

To add it as a Server: response Header :

server.tag = var.serverName

Note that include_shell directives are only called when you start lighty and not on every request.

Incorrect MySQL date

Several ingame time calculation we made in game are based on Paris time. Some weeks ago, we decided to make a pass on all our servers to always use Paris Time (GMT +1).

Today, I spotted that logs we save in the DB have some date inaccuracy. It appears that our mysql server and instances weren't always updated to the correct date. Some hours later, here is what I learned :

Finding and updating MySQL date

You can tell what timezone mysql should use when you start the service. If you don't specify anything, it will use the system time. Once loaded, you can get its time by running SELECT NOW().

This is the easiest way to spot errors.

To know the defined timezone, run SELECT @@global.time_zone. If not defined, you'll read SYSTEM, which is not very helpful.

Note here that even if you changed the system date AFTER you started mysql, mysql will still use the date that was in effect when you first launched it.

It means that changing your server time will not affet running mysql processes. You'll have to restart mysql to do that : sudo /etc/init.d/mysql restart

Finding and updating the server date

Even after restarting mysql on some servers, the mysql date was still incorrect. After connecting the the sql server, I found that it was the server time that was incorrectly set (I just type date).

To update the current time zone, I had to call sudo dpkg-reconfigure tzdata (I'm using ubuntu) and choose the correct city

Updating mysql running through ndb_mgm

I'm no server expert, so this part was a little trickier. Some of our databases are using ndb cluster for replication. Reloading those configurations was harder.

First, I had to connect to the server running the ndb management and call ndb_mgm. In the later prompt, I typed show and this get me the list of all servers currently managed.

I then shut them down typing shutdown.

The, I reloaded the management and the node running on this server by doing sudo /etc/init.d/mysql-ndb-mgm restart and sudo /etc/init.d/mysql-ndb restart

Finally, I had to connect to all the servers I saw earlier (with the show command) and run sudo /etc/init.d/mysql-ndb restart on each of them

ParisJS #8

(The whole conferences were in french, but as I'm writing every post on my blog in english, I'll write this one too.)

Tonight I was attenting the 8th parisjs meetup. We had the chance to have it hosted at Valtech, in a very wealthy part of Paris, in somptuous quarters and a large room with giant screen (and great pizzas too).

Anyway, this time the meetup was split in two : first part was made of complete talks, while second part only had small lightning talks. With pizza and beer in between.

Wakanda

The first talk was about Wakanda. Wakanda is a complete suite of client/server Javascript which goal is to help create business oriented apps. It is created by the same company as 4D, but this time is completly open source.

The product seemed well done, but kinda monolithic : server side js, client side javascript framework, application studio, debugguer.

I can surely see it used for creating Intranet applications, for some very specific business cases. I have an ambiguous feeling about Wakanda. I think they did a very good job, the whole package seems really neat, the IDE is clear, client/server communication is smooth, etc. On the other hand I'm always suspicious of apps that can do everything.

(Note that I didn't try the product, I only heard about it tonight for the first time and watched a 20min presentation so that's a little light for me to give a precise opinion)

Joshfire Framework

A few months ago, @sylvinus from Joshfire told us that they planned to realease their framework, modeslty named Joshfire.

This is by far the most interesting presentation of the meetup. Joshfire is a javascript framework aimed at working seamlessly between any devices : desktop, mobile, iPad, TV, anything.

It's basic idea is to abstract to its bare bone any interaction. From what I remember, for any "page" you want to define you have to write two JSON structures.

One defines the data tree (what your data is), the other defines the UI tree (how your data can be interacted with). It also ships with some adapters (an adapter is the link between the UI Tree and a specific device).

All you have to do to port your Joshfire app to a new device is to write (or grab if it already exists) an adapter. The main logic and data code is the same for every device, the maintenance is now only focused on any specific device.

Even if the main idea of Joshfire is awesome, their documentation and licensing is even more awesome : the project is already completly documented, with examples and is also completly free and available on github.

CSON, no sorry, JISON

@jie was supposed to talk about CSON, a compressed JSON. But as he already gave a very similar talk (about BSON) at the last #parisnode event, he changed the subject.

I'm not really sure what the real subject of the talk was. I think he mentionned compiling Javascript into Javascript (much like CoffeeScript), but it eventually turned into a Jison demo.

Jison seems to be a tool for automating lexing and parsing languages, to output new code. In effect, this could allow for transforming a custom language into an existing language. CoffeeScript, Haml or Sass works that way : they take a new language as input, and return Js, Html or Css as output.

The advantages are that the custom language is usually much more concise, easy to write and easy to read.

Anyway, this presentation was full of nice quotes :

The language I'm about to show you is totally useless.

Pipe ? What is that ? Oh, you mean the strokes.

The bad thing about Jison is that its documentation is crap

Why does it work ? It was supposed to fail !

Overview of a dev life

This talk wasn't about any new shiny technology. It was about those old browsers and bad habits we had 10 years ago, and how we still managed to make great websites.

This remind me of the "good ol' days" when I discovered the web with FrontPage and ClaraSoft. When IE6 was considered a modern browser.

@molokoloco show us that he managed to simulate ajax using nested iframe, had a website still online and running even after 10 years, was able to code full websites in 3 days, and had read more than 50.000 blog posts. And all that while still using Windows and Dreamweaver.

(Small side note : I praise both @molokoloco and @jie for what they managed to do. I know how easy it is to procrastinate and configure UI, test new tools and IDE instead of getting things done. That didn't seem to be an issue for them.)

mongoDB

This talk was the first in the serie of lightning talks (less than 20mn). It was about mongoDB and how to integrate it in a nodejs app.

As I had never tried nor nodejs nor mongoDB I didn't quite grasp what it was really about. All I get is that in order to get a result from a mongoDB query, one have to go through 3 steps of connection to the DB. In the asynchronous world of nodejs, this doesn't work well, so each step has to fire a callback once executed.

From there, I was lost. There was something about manually calling a callback once initialized, but honestly I didn't get it.

Anyway, I learned from a small talk during pizza time that mongoDB was better than couchDB (performance-wise), and that one have to sacrifice binding to the altar of redundancy to get really fast response time.

Audio demo in less than 1kB. No, 800B. No, wait, 200B

This time the talk was a very fun demo. Using some simple minification techniques, Js was able to play a random music.

This involved encoding the wav file in base64 (taking special care of some chars), and then playing it in an audio tag. Adding a bit of random to play a different note on each loop.

Fun, but interesting.

Some words about the Observer Pattern

This talk was more about theory than practice. Maybe it was the late hour, but it didn't catch my attention as the other did. Maybe someone would re-explain it to me ?

Well, I got the general idea : coding a js snippet that hard code the name of the elements that should react is bad practice because of the maintanability nightmare it cause when elements are removed.

Instead, the speaker advocate the use of a MessageBroker. Some kind of general listener that then dispatch event to element registered to that event (am I right ?).

Then someone in the audience noted that the opposite pattern should work better : that every element registered itself to an event and react when such event is fired (am I still right ?)

Honestly, I really am not sure about this talk, so if anyone could fill the blanks and correct me, I'd be glad.

Sencha and Sencha Touch

I won't go into too much detail on that talk. This was a generic presentation of Sencha (formerly known as ExtJs). I already had the basic understanding of ExtJs (but not the expertise of some of the ExtJs experts in the room), so I was really only half listening.

Sencha is a great product. It is very similar to what Wakanda was showing in the first talk. It is destined to data-heavy applications with lots of numbers, columns, charts, pies, etc.

Sencha Touch is a mobile version of Sencha. It is iOS oriented and emulate the standard UI elements in HTML.

Mozilla Labs

A quick list of the Mozilla Labs projects. I honestly don't remember them all, except Tilt that is a 3D viewer of any web page. It simply calculate the DOM depth and create a pyramid-like structure that you can browser in 3D.

I'm sure that beyond the cool and shiny aspect, it can be useful as a debug/optimisation tool.

Conclusion

Once again, thanks to #parisjs for those talks, always inspiring and a way to meet new people.

For all the new readers, I have an unfixed bug in my comment section : your post can be invalidated if your are using Chrome with an email auto-filler. My custom anti-spam will flag you as spam because Chrome fills an hidden honeypot field.