Pixelastic

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

Blog

Paris Web 2011 : Accessibility

In October, I was attending the Paris Web event. For those that haven't heard of it, it is THE french web event, two days of conference on various subjects web related. It is language agnostic and talks range a very broad list of topics from accessibility, open data, security, performance, UX, UI, html5, etc.

I've attended 16 talks in the course of the event, plus a full day of workshops. I would need far more than a single post to write down everything I learn from those days, both technical and human. I really love Paris Web for those moments where you start to chat with other peoples as passionate as you are.

Here, I'll only focus on a specific subject that everyone cared about : Accessibility.

Know your audience

Accessibility was discussed at length, as it always is the case in Paris Web. It is one of the values held by Paris Web that I also hold dear. My only regret is that it feels like everyone in Paris Web attendee were already familiar with it, had implemented at least the basic good practices, that we all were already convinced of why it is good. I kind of feel that were not the right public, that the speech was wasted on us as we already were convinced.

We, as web professional, are aware of the accessibility concerns. Big groups and public websites are aware of it too. But the middle ground of small companies do not care. "This is not our target", "Spending 40% more for 10% of users ? No way", "We are not big enough", are answers I've often heard when trying to explain to clients why I cared about aspects of their projects they didn't even see.

Continuous integration

Laurent Denis and Elie Sloïm told us that accessibility should not be thought as the last part of a project, the one we do the day before launch. It has to be taken into account for the very start of the project, in the conception phase, and not at the end, as a correction phase.

Every person ever included in the project should be at least aware of the accessibility concern, this is not the work of one man alone. Accessibility experts are not people you can hire to fix your website once it's done. They should be requestd during all the conception phase.

No one ever read the 100 page accessibility audit. No one wants to be told at the end of the project that what they did is wrong and that they should start everything over from scratch. Instead, mini briefs, on mini subjects, sometimes no longer than 15mn, on a regular basis can yield very great results. Starting with the general website semantic, adding unobstrusive javascript, and going deeper and deeper into tasks more and more difficult.

There is no perfection in accessibility. There's only an ideal we tend to. You don't fix a website for accessibility, you just improve it.

Throw away formal accreditations

We can't make a website absolutly perfect, we can just improve it on little touches to make it better and better. A, AA and AAA homologation is absurd, because there is no metrics to quantify the level of accessibility of a website. How could you compare two accessibility features ? How video subtitles is more accessible than alt on images ? We should just forget the accreditations. At first, we did accessibility improvement to help people with disabilities. Somewhere along the years, we became legally forced to provide accessibility measures and it became one more line on the planning and we lost the initial meaning that was driving us.

We should really take accessibility down that pedestal we put it. It's not that hard to make an accessible website, don't be scared by the list of accreditation and rules.

What about HTML5 ?

The geek side of your mind can't stop feeling the excitation when everyone talks about all the shiny stuff : file API, history, geolocation, web sockets, forms, etc. But the eternal question remains : what good are those new toys if we can only serve them to a handful of users. Will I use them now, for the benefit of only some, or will I wait for better support for the benefit of all ? But if I don't promote them myself, I'm only slowing down adoption by all browsers...

That's a tricky question and I don't have a definite answer (and that's fine !).

Paul Bakaus posted recently and article where he stated that it is better to build something awesome for 70% of the people that something good for 95% of them. It surely is true in the gaming world where gamers have the habit of buying new hardware to keep with the new game graphics. In the classical web world, we are still scared of asking the user to change its browser.

But it tickles my accessibility sense when someone told me that a part of the users won't be able to access the content because they don't have the correct requirement. This feels absolutly contrary to the open web principles.

Web and dev events in Paris

For the past month or so, I've attended quite a bunch of dev and web events, here in Paris.

Every time I get back from one, I wanted to post something about it. But I never did, as I always seems to have something more important to do. That's quite a shame, because those events were (for the most part) really interesting, some were even really motivating.

So, expect a full blog post on each of them in the coming days. For the time being, here is just an overview.

Paris Web is THE french web event. Two days of conferences about the web, not too technical, but very practical. Here we speak equally about the "why" than about the "how". Very great speakers, team and place. The third day is for workshops, in smaller groups.

Then comes Paris JS, held each month. It's an evening of informal talks about Javascript, a few speakers will demo an app, a framework, or talk about anything JS related. Very great to meet interesting JS fellows, and exchange about frameworks and projects.

Paris Hacker is an other informal event, where everyone is free to speak about any hacky/geeky subject. Most of the time we review the last Hacker news posts and discuss them, talk about incoming events, and so on. There almost no trolling. Most of the time.

JsGuru is a completly different kind of event. This one is a one-day Javascript formation. It costs real money this time, but you got to learn a few tricks and get your started on some frameworks and libraries like Backbone, Mustache, Lawnchair, etc.

And the final one is the Hack Day Paris. Partially organized by the same team as Paris Hacker, it was a 40hrs hackathon, with no constraint except to "build something brilliant". More than 180 fellow geeks attended, and 43 projects were finally demoed on stage. This was one of the most motivating experience I ever did.

A few days after the Hack Day, an other event was held by SFR were all the Hack Day participants were invited. Along with participant from two other events (Designer Weekend and Museomix), the goal was to help all those people to meet, and to showcase some of SFR latest innovation. This is clearly the event that I liked less.

Getting list of Facebook friends from a test account

To get the list of friends of a specific user, you are supposed to issue a simple GET request to me/friends (or USER_ID/friends), passing the user accessToken in the request.

Facebook used to return an array named data where each value is an object representing a friend. Each of this objects had two keys : id and name.

Until yesterday, it worked well.

Today, it seems broken for test users. The name key is no longer returned in the call, you only get id.

I'm not sure it's intentionnal or not. At least I haven't seen any notice about this change. But I'm not sure it's a bug either, as Facebook documentation is crappy, we never really know if the output we got is the expected one or if it's a bug.

I'm not even sure we were supposed to get the name in the first place, actually.

What is definitely a bug is that the behavior is different for test users that for classic users.

Passing flashVars with Flash 10 in IE

I've spent the last two days debugging a weird issue involving https, IE and Flash.

In the end, I boiled the issue down to IE and Flash 10, https wasn't involved (in fact, that was a different issue).

Markup hell

It is known that to have a real crossbrowser markup to embed Flash we need an IE specific version and a non-IE one.

What I didn't know was that flashvars needed to be passed in two different formats between Flash player 10 and Flash player 11.

11 expect the classic flashvars parameter while 10 expect them to be passed as simili GET parameters to the movie url.

Final HTML markup

In the end, here is the PHP code I use to generate my SWF markup :

sprintf(
'<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="%1$s" height="%2$s" id="%3$s">
<param name="movie" value="%4$s?%6$s" />
%5$s
<!--[if !IE]>-->
<object type="application/x-shockwave-flash" data="%4$s" width="%1$s" height="%2$s">
%5$s
<!--<![endif]-->
%7$s
<!--[if !IE]>--></object><!--<![endif]-->
</object>
',
$width, $height, $id, $url, $params, $flashVars, $alternateContent);

Where :

  • $width and $height are the size (in pixel) of your movie
  • $id is the html/css id of the main object element (as used in swfObject.getObjectById)
  • $url is the url address of your swf file
  • $params is a string containing all the <param name="name" value="value" /> that you want to pass. Usually it will contain the wmode, allowfullscreen, allowscriptaccess and flashvars keys.
  • $flashVars is a duplicate of the flashVars key of $params and should contain a string in the form foo=bar&baz=nyan to be passed to the swf in Flash 10
  • $alternateContent is the html text to be displayed when Flash is not installed in the browse

I hope that this markup will help you, because I spent a damn long time testing all that stuff, jungling between VM and IE instances.

swfobject.getObjectById() when flash not installed

SWFObject is the de-facto library used whenever you need to ember Flash files in your code. It takes care of smoothing all cross browser issues.

It has a getFlashPlayerVersion method that return a string of the current version in the form major.minor.release. Its value is 0.0.0 if Flash isn't installed.

It also provides a cross browser markup, including conditionnal comments for IE, that validate and works everywhere. The downside is that it forces you to create two elements in your markup with the same id.

Hopefully, the getObjectById method is here to return the correct DOM element based on the browser flash integration type.

But... It seems that the mechanisme is buggy when Flash isn't installed (on 2.2)

I've tested running IE9 without Flash installed and FF8 with Flash disabled, and the return of getObjectById differs : I got null in IE9 and the DOM element in FF8.

I've added a small patch to my code to take it into account :

var el = swfobject.getObjectById(id) || document.getElementById(id);

And I've also submitted a bug report.

Fix the floating issue with json_decode in PHP 5.3

When dealing with online API that are handling a lot of items (like Twitter or Facebook), you'd better be aware of a PHP limitation with json_decode.

json_decode is supposed to take a JSON string and return a PHP array or a PHP object from it.

Unfortunatly if one of the key is an int and is bigger than the max int value, it will be cast as float instead. And you'll lose precision in the process.

In my case it resulted in a complete unability to find a user in the database as the id didn't match anything. This was quite hard to find as I couldn't reproduce it on my local machine.

Know your system

My local system was a 64bits machine while the production servers were 32bits. And of course, max int precision is far bigger on 64bits machines so the error didn't pop in my tests.

If you're running PHP 5.4, the fix is easy. Just add the JSON_BIGINT_AS_STRING bitmask as 4th option like this

$decoded = json_decode($encoded, true, null, JSON_BIGINT_AS_STRING);

If you're running a 32bits machine with PHP 5.3 like me, it's a little more tricky.

The regexp

My solution is to parse the original JSON string and add quotes around ints so json_decode will keep them as string.

My first attempt was naive

preg_replace('/":([0-9]+),/', '":$1,', $encoded)

This will find any int between ": (marking the end of a key) and , (marking the start of the next key), and replace it with the same string but enclosed in quotes.

I soon found out that this did not cover all the cases, especially if the int key was the last of the JSON, it won't be followed by a , but by a } instead.

So, I adapted it a little bit :

preg_replace('/":([0-9]+)(,|})/', '":$1$2', $encoded)

Ok, it worked better. Any int key in the JSON, anywhere will be enclosed in quotes.

It was a little overkill so I decided to limit it to keys of at least 10 digits

preg_replace('/":([0-9]{10,})(,|})/', '":$1$2', $encoded)

Better. But still not perfect.

As I soon discovered, sometimes Facebook returned JSON containing JSON itself (in Request data or Credit order_info for example).

The previous approach would add quotes around ints in JSON escaped string and would thus corrupt the whole key.

This time, I added a final touch. I only added quotes around int that were not in an escaped JSON string themselves, by checking that the closing quote of the key wasn't escaped.

preg_replace('/([^\\\])":([0-9]{10,})(,|})/', '$1":$2$3', $encoded)

Here it is, the final fix. I might have forgotten some corner cases, but at least it works for my current application.

Hope it helps !


Accessing a frame with Firebug console

If you want to access the Javascript console of an inner frame of a webpage, know that you can "browse" through the window as you could browse through a file system.

For example, if you want Firebug to use the first frameof the page as its current window object, just type the following code in Firebug console :

cd(window.frames[0])

This proved immensely useful when debugging a Facebook application.

Toggling insert/normal mode in vim with CapsLock

You know that CapsLock key on your keyboard ? The sole usage of this key is to SHOUT ON TEH INTERNETS§§§. I decided to disable it completly as I never use it on purpose.

I also wanted to use it in vim to toggle between normal and insert mode with one key instead of the default i/Esc.

Disabling CapsLock

Disabling CapsLock is a fairly straightforward process. The xmodmap program is responsible for binding keyboard events to your software and you can change the default behavior by creating an ~/.Xmodmap file.

Just put the following code in it and the pressing the CapsLock key will no longer block your next keys in Caps.

clear Lock

Catching it in vim

Now, to get it in vim, you'll have a little more work to do. First, CapsLock is not one of the default vim keycodes, so you won't be able to remap it to any useful function. To use it in vim, we will hook it directly on xmodmap to another key, one that is part of vim default keycodes.

I choose the virtual F13 key. Your physical keyboard might only have F keys from 1 to 12, but the internal software seems to be able to react to 37 of them. So, why not using them ?

In your ~/.Xmodmap file, this is as easy as adding the following line

keycode 66 = F13

66 is the internal code for the CapsLock key. We just define that pressing the physical CapsLock key should trigger the F13 virtual key.

Now, in ~/.vimrc, we will tell vim to explictly listen to extended F keys (from 13 to 37) which it does not do by default.

set <F13>=^[[25~

^[[25~ is the special keyboard code sent to vim when the F13 key is triggered. Here we just define that such a keyboard code should be interpreted in vim as an <F13> vim key.

Now, you can use <F13> in your custom vim mappings

Toggling normal/insert mode in vim

vim accepts two kinds of mapping. Those triggered in normal mode (using nnoremap) and those triggered in insert mode (using inoremap).

Here we want that pressing CapsLock (or <F13> in vim as we defined) in normal mode will go to insert mode, like pressing i does. And we also want to get back to normal mode when pressing CapsLock in insert mode, just like pressing Esc does.

nnoremap <F13> i
inoremap <F13> <Esc>l

Notice the l after Esc. It is here to prevent the caret to move back one character when exiting insert mode.

Fixing the shell

One last thing to fix is your shell. By defining in xmodmap that pressing CapsLock would trigger an F13 event, it means that whatever software that react on F13 will now react on CapsLock. Unfortunatly, zsh does react on F13. It insert a ~ character on it (just like it does with F12).

To disable it, we'll simply define a key binding in ~/.zshrc so pressing F13 does nothing.

bindkey -s "\e[25~" ""

Here it is. You can now press CapsLock anywhere and it won't have any effect. Plus, pressing it in vim will toggle insert/normal mode.

Getting the list of Facebook pending requests of a user

Getting the list of pending facebook requests of a user a few weeks back was as easy as calling

https://graph.facebook.com/me/apprequests?access_token={user_access_token}

We discovered around the 1st October that some of our requests were failing in production, without any more clue than some "OAuthException : access_token invalid" messages in our logs.

It appears that FB changed the way their endpoint react to /apprequests call. Of course, they didn't bother telling us.

The previous url does not work anymore. Switching the user access_token to the app access_token as documented does not work (as usual with FB documentation). It returns an error.

Instead, the following call wil yield the correct result :

https://graph.facebook.com/{user_id}/apprequests?access_token={app_access_token}

Increasing VirtualBox hard drive size

While trying to import a huge (1.7Go) mysql dump file into my VM I was blocked by mysql telling me that not enough space was left on the device to complete the operation.

As I was running a VM, I thought it would be a simple matter of increasing the virtual hard drive size.

Turns out it wasn't that simple. After much trial and error, here is how I finally did it.

Creating a new hard drive

VirtualBox let you easily add new devices, such as hard drives to your VM. I simply created an empty 120Go hard drive and booted my VM.

Here, under Ubuntu, I cloned my current hard drive to the new one using :

sudo dd if=/dev/sda of=/dev/sdb

Fixing the guest partition

Once finished, I opened Gparted, selected /dev/sdb and saw that I had 112Go unallocated. I couldn't easily add them to the initial partition as a swap partition was in the way.

I finally decided to remove the swap partition and resize the initial one to the (almost) complete size of the hard drive.

I left 1Go free in case I ever needed to create a new swap partition later to fix the one I deleted.

Then, I closed the VM. Get back to VirtualBox panel and remove the original drive, keeping only the new 120Go one.

One reboot later, my Ubuntu was proudly displaying its 120Go.