USB Connectors Wasting 4 Million man-hours per year

August 20th, 2010

The lack of symmetry for USB connectors is wasting 4 Million man-hours per year.
And that is using conservative numbers.

To the engineers and designers in charge of specifications for those connectors:
- Why do you need connectors to be asymmetric?
- Whatever your reason is, can’t you come up with a symmetric connector with some logic that would solve the problem?

1/ The computation

How do we get to 4 Million man-hours?

Jeff Ravencraft of Intel Corporation, Chairman and President of the USB Implementers Forum said “Over 6 Billion products are in the market, and over 4 Billion ship a year now.”
There’s even a commercial for USB claiming out loud those 6 Billion devices and it was back in June 2009. With 4 Billion new devices every year, we should actually be around 10 Billion now.

But let’s start with 6 Billions devices to be conservative, even though by now we should be around 10 Billion.

6,000,000,000 USB devices out there.
Let’s divide by 10, assuming only one device out of 10 is in use (the rest being obsolete devices rotting in boxes in your attic)
Let’s divide by 2, assuming we insert the wrong way only half the time (50% chance of doing so)
Let’s multiply by 52, assuming we plug them only once a week on average
Let’s multiply by 1, assuming we waste one second plugging it back correctly
Let’s divide by 3600 seconds to have the result in hours

6B / 10 / 2 /3600 * 52 = 4.3 Million

What does 4 Million man-hours mean?

Let’s compare this number to numbers we can grasp.

At 40 hours per week, people work around 2,000 hours per year.

Thus 4M man-hours translates to:
- 2,000 years of work for a single man
- 20 years of work for a 100 employee company
- 5 complete weeks of work from all the Google employees (Google has roughly 20,000 employees)

4M man-hours is also $32 Million dollars at the California minimum wage of $8.

4M man-hours is also $100 Million dollars at the 2008 US median household income of $50,000, or $25 per hour.

These amazing numbers don’t take into account the amount of frustration generated by having to struggle with mating two simple pieces of hardware.
These man hours wasted have pain and anger written all over them, unlike the 5 Million hours wasted playing Pac-Man on Google (unless those ghosts make you angry).

Companies worrying about their employees wasting time playing online games at work and taking radical measures like banning certain websites like Facebook better off step up and demand smarter features from their computer manufacturer, whether it’s a mouse you never have to clean (we finally got that) or simple symmetric connectors.

And this is just for USB (and yes, even the latest USB 3.0 has asymmetric connectors).

Now there’s still Firewire, VGA, DVI, HDMI, RJ-45, RJ-11 phone jack, PATA, SATA, Power connectors, SD cards and all other card formats like CompactFlash and XD, … even your batteries!

Although we start to finally see some much needed evolution for the batteries with the recently announced Microsoft GangstaLoad InstaLoad technology.

Have you ever been frustrated wasting time mating two connectors?
How many times a day do you plug USB connectors?

Let’s refine those numbers and see what we have for all those others poorly designed connectors.

Maybe finally we’ll start seeing symmetric connectors, like the good old Cinch connectors or even my earphone’s Jack!

UPDATE: The solution could be very simple as Engadget reports UltraTek provides a solution to that problem with a simple connector.

How Facebook checks your account is not fake (and keeps legitimate users out)

May 13th, 2010

Facebook has been boasting not only the most users for a social networking site, but also the most “quality” users (ie less fake users).

How can Facebook achieve that?

First they’ve been actively purging fake accounts.
More recently they started testing your knowledge of your own friends.
Because everybody knows you know well all your friends on Facebook right?

This feature is disguised as a way to check that your account is not being accessed by an unauthorized person logging from a unrecognized computer.
It happens if you try accessing your account while traveling, and logging from a location you never logged from before.

Not only you will be asked for a Captcha, but Facebook will present you a set of 7 photos where your friends have been tagged, and you will have to recognize them.

You can only skip 2 questions so you better know your friends well, and be lucky enough to be shown photos with an actual face on it.

Especially when they start asking you questions on tagged pictures like those ones:

Try it yourself by logging from a friend’s computer or from a computer abroad and test your knowledge of your friends.
It’s fun, especially when you get yourself locked out of your own account and have to wait one hour to try it again.

Detailed flow

First you’re being asked to enter a Captcha:

Facebook login verification using photo tagging

Then you are tested on your knowledge of your friends’ pictures:

Facebook login verification using photo tagging

It reads:

In order to proceed, Facebook needs to verify that you are the owner of this account. To do this, please identify the people tagged in the following series of photos.
To pass, you cannot get any answers wrong. If you aren’t sure about a question, please skip it. You can only skip two questions.

If you fail, you get this:

Facebook login verification using photo tagging

Please come back in a little while
Your answers were not accurate enough.
For security reasons, you are only allowed to authenticate your identity once every hour. Please come back then to try again. Sorry for the inconvenience.

If you succeed after having failed previously, you will be shown the recent login attempts to review.

Facebook login verification using photo tagging

Please review recent activity on your Facebook account
Your account was recently accessed from a location we’re not familiar with. Please review the activity details below.
If anything looks unfamiliar, we’ll help you change your password (this will help prevent people in the future from accessing you account without permission).
Do you recognize the account activity listed above?

Note the funny wording about preventing people from the future to access your account. Ambiguous. What if I want my future self to access it?

Is it too much?

Although these extensive security measures really do their job of keeping unauthorized persons to access your Facebook account, aren’t they a bit too much?

Wouldn’t a more classical method combining a Captcha and an email with a link to confirm you identity be enough?
Here you have a Captcha, plus a series of 7 pictures with friends tagged.
You cannot make any mistake, you can only skip two questions.
It is overkill for user identification.
Hence the underlying reason behind this flow is more for fake user account determent than really protecting your account from unauthorized logins.

Maybe at some point the only way you will be able to add a friend on Facebook will be to go through 7 random pictures with and without your candidate friend on it and you would have to tell if he is in the picture or not.

This will certainly upset spammers using fake accounts using friends they know nothing about.
But it will also upset those real people having lots of friends because they are just over eager to add more.

We all have one of those friends, don’t we?
You know, those with more than 1,000 friends you always wondered how they know so many people (and they probably don’t).

I’m curious to know how well they would do at the photo tag test.

Facebook rivaling Google by building its own Web Crawler powered by… You!

May 1st, 2010

With Facebook giving the publishers easy ways to mirror their external pages on Facebook, it means it is effectively building the most relevant search engine, the semantic search engine.

And it’s doing that using free labor: viewers of pages who “Like” or “Recommend” a page using the new Like button.

Here is an example of this search engine (using this very article), already available and directly integrated in Facebook, listing all the web pages external to Facebook that users “Liked” in the “Page” section of the results:

On the technical side, you can see Facebook’s crawler in the access log of your HTTP server.
It has the User Agent set to facebookexternalhit/*
Here is an example of Facebook pinging this very article in the access.log of the Apache server:

69.63.178.249 – - [05/May/2010:08:31:40 -0600] “GET /2010/05/facebook-rivaling-google-by-building-its-own-web-crawler-powered-by-you/ HTTP/1.1″ 200 18379 “-” “facebookexternalhit/1.0 (+http://www.facebook.com/externalhit_uatext.php)”

Complex Expensive Mathematical Proprietary Algorithms vs. You

What will the result be?

A search engine more powerful than Google as it will index only real pages that actual users like, and not fake pages.

Google and Bing and all serious search engines in the market must spend millions of dollars building complex automated Web Crawlers that keep surfing around the clock, retrieving pages, following links and crunch each page to extract relevant information based on keywords to index them.

So far, the ranking of your site depends on how this complex algorithm works and classify keywords, with inner workings so obscure and complex it gave birth to a totally new field of Internet technologies: Search Engine Optimization (aka SEO).

Facebook is moving the power from complex obscure and proprietary algorithms to the end users, the only persons who can really tell if a page is worth reading.
Not only Facebook can tell the page is worth indexing, but it can tell what its rank should be, just by looking at the number of people who shared the same page.

Every time you click on a “Like” button, you effectively tell Facebook: here is the address of a page I read and liked, and it’s worth sharing with others.

Facebook is actually building the first successful crowdsourced search engine, and it will be a powerful one with pages chosen by users, getting rid of all the fake websites out there like parked domains and parasite websites that are just exploiting the biggest weakness of search algorithms: they are not human.

Those parasite websites usually do their own web crawling and build pages (sometimes on the fly) using keyword stuffing to lure search engines into thinking their content is relevant in order to achieve higher ranking, then serve lots of ads on the pages to generate revenue from that traffic.
I personally move right away from those websites when I land on them, meaning I will never click a “Like” button if they had one because it’s too obvious they are just copy pasting content from somewhere else.

You can’t lure the human eye so easily and a smaller percentage of people who lands of the parasite pages will actually “Like” them, while a regular search engine would rank them high based on the keywords.

Not to mention the porn sites.
Who will “Like” or “Recommend” a porn webpage with the link being posted directly to their Facebook profile and broadcasted to all their friends in their News Feed?

The raise of Microsoft’s Bing (under the cover of Facebook)

In a way, the “Like” button is how Facebook added a Captcha to all websites so only content worth indexing is being saved for search.
Even more powerful than a Captcha on a webpage, it’s also a Captcha on your brain and morality as users will not reference questionable websites like porn.

Who will benefit from that?
Facebook of course, but also Microsoft’s own search engine, Bing, which so far has been struggling against Google even after Microsoft spent billions of dollars on it.
Don’t forget that Microsoft invested $240M in Facebook back in 2007 (see Facebook’s press release), and they could well be behind Facebook’s strategy to take over the web.

Bing is already omnipresent in Facebook search and it keeps growing.

Facebook Bing Search

At more than a billion clicks per day on the “Like” button, it’s happening really fast.

The consequences are as follow:
- Facebook is referencing a “cleaner” web: it will have an inventory of real pages with less parasite websites referenced and more general audience content
- Bing from Microsoft will benefit directly from this crowdsourced search engine.
- the SEO importance will diminish

Of course people will adapt:
- SEO guys will get on the Facebook bandwagon and their job will be to add a “Like” button to your site (and still charge you a lot for that)
- Parasite websites will have to make their content much nicer to the human eye to fool humans into thinking they have the original content. It probably means that a simple copy of the original content instead of keyword stuffing will do better than a pages belching lots of content gathered from multiples places.
- Google will be (certainly is already) restless and start spending billions to compete with the Microsoft+Facebook alliance.

But don’t forget Google also has its own social network: Orkut.

Could Google’s response rely on finally getting Orkut to take off?
I would start by renaming it to something I don’t have to Google every time for spelling and pronunciation…

While Google will not go away any time soon, the search engine wars is just starting and the key is to make is social.

Administer your ghost pages shared by the new Facebook Like button

April 25th, 2010

——————
Note: Use this post to talk about the Wordpress Facebook Like button plugin
——————

If you’re using THE Facebook Like button plugin (the first one the market and most robust ;-) hosted on Wordpress, you want to be able to administer your pages.

It’s nice to have lots of people like your pages, but it’s even better if you can also send all those Facebook user a message too.
For instance you could post updates about your page, or offer products and services (or advertisement) in a pinpoint accuracy targeted way.

The main revolution Facebook announced at f8 on April 21st is that every legacy web page on the web can now be turned into a Facebook page.

Here is how it works in practice and how to administer your blog pages on Facebook.

You will be able to not only view all the Facebook users who Liked your page, but see statistics and also send all of them messages directly to their Facebook feeds.

Pretty powerful spammy viral tool here.

The First solution if you use Wordpress and the Facebook Like button plugin is to simply configure the plugin by entering your Facebook ID in the Settings page.

It will make an “Admin Page” link appear next to the number of shares you have so far for the page:

Like button with Admin link

And voilà! You’re done. The meta data will be added automatically to the header.

The Second solution, if you don’t use the plugin, or if you use another blogging software or even a standalone website is to add some meta tags in the html header.

Here are the steps to do it manually in Wordpress.

1/ Modify you Wordpress header

Edit your Wordpress header file…

bash# cd ~/wordpress/wp-content/themes/<THE DIRECTORY OF YOUR THEME>/
bash# vi header.php

… by adding HTML tag attributes (very top of the file):

<html xmlns="http://www.w3.org/1999/xhtml"
        xmlns:og="http://opengraphprotocol.org/schema/"
        xmlns:fb="http://www.facebook.com/2008/fbml" <?php language_attributes(); ?>>

… and by adding these meta tags in the header section of the header.php file:

<meta property="fb:admins" content="YOUR OWN FACEBOOK ID"/>
<meta property="og:title" content="<?php the_title_attribute( $args ); ?>" />
<meta property="og:type" content="blog" />
<meta property="og:url" content="<?php echo get_permalink($post->ID); ?> "/>
<meta property="og:image" content="http://blog.bottomlessinc.com/wp-content/uploads/2010/04/logo.jpg" />

Don’t forget to replace “YOUR OWN FACEBOOK ID” with your own numerical Facebook ID.
(example: “68310606562″ if you are Mark Zuckerberg)

Be careful to use the proper Facebook ID as once people start liking your post, you cannot change this ID anymore for security reasons.
You can only append new Facebook IDs (separate them with commas) and cannot replace the original Facebook ID which always has to appear first.
So in the previous example the first Facebook ID will always have to be 68310606562, otherwise Facebook will return this error when trying to like the page:

You previously specified 68310606562 as the leading admininstatory in the ‘fb_admins’ meta tag. The ‘fb_admins’ tag now specifies that 666 is the leading administrator. That needs to be changed back.

Also you can’t remove the Admin ID anymore once it’s been entered, or you will get this error:

Your page no longer includes any admininstrator IDs, even though you’ve specified one before. You must include 68310606562 in the ‘fb_admins’ meta tag, and it must be the very first one if there are many.
Facebook ©2010

Thanks to Tim at Hyperarts for the code.

2/ Administer your Facebook Ghost Pages

Now refresh your page, click on the “Like” button and notice the link to your newly created Facebook admin page as in this screen shot:

Facebook Like Admin Page

Clicking on the “Admin Page” link will redirect you to Facebook, which is only a regular Facebook Page automatically created with the picture specified in your header meta tag as profile picture.

It looks like this:

Facebook Like Admin Page on Facebook

Notice at the top the message in the yellow box confirming your are administrator of the page:

Administer Your Page.

You are seeing this page because you are an administator. All other users are directed to http://blog.bottomlessinc.com/2010/04/creating-a-wordpress-plugin-add-the-new-facebook-like-button-to-your-posts/, but you are being directed here so you can manage your fans and publish stories to your fans’ News Feeds.

(hum, looks like Facebook doesn’t know how to spell administrator).

Facebook provides a list of all the pages you administer in one convenient place.

Facebook is definitely mirroring the whole entire world wide web with these ghost pages that will blossom like mushrooms this spring.

From this Facebook page you can:
- see all Facebook users who Liked your page (formerly known as “Fans”)
- see statistics about the page (“insights”)
- post a message to your page wall

You will then start getting a weekly email update from Facebook listing the statistics of all your the different pages that were created.

For each page you will see:
- number of fans this week and number of total fans (hum, Facebook still calls them “Fans” here, I guess it didn’t sound right to call them “Likers”?)
- Wall Posts, Comments, and Likes this week (and last week)
- visits to your page this week (and visits last week)
- a direct link to Update your fans

Posting a message to your page wall will make your message appear in the Stream of every user who liked your page.

Virality is back (for external website that is, not Facebook applications)

Creating a Wordpress plugin: Add the new Facebook Like button to your posts

April 22nd, 2010

——————
Note: Here is the latest version of the Facebook Like Wordpress Plugin for the impatient (and people not interested in the technical details but just looking for a solution working out of the box).

There is also the Official Wordpress page (from which you should rate the plugin and report it works, thanks).

This blog post is about the process of creating the plugin itself, so if you use the plugin directly you don’t have anything else to do than just installing it.
No coding necessary.
Otherwise you would add things manually and then the plugin would do the same again.
Jump to section 7/ Installation of the plugin if you just want to use the final product working out of the box.
Check also section 8/ Customize the plugin for help on configuring it when installed.
——————

Writing a Wordpress plugin is fairly simple provided you know PHP and follow the well documented process at wordpress.org.

If you’re in a hurry and just want a simple functionality, this guide is what you need.

Here’s a shortened version on how to create a Wordpress plugin that will add the new Facebook “Like” button announced yesterday at f8 to your posts and/or pages.

Facebook new Like button

Simple yet customizable as we’ll still provide a settings page for the plugin.

Facebook new Like button Wordpress plugin settings

1/ Optional Preparation

You can write a plugin and release it without submitting it to the official Wordpress directory.

Submitting your plugin to the Wordpress directory means your plugin must be release under GPLv2, so be aware of that before hand if it bothers you.

Some benefits of submitting to the directory are:
- faster distribution (users can find it easily)
- free SVN hosting
- packaging of the different versions
- access to analytics (number of downloads, …)

If you intend to submit your plugin to the directory, it may be a good idea to first look up which names are available as you may want to name your files and functions according to this name.
Check out the Wordpress plugin SVN to see what’s already taken.

2/ Create the plugin folder

bash# cd ~/wordpress/wp-content/plugins/
bash# mkdir like
bash# cd like/
bash# touch readme.txt
bash# touch tt_like_widget.php

We really need only two files:
- the readme file to describe the plugin,
- the actual code of the plugin in the php file (name it whatever you want).

3/ Write the Readme file

A basic Readme file looks like this:

=== Like ===
Contributors: bottomlessinc
Donate link: http://blog.bottomlessinc.com/
Tags: share, facebook, like, button, social, bookmark, sharing, bookmarking, widget
Requires at least: 2.3
Tested up to: 2.9.2
Stable tag: 1.0

The Facebook Like Button Widget adds a 'Like' button to your Wordpress blog posts.

== Description ==
Let your readers quickly share your content on Facebook with a simple click.

== Installation ==

1. Upload `tt_like_widget.php` to the `/wp-content/plugins/` directory
1. Activate the plugin through the 'Plugins' menu in WordPress
1. (Optional) Customize the plugin in the Settings > Like menu

== Frequently Asked Questions ==

= Is Like free? =

Yes

== PHP Version ==

PHP 5+ is preferred; PHP 4 is supported.

== Changelog ==

= 1.0 =
Stable version

You can get more information on the readme file with this more elaborated example.
Wordpress also provides a readme validator the way W3C does for XHTML validation.

4/ Write the PHP file

Only one function will be called in the file, the init function:

tt_like_init();

It does three main things:
- register and retrieve the parameters of your plugin if you have any (you will be able to set those in the settings page)
- register your own function to be called when an event happens, here an event called ‘the_content’ called every time the content of the post is rendered. Our plugin here will just append some content at the end of the post content.
- register your own function to be called to render the settings page in your Wordpress admin panel so you can customize your plugin.

function tt_like_init()
{
    add_option('tt_like_width', '450');
    add_option('tt_like_layout', 'standard');
    add_option('tt_like_showfaces', 'true');

    $tt_like_settings['width'] = get_option('tt_like_width');
    $tt_like_settings['layout'] = get_option('tt_like_layout');
    $tt_like_settings['showfaces'] = get_option('tt_like_showfaces') === 'true';

    add_filter('the_content', 'tt_like_widget');
    add_filter('admin_menu', 'tt_like_admin_menu');
}

The add_option function is provided by the Wordpress API and registers the default values of your options.
The previously saved setting are retrieved using get_option() and stored in our global variable we named ‘tt_like_settings’.
Our function tt_like_widget() will get called every time the content of the post needs to be rendered as we registered it with the add_filter() function.
In a similar manner, tt_like_admin_menu() will get called to render the settings page in the Wordpress admin interface.

The tt_like_widget() function is pretty straight forward: just append whatever you want to append to the $content variable.

function tt_like_widget($content)
{
     $showfaces = ($tt_like_settings['showfaces']=='true')?"true":"false";
     $url = urlencode(get_permalink()) . "&amp;layout="  . $tt_like_settings['layout']
                                . "&amp;show_faces=" . $showfaces
                                . "&amp;width=" . $tt_like_settings['width'];
     $button = '<iframe src="http://www.facebook.com/plugins/like.php?href='.$url.'" scrolling="no" frameborder="0" allowTransparency="true" style="border:none; overflow:hidden; width:'.$tt_like_settings['width'].'px; height: 50px"></iframe>';
     $content .= $button;
     return $content;
}

Here we build a Facebook Like button which is just an iframe pointing to a Facebook URL having the URL of the current post as parameter.
It means we need to retrieve the URL of the current post dynamically, this is done using get_permalink()
This is also the place we use our settings to produce a Facebook Like button customized according to the settings on the admin page.

And now for the settings on the admin page. We basically build an html form that will record the user preferences.

function tt_plugin_options()
{
    $tt_like_layouts = array('standard', 'button_count');

    <div class="wrap">
    <h2>Facebook Like Button</h2>

    <form method="post" action="options.php">
    <?php
        if (tt_get_wp_version() < 2.7) {
            wp_nonce_field('update-options');
        } else {
            settings_fields('tt_like');
        }
    ?>

    <table class="form-table">
        <tr valign="top">
            <th scope="row"><?php _e("Width:", 'tt_like_trans_domain' ); ?></th>
            <td><input type="text" name="tt_like_width" value="<?php echo get_option('tt_like_width'); ?>" /></td>
        </tr>
        <tr>
            <th scope="row"><?php _e("Layout:", 'tt_like_trans_domain' ); ?></th>
            <td>
                <select name="tt_like_layout">
                <?php
                    $curmenutype = get_option('tt_like_layout');
                    foreach ($tt_like_layouts as $type)
                    {
                        echo "<option value=\"$type\"". ($type == $curmenutype ? " selected":""). ">$type</option>";
                    }
                ?>
                </select>
        </tr>
        <tr>
            <th scope="row"><?php _e("Show faces:", 'tt_like_trans_domain' ); ?></th>
            <td><input type="checkbox" name="tt_like_showfaces" value="true" <?php echo (get_option('tt_like_showfaces') == 'true' ? 'checked' : ''); ?>/></td>
        </tr>
    </table>

     <?php if (tt_get_wp_version() < 2.7) : ?>
       <input type="hidden" name="action" value="update" />
       <input type="hidden" name="page_options" value="tt_like_width, tt_like_layout, tt_like_verb, tt_like_colorscheme, tt_like_showfaces"/>
    <?php endif; ?>

    <p class="submit">
    <input type="submit" name="Submit" value="<?php _e('Save Changes') ?>" />
    </p>

    </form>
    </div>
}

Here we have some code for an input box, a dropdown menu and a checkbox as example.
There is some handling for earlier version of Wordpress.
Refer to the options page help for further information.
The _e() function is here for internationalization.

5/ Submit your plugin to the Wordpress directory

Submit your new plugin to the directory by providing a unique name for it.

You will then be able to upload it to the SVN repository.

6/ Check in your code in the SVN repository

After Wordpress approves your plugin (it took 3 days for this one), you can check your code in the provided SVN link.

bash# mkdir ~/my_wp_plugin
bash# cd ~/my_wp_plugin
bash# svn co http://svn.wp-plugins.org/like
A    like/trunk
A    like/branches
A    like/tags
Checked out revision 233010.
bash# cp ~/wordpress/wp-content/plugins/like/readme.txt trunk/
bash# cp ~/wordpress/wp-content/plugins/like/tt_like_widget.php trunk/
bash# svn add trunk/*
A         trunk/readme.txt
A         trunk/tt_like_widget.php
bash# svn ci -m "First stable version"
Authentication realm: <http://svn.wp-plugins.org:80> WordPress.org Subversion
Username: bottomlessinc
Password for 'bottomlessinc': ****
Adding         trunk/readme.txt
Adding         trunk/tt_like_widget.php
Transmitting file data ..
Committed revision 233012.
bash#

Now you can tag the revision of the plugin as your first version.

bash# svn cp trunk tags/1.0
A         tags/1.0
bash# svn ci -m "Tagging v1.0"
Adding         tags/1.0
Adding         tags/1.0/readme.txt
Adding         tags/1.0/tt_like_widget.php
Committed revision 233013.
bash#

Now that your code is checked in with the mandatory readme.txt file and you tagged the version 1.0 of your SVN to match the Stable tag: 1.0 in readme.txt, Wordpress will do all the rest and package it for you.

It will be available to a URL resembling http://wordpress.org/extend/plugins/like making it accessible to all Wordpress user and providing you download statistics and feedbacks from users.

You can also promote your plugin further by submitting it to wp-plugins.

7/ Installation of the plugin

Here is the complete code for the widget:

Facebook Like Wordpress Plugin (Latest Version)

Unzip it in your plugin directory.

bash# cd ~/wordpress/wp-content/plugins/
bash# wget http://blog.bottomlessinc.com/wp-content/uploads/2010/04/like.zip
bash# unzip like.zip

Then go to the Wordpress admin dashboard, activate it, and optionally customize it in the settings page.

8/ Customize the plugin

The plugin works out of the box without configuration as it uses the IFRAME version of the button.

Optionally you can use the XFBML version but it requires more setup and a better knowledge of the Facebook platform as you will need to create a Facebook Application and enter its App ID in the settings page of the plugin.

Which one to choose, IFRAME or XFBML?

It really depends on how technical you are.
If you are not, stick with the default settings using the IFRAME version.
If you are technical you can venture in the XFBML version, but even there you will hit snags as Facebook is notorious for producing unstable Javascript and not getting things to work the first time (a daily struggle when you develop Facebook applications).

With XFBML, the user who clicked the Like button can add a comment that will be attached to the post on his profile.

Facebook XFBML Like button comment

The benefit of using XFBML is purely real estate: provided the user not only clicks the button but adds a comment, the profile post will now include the image you entered in the Settings of the plugin along with an excerpt of the article.

For comparison here is the one liner you will see if using IFRAME or if using XFBML when the user did not add a comment…:
Facebook Like button wallpost IFRAME

… and here is the profile post the user will generate when adding a comment with the XFBML version of the button:
Facebook Like button wallpost XFBML

Even though Facebook provides a simplified interface to generate a new Application, it doesn’t work right away.

When I first set it up I had this message when clicking the button:

The application ID specified within the “fb:app_id” meta tag is not allowed on this domain. You must setup the Connect Base Domains for your application to include this domain.
Facebook ©2010

When editing the settings of the Application itself, I couldn’t see anything wrong, and hit the “Save Changes” button without modifying anything.
Surprisingly it raised this error, refusing to save the (non existing) changes:

Validation failed.

Connect URL must point to a directory (i.e., end with a “/”) or a dynamic page (i.e., have a “?” somewhere).

In this case just edit the Application, go to the “Connect” tab and in the first field called “Connect URL”, make sure your website ends with a forward slash.
For instance I had to manually change my Facebook Connect URL from “http://bottomlessinc.com” to “http://bottomlessinc.com/” to make things work.

And even after that, when using the XFBML version the button doesn’t show up in around 20% of the page refresh.
That’s why sticking with the default IFRAME version is more reliable.

There is also a chance that adding a slash to your Connect URL will solve the problem of the Like button blinking (showing up as pressed then right away as unpressed).
During this blinking of the button you can see the message “You like http://example.com” which disappears also right away.

If you use the XFBML version of the plugin, you must provide the numerical Facebook ID of the Facebook user you will use to manage the pages.
Otherwise people clicking on the Like button will receive this error:

You failed to provide a valid list of administators. You need to supply the administors using either a “fb:app_id” meta tag, or using a “fb:admins” meta tag to specify a comma-delimited list of Facebook users.

Did you find this post useful? Like it on Facebook :-) and Spare a few cents:

Facebook throttling the last viral channel

March 24th, 2010

Up until today, there was still one viral channel left on Facebook that allowed your applications to grow organically: the wall posts.

Today Facebook cracked down on it as explained in their developer blog.

The consequences are amazing as you can see the overnight 50% drop in DAUs for quiz applications that relied heavily on wall posts like Social Interview (graphs courtesy of developeranalytics.com):
Social Interview DAUs down 50 percent

So from a canvas application you can still publish stories to walls, but you now have to ask the user each and every time to confirm with the “Publish this story to your friend’s Facebook Wall?” popup like this one:

Before you could let the user choose not to have this popup every time they want to post something on a wall by using the Facebook.showPermissionDialog() javascript call…:

Facebook.showPermissionDialog('publish_stream', callback);

function callback (perms) {
  if (!perms) {
    message('You did not grant the special permission to post to friends wall without being prompted.');
  } else {
    message('You can now publish to walls without being prompted.');
  }
}

… that would prompt for your permission to, hem, not be prompted when publishing a story to a wall (“Allow {Application X} to publish posts or comments without prompting me.”):

Once you had this permission granted by your user, you could just call streamPublish() with the auto_publish parameter set to true to avoid the popup:

Facebook.streamPublish(null, attachment, actionLinks, target_id, "Add a personal message", callback, true);

In practice it didn’t quite work because even though the language in the permission dialog is clear that you would not see any popup anymore, you would still either:
- get the popup all the time (and that was a Facebook bug)
- or reach a throttling limit (streamPublish() would return “Feed action request limit reached”) and would not be able to post anymore.

Facebook is very obscure on what the limits are, contrary to the requests limits which you can see from the Statistics of your application in the Developer app (tab “Allocations”).

So you had to use a trick to circumvent this throttling by asking for a totally unrelated permission: the Offline permission.

Facebook.showPermissionDialog('offline_access', callback);

That would ask the user for yet another permission using the “Allow Constant Authorization.” popup:

This workaround worked well until today, as you now get a lot more “Feed action request limit reached” errors.
So much more that Facebook added an extra tab in the Statistics of your application called “API Errors”:

What’s remaining now for virality on Facebook?
- the notifications are gone
- the invites are throttled in an obscure way so you never see your allocation of invites per user per day go up
- the wallposts are throttled
- … but you now have access to users emails!

This is a clear move from Facebook to capture more revenues by forcing developers to buy ads from them.

The true organic virality is gone, unless developers become spammers and start hammering the email addresses of Facebook users.
This will happen unfortunately, and users will just opt-out, so it’s a short lived solution.

Is it time to move back to MySpace?

InnoDB engine disabled when specifying a buffer pool size too high

March 12th, 2010

The InnoDB engine will (silently) not start if innodb_buffer_pool_size too big.

You modified your my.cnf to increase the performance of your DB by tweaking the InnoDB variables.
Then you restarted MySQL for the changes to take effect, everything seems fine, no error message.

Except your InnoDB tables are no longer working.

mysql> SELECT VERSION();
+-----------------------+
| VERSION()             |
+-----------------------+
| 5.1.37-1ubuntu5.1-log |
+-----------------------+
1 row in set (0.00 sec)

mysql>
mysql> SHOW CREATE TABLE users;
ERROR 1286 (42000): Unknown table engine 'InnoDB'
mysql>

You can’t believe your eyes and start double checking for confirmation:

mysql> SHOW VARIABLES LIKE 'have_innodb';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| have_innodb   | NO    |
+---------------+-------+
1 row in set (0.00 sec)
mysql>
mysql> SHOW ENGINES \G
*************************** 1. row ***************************
      Engine: MyISAM
     Support: DEFAULT
     Comment: Default engine as of MySQL 3.23 with great performance
Transactions: NO
          XA: NO
  Savepoints: NO
*************************** 2. row ***************************
      Engine: MRG_MYISAM
     Support: YES
     Comment: Collection of identical MyISAM tables
Transactions: NO
          XA: NO
  Savepoints: NO
*************************** 3. row ***************************
      Engine: BLACKHOLE
     Support: YES
     Comment: /dev/null storage engine (anything you write to it disappears)
Transactions: NO
          XA: NO
  Savepoints: NO
*************************** 4. row ***************************
      Engine: CSV
     Support: YES
     Comment: CSV storage engine
Transactions: NO
          XA: NO
  Savepoints: NO
*************************** 5. row ***************************
      Engine: MEMORY
     Support: YES
     Comment: Hash based, stored in memory, useful for temporary tables
Transactions: NO
          XA: NO
  Savepoints: NO
*************************** 6. row ***************************
      Engine: FEDERATED
     Support: NO
     Comment: Federated MySQL storage engine
Transactions: NULL
          XA: NULL
  Savepoints: NULL
*************************** 7. row ***************************
      Engine: ARCHIVE
     Support: YES
     Comment: Archive storage engine
Transactions: NO
          XA: NO
  Savepoints: NO
7 rows in set (0.00 sec)

mysql>

Yep, InnoDB is definitely gone.

If you try to create an InnoDB table unfortunately the command will not fail:
MySQL will create a MyISAM table behind your back without telling you it couldn’t create an InnoDB table. Ouch.

Examining your /etc/mysql/my.cnf and you see you typed some extra zeros:

innodb_buffer_pool_size=10000M

Probably you were thinking assigning 1G to the buffer pool when in fact it was 10GB, and your server only has 2GB of memory.
Change that to:

innodb_buffer_pool_size=1000M

Restart MySQL and you get your InnoDB tables working again.

mysql> SHOW VARIABLES LIKE 'have_innodb';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| have_innodb   | YES   |
+---------------+-------+
1 row in set (0.00 sec)

mysql>

It’s amazing but MySQL will actually not complain about a value too high when you restart it.
It looked like this to me when the value was too high:

bash# /etc/init.d/mysql restart
 * Stopping MySQL database server mysqld    [ OK ]
 * Starting MySQL database server mysqld    [ OK ]
 * Checking for corrupt, not cleanly closed and upgrade needing tables.
bash#

On an Amazon EC2 Standard Default Small Instance running Ubuntu server, I was surprised to find the limit is very low.
It’s a 32-bit platform with 1.7 GB of memory, 1 EC2 Compute Unit (1 virtual core with 1 EC2 Compute Unit), and 160 GB of local instance storage.

InnoDB could not start when innodb_buffer_pool_size was set to 512M.
However it worked with 256M.

Enabling Memcached on BlueHost

March 11th, 2010

Bluehost is a pretty good web hosting company, cheap and leaving you in total control of your website.
That is if you know your way around.
I highly recommend them for dirt cheap hosting yet access to powerful features.

A common complaint against any cheap hosting is the lack of memcached installation by default.
It really doesn’t make sense even business-wise for them because memcached would allow to use less CPU/Memory per site hosted, meaning less total servers, meaning less power drawn, meaning big savings.
The hosting plans charging usually a fixed amount per month or year, reducing CPU/Memory/Servers would really make sense as the savings would be on directly on them.

Anyway, now we need to setup memcached ourselves on a machine we don’t have root access to.
No big deal, we will just have to compile everything ourselves.

Here’s how.

1/ Create an installation folder.

As we cannot write to /usr/, we cannot install any software system wide, so everything will remain local in our home folder.
Let’s call it ~/install/
It will be where you install all your compiled software, acting like the /usr/ folder we don’t have access to.

bash# mkdir ~/install

2/ Compile libevent

Why libevent? Because we will need it later to compile memcached.

bash# wget http://www.monkey.org/~provos/libevent-1.4.13-stable.tar.gz
bash# tar zxf libevent-1.4.13-stable.tar.gz
bash# cd libevent-1.4.13-stable
bash# ./configure -prefix=~/install/
bash# make
bash# make install

libevent is now neatly installed in our home directory at ~/install/

3/ Compile memcached

bash# wget http://memcached.googlecode.com/files/memcached-1.4.4.tar.gz
bash# tar xzf memcached-1.4.4.tar.gz
bash# cd memcached-1.4.4
bash# ./configure --with-libevent=~/install/ --prefix=~/install/
bash# make
bash# make install

Neat, now we have memcached installed in ~/install/bin/, so let’s try to run it.

bash# cd ~/install/bin
bash# ./memcached
failed to set rlimit for open files. Try running as root or requesting smaller maxconns value.
bash# ./memcached -c 100
^CSIGINT handled
bash#

So we hit a limitation: as we’re not root, our memcached server is limited to only 100 connections instead of the default 1024.
Maybe we can live with that.

Now the server part is done, we need to be able to use the PHP commands to communicate with memcached.
This is found in the PEAR packages.

4/ Install the PHP memcache client

(the memcache client doesn’t have the ‘d’ at the end)

bash# pecl install memcache
downloading memcache-2.2.5.tgz ...
Starting to download memcache-2.2.5.tgz (35,981 bytes)
..........done: 35,981 bytes
11 source files, building
running: phpize
Configuring for:
PHP Api Version:         20041225
Zend Module Api No:      20060613
Zend Extension Api No:   220060519
Enable memcache session handler support? [yes] :
Notice: Use of undefined constant STDIN - assumed 'STDIN' in CLI.php on line 304

Warning: fgets(): supplied argument is not a valid stream resource in CLI.php on line 304

Warning: fgets(): supplied argument is not a valid stream resource in /root/lib/php/PEAR/Frontend/CLI.php on line 304
building in /usr/local/src/pear/pear-build-bottoml8/memcache-2.2.5
ERROR: could not create build dir: /usr/local/src/pear/pear-build-bottoml8/memcache-2.2.5

Ouch, we’re not root so pecl fails.
No big deal: pecl already downloaded memcache-2.2.5.tgz for us, let’s compile it manually.

bash# tar xzf memcache-2.2.5.tgz
bash# cd memcache-2.2.5
bash# phpize
bash# ./configure --prefix=~/install/
bash# make
bash# make test
bash# make install
Installing shared extensions:     /usr/lib/php/extensions/no-debug-non-zts-20060613/
cp: cannot create regular file `/usr/lib/php/extensions/no-debug-non-zts-20060613/#INST@7000#': Read-only file system
make: *** [install-modules] Error 1
bash#
bash# ls modules/
./  ../  memcache.so*
bash# cp memcache.so ~/install/lib/

Ok, make install failed, but we have already what we need: memcache.so in the memcache-2.2.5/modules/ directory.
It’s the extension we need to load in PHP (in the php.ini file) so we can use the PHP commands to access memcached.
We just moved it to ~/install/lib/ so it’s comfy with the other libraries we compiled earlier (libevent and memcached).

5/ Load the memcache module for PHP

Now for the tricky part:
As we don’t have root access, we cannot just change the server’s php.ini file to include our freshly brewed memcache.so and restart Apache to make the changes taken into account.

But Bluehost provides us with a neat way to use our own php.ini file.
By default this option is disabled.
In their cPanel it’s listed under the category ‘Software / Services’ as ‘PHP Config’.

By default the setting is Standard PHP5, we need to change that to the third option: PHP5 (FastCGI)
It will directly load the php.ini it finds in your ~/public_html/ directory.

On this same page of the cPanel, there’s an interesting button “INSTALL PHP.INI MASTER FILE”.
Just click it and magically the server’s php.ini file is copied in ~/public_html/php.ini.default

It’s now our base php.ini we’ll use to load memcache. Let’s edit it.

bash# cd ~/public_html/
bash# mv php.ini.default php.ini
bash# vi php.ini

In php.ini, find the line that reads:
extension_dir = “/usr/local/lib/php/extensions/no-debug-non-zts-20060613″
and replace it with
extension_dir = “/home/your_bluehost_user_name/install/lib”
so that we have access to our memcache.so lib.
At the end if php.ini, before the last line that loads the Zend Optimizer, include this line to load memcache.so:
extension=memcache.so

There should be some other libraries being loaded here:
;extension=pdo.so
;extension=pdo_sqlite.so
;extension=sqlite.so
;extension=pdo_mysql.so

As we changed the extension_dir path these libraries are not accessible anymore so you can just comment them.
extension_dir does not support listing multiple directories so I wish we didn’t have to do that.
At some point there was a proposal to make it happen, don’t know if it’s implemented yet, I couldn’t find anything about it.
Worst case scenario if you need PDO (and you probably do), you just need to compile it and install it in ~/install/lib/

Now that php.ini is modified, the server will pick up the configuration automagically.
But you may have to wait a little bit as php.ini will not be read again right away, you have to wait for the next poll, a few minutes.

6/ Let’s use memcached!

Now everything’s installed, let’s finally use memcached.

Create a memcache.php test file that will connect to memcached and just return the server version:

<?php
$memcache = new Memcache;
$memcache->addServer('localhost', 11211);
$memcache->connect('localhost', 11211);

echo $memcache->getVersion();
?>

Start the memcached in verbose mode so we can see our connection arriving:

bash# cd ~/install/bin/
bash#  ./memcached -h
memcached 1.4.4
-p <num>      TCP port number to listen on (default: 11211)
-U <num>      UDP port number to listen on (default: 11211, 0 is off)
-s <file>     UNIX socket path to listen on (disables network support)
-a <mask>     access mask for UNIX socket, in octal (default: 0700)
-l <ip_addr>  interface to listen on (default: INADDR_ANY, all addresses)
-d            run as a daemon
-r            maximize core file limit
-u <username> assume identity of <username> (only when run as root)
-m <num>      max memory to use for items in megabytes (default: 64 MB)
-M            return error on memory exhausted (rather than removing items)
-c <num>      max simultaneous connections (default: 1024)
-k            lock down all paged memory.  Note that there is a
              limit on how much memory you may lock.  Trying to
              allocate more than that would fail, so be sure you
              set the limit correctly for the user you started
              the daemon with (not for -u <username> user;
              under sh this is done with 'ulimit -S -l NUM_KB').
-v            verbose (print errors/warnings while in event loop)
-vv           very verbose (also print client commands/reponses)
-vvv          extremely verbose (also print internal state transitions)
-h            print this help and exit
-i            print memcached and libevent license
-P <file>     save PID in <file>, only used with -d option
-f <factor>   chunk size growth factor (default: 1.25)
-n <bytes>    minimum space allocated for key+value+flags (default: 48)
-L            Try to use large memory pages (if available). Increasing
              the memory page size could reduce the number of TLB misses
              and improve the performance. In order to get large pages
              from the OS, memcached will allocate the total item-cache
              in one large chunk.
-D <char>     Use <char> as the delimiter between key prefixes and IDs.
              This is used for per-prefix stats reporting. The default is
              ":" (colon). If this option is specified, stats collection
              is turned on automatically; if not, then it may be turned on
              by sending the "stats detail on" command to the server.
-t <num>      number of threads to use (default: 4)
-R            Maximum number of requests per event, limits the number of
              requests process for a given connection to prevent
              starvation (default: 20)
-C            Disable use of CAS
-b            Set the backlog queue limit (default: 1024)
-B            Binding protocol - one of ascii, binary, or auto (default)
-I            Override the size of each slab page. Adjusts max item size
              (default: 1mb, min: 1k, max: 128m)
bash#
bash# ./memcached -c 100 -vvv -l 127.0.0.1
slab class   1: chunk size        96 perslab   10922
slab class   2: chunk size       120 perslab    8738
slab class   3: chunk size       152 perslab    6898
slab class   4: chunk size       192 perslab    5461
...
slab class  40: chunk size    616944 perslab       1
slab class  41: chunk size    771184 perslab       1
slab class  42: chunk size   1048576 perslab       1
<26 server listening (auto-negotiate)
<27 send buffer was 124928, now 268435456
<27 server listening (udp)

---- Access the memcache.php file here in your browser ----

<28 new auto-negotiating client connection
<29 new auto-negotiating client connection
29: going from conn_new_cmd to conn_waiting
29: going from conn_waiting to conn_read
29: going from conn_read to conn_parse_cmd
29: Client using the ascii protocol
<29 version
>29 VERSION 1.4.4
29: going from conn_parse_cmd to conn_write
29: going from conn_write to conn_new_cmd
29: going from conn_new_cmd to conn_waiting
29: going from conn_waiting to conn_read
28: going from conn_new_cmd to conn_waiting
28: going from conn_waiting to conn_read
28: going from conn_read to conn_closing
<28 connection closed.

Tada! And magically the browser is displaying a magnificent “1.4.4“.

You got yourself a memcached server running on BlueHost.

Did you find this post useful? Buy this man a beer:

Setting up MySQL replication

March 10th, 2010

In this article the Master is 200.126.187.013 and the Slave is 200.126.187.066

On the Master, edit /etc/mysql/my.cnf:

server-id        = 126187013  # choose a unique integer
log_bin          = /var/log/mysql/mysql-bin.log
bind-address   = 0.0.0.0  # listen on all interfaces (by default 127.0.0.1 is used)
binlog_do_db   = mydb    # replicate only the 'mydb' database

Test your new configuration for syntax error:

bash# mysqld --help

Make sure the skip-networking option is not enabled.
Make sure server-id is unique. You can for instance use the last 3 octets of the IP address of the server.

Create a replication user on the Master using the IP address of the Slave that will access it (200.126.187.66):

mysql> select version();
+-------------------+
| version()         |
+-------------------+
| 5.1.37-1ubuntu5.1 |
+-------------------+
1 row in set (0.00 sec)
mysql> CREATE USER 'replication'@'200.126.187.66' IDENTIFIED BY 'slavepass';
mysql> GRANT REPLICATION SLAVE ON mydb.users TO 'replication'@'200.126.187.66';
mysql> GRANT SELECT ON mydb.users TO replication;

Restart MySQL for the changes to take effect:

bash# /etc/init.d/mysql restart

On the Slave, edit /etc/mysql/my.cnf to set the server-id:

server-id  = 126187066    # choose a unique integer

Copy the current database on the Master with mysqldump and load it on the Slave.

Check the current status of the Master by retrieving its log file name and position:

mysql> SHOW MASTER STATUS;
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000003 |    23577 | mydb         |                  |
+------------------+----------+--------------+------------------+
1 row in set (0.00 sec)
mysql>

Start the replication on the Slave.

mysql> CHANGE MASTER TO MASTER_HOST='200.126.187.013', MASTER_USER='replication', MASTER_PASSWORD='slavepass', MASTER_LOG_FILE='mysql-bin.000003', MASTER_LOG_POS=0;
mysql> START SLAVE;

We did take some shortcuts here: the proper way would have been to:
1/ prevent the Master from committing anything
2/ backup the DB on the Master
3/ check the log file name and log position on the Master (‘SHOW MASTER STATUS’)
4/ load the backup on the Slave
5/ start replication using the log file name and position on the Master
6/ unlock the Master so the commits can happen again

A nightmare if the Master is already a live production server because it means from step 1/ to 6/ the Master is dead not committing anything.

As we did a ‘dirty’ backup, the replication will bump into errors that will stop the Slave (mainly because of entries already on the Slave, so we can safely skip them).
List them on the Slave with ’show slave status \G’ (look at the ‘Last_Error’) and if you can skip it, do it this way:

mysql> SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1;
mysql> START SLAVE;

Continue skipping the failed insert (if they can be skipped of course) until the slave completely catches up with the Master.

How do I know when the Slave is done catching up with the Master?

Issue a ‘SHOW SLAVE STATUS’ on the Slave:

mysql> SHOW SLAVE STATUS \G
*************************** 1. row ***************************
             Slave_IO_State: Waiting for master to send event
                Master_Host: 200.126.187.013
                Master_User: replication
                Master_Port: 3306
              Connect_Retry: 60
            Master_Log_File: mysql-bin.000003
        Read_Master_Log_Pos: 339528
             Relay_Log_File: prod1-relay-bin.000004
              Relay_Log_Pos: 339665
      Relay_Master_Log_File: mysql-bin.000003
           Slave_IO_Running: Yes
          Slave_SQL_Running: Yes
            Replicate_Do_DB:
        Replicate_Ignore_DB:
         Replicate_Do_Table:
     Replicate_Ignore_Table:
    Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
                 Last_Errno: 0
                 Last_Error:
               Skip_Counter: 0
        Exec_Master_Log_Pos: 339528
            Relay_Log_Space: 339665
            Until_Condition: None
             Until_Log_File:
              Until_Log_Pos: 0
         Master_SSL_Allowed: No
         Master_SSL_CA_File:
         Master_SSL_CA_Path:
            Master_SSL_Cert:
          Master_SSL_Cipher:
             Master_SSL_Key:
      Seconds_Behind_Master: 0
1 row in set (0.00 sec)

mysql>

You can see everything is fine because:
- ‘Seconds Behind Master’ reports 0, so the Slave is done catching up (it’s in sync with the Master)
- Both Slave IO and Slave SQL are running
- The Slave is just waiting for new data to come in: ‘Waiting for master to send event’

Source

Changing the timezone on a Ubuntu server

March 10th, 2010
bash# sudo dpkg-reconfigure tzdata

Then just follow the instructions on the screen to select your time zone.

While we’re at it, let’s sync the time with the atomic clock:

bash# sudo ntpdate pool.ntp.org
10 Mar 09:55:19 ntpdate[23121]: adjust time server 173.8.198.243 offset -0.009830 sec