Hackdays, Gesture Control, Drones and Minority Report

On Slideshare’s 7th birthday, the engineers at Slideshare were treated to Slideshare’s special treat: the Internal Hackday. If you have been anywhere near Slideshare’s Hackdays before, you know that they are a breed of their own. There are people pulling all nighters, there are others struggling to, but succumbing to fatigue and sleep. There are people who lock themselves in a conf room and yell at anyone who tries to feed them food. And there are those who like to walk around dispensing product advice. But one thing is for sure, you know something is up when you look at the haggard, unkempt bunch with a frenzy in their eyes. Plus the sales at the cigarette shop at the corner goes up as worried geeks pace puffing anxiously. What I am trying to say is that the energy at these Hackdays has to be seen to be believed. This one was the same as teams began their pre Hackday brainstorming, shortlisting ideas and discarding them before finally settling on one they thought would win them the prizes.

I have been in a few of Slideshare’s hackdays before and decided another one with a script/server wasn’t going to be fun. Decided I wanted to do something different. A few ideas later, i began to tend towards getting an ARDrone for this hack. The fact that I encountered demos at both rubyconf and jsfoo about the ARDrone probably helped. Also, the past year has seen much more support in various language for the ARDrone. Add to it the fact that the past few months had been colleague after colleague unboxing LeapMotion devices and it doesn’t take long for a nerd’s mind to make the leap. I named the project ‘Minority Report’, pulled up the submission form and signed on the dotted line.

While I had grand plans to have the ARDrone detect faces, recognize people and shoot nerf ammo at them, the reality of a two day hackday meant that I had to trim it down a much leaner and sweeter MVP.

As the gong rang, I lugged my ARDrone into the office and the surprise on my colleagues’s faces set the mood for the hackday. The fact that they were worried about competing with something that made them drool made it all the more fun. I spent an hour playing with it and amusing them (boys will be boys eh?) and then settled down to code.

Turns out that writing coding to interface with real life devices has its own unique challenges. Who imagined that I would have to go get a muscle relaxant spray after a couple of hours because my shoulder began to ache painfully because of me holding my arm over the LeapMotion? Or that you always had to be prepared to duck when the drone was a meter away? Or that you had to factor in an hours recharge time after a 15 minute flight? Or that you had to include a safety instruction slide in your demo pitch so that people knew what to do if you drone decided to fly into them?

Well, as I said, interesting. And tough. I had initially wanted to use opencv for face detection and facial recognition, but turns out what you want to do and what you can get done are two different things entirely. After struggling a few hours with compile flags, 32bit vs 64bit compile modes and commenting out lines .h files I decided that trying to compile opencv at 3 am in the morning while still working through the actual product’s ruby code the next day wasn’t going to be practical. Time to fall back to plan B.

The hack started off well as getting gesture information into the ruby program was simple. The setup was quick and the packaged software was reliable and smooth. The problem however, was sensitivity. The LeapMotion is sensitive, let me tell you. Since it can detect a few predefined gestures, i had initially planned to hook into Leapmotion’s swipe gestures to control the drone. A few minutes of swiping later, it was obvious that it wasn’t going to cut it. For one, getting the gestures right was difficult. If your gestures aren’t smooth enough, LeapMotion doesn’t pick it up. Or you swipe up and you bring your hand back down to swipe up again, LeapMotion detects a swipe down gesture as well. You don’t really want to be struggling with your LeapMotion gestures when your drone has decided to careen towards the demo audience, right? So I settled for the hand objects that LeapMotion provided data about and wrote my own gesture detection code with gestures thresholds and so forth.

Once I had a decent setup going for how to control the drone, I hooked the drone up. Worth knowing that the setup for the drone is a bit tricky. You need to connect to the Ardrone’s wifi network. Since it is on udp, you can’t really be sure your drone is receiving your signals. In any case, coding the drone was fairly simple. I tried using artoo-ardrone, but finally settled on using argus directly. The drone has a bit of a lag from the time you give it a command to when it actually executes it. Just a second or so, but it is obvious and is a bit disorienting when you are waving your hands about trying to get it to stay away from a wall. Again, one of those things about the real world.

drone on table 2

The drone’s battery also runs only for about 15 minutes and has to be recharged for an hour. I should probably have gotten some spare batteries. Would have been able to test out the program in much more detail.

It took a few hours to get the code right, add in the necessary checks to ensure that the program would not crash due to a wrong gesture or any of the obvious edge cases and then it was time to write something relevant to the hackday host. The camera seemed interesting so I set up some code to pick up some image frames from the video feed and upload it to slideshare. Here are a few of those slides. Hack done! Time to make the presentation and finally demo it.

vishu drone photo

IMAG0280

The demo was great. We cleaned out a large area towards the front, and set the drone on a disassembed table tennis table. A few safety slides later, the drone was up. The audience actually enjoyed the demo. Turned out to be one of those cool hacks and when the judges asked what the audience though would with the first prize, the unanimous vote was for the drone. But since it didn’t really have much to do with slideshare itself, the judges had to pass. Here is a demo of the hack

I probably need to spend some time cleaning up the code a little bit and working on the face detection part. Maybe in a week or so. Feel free to look at the code over at Github. And do check out the official blog post on the hackday.

Track custom time events using Google Analytics – Site speed user timings

Newrelic is an awesome tool for RUM. Unfortunately it does not allow you to instrument custom frontend events. As an example, Newrelic gives you information about time to first byte, and page load. However, what if you want to track the time async loading of a particular script file took, for example, you would be stuck.

Instead, User Timings is a not so widely used mechanism to track custom events. You can track when your script finally finishes loading, how much time a user spends doing something and other time periods. You can then view distribution by geoghraphy, by browser and even view the time buckets these events fall under. Cool stuff!

 

The year so far

I haven’t blogged in quite a long time. In fact I haven’t blogged since I joined Slideshare at all (except for the speakmyname post). However, this is one of those days when you take stock of how the past few months have been and reminisce, particularly since you have a few days away from work for Christmas and the New Year. Disappointingly the world didn’t end yesterday and I have to continue with my life.

So here is how it has been in the past few years

  1. I joined Slideshare, now a part of Linkedin. Got in through the interviews and all and remember thinking, this is going to be crazy. It was scarily exciting when I joined. Still is. Never a day when what you expect of the day actually happens. One challenge solved and a couple more crop up. Funnily enough, everyone seems to be tackling exciting problems of their own. Shaving off a few seconds in database polling time by moving to Queues. Machine Learning for Spam Detection. Garbage collection issues in Solr. Collaborative recommendations. And many more. Makes you jealous and want to switch to a different team every day.
  2. Hackdays, hack days and more hack days – The first hack day was scary. My first thought was ‘omg, how are people going to judge me’. Would I be able to do justice to the hack. Turns out thats not the biggest challenge. The game is in delivering. That sets you apart from those you don’t and you are halfway though. Funnily enough I never won the first prize in any of the internal hack days (I participated in 3). But since the judges make it clear that they are evaluating hacks as any investor would, I guess I should have shaved for the demo ;) Still, nothing matches the craziness and fun of a sleepless few nights followed by nerve wracking demos. Since slideshare is now a part of Linkedin, we now have Indays. And then there was the Yahoo Open Hack 2012. A fun and tiring 36 hours of adrenaline fueled coding ending with bookmafia (stay tuned). Did I mention I spend another all-nighter with the Developher hack day teams ending with me all cranky by the time the final demoes ended. @beachbrake and @chefschatter and abhineet won the second prize so it ended with me borrowing their prize iPads for a while so it was great.
  3. Dizzying razzle dazzle – A few moments that stand out in these years
    • Refactored over 2k lines of JS in a couple of weeks and found it surprisingly worked fine on IE7 as well. I still savor that
    • The moment when I patched a ruby gem and fixed a bug. Was too shy to send a pull request though. And can’t find the change I made anymore.
    • The day before the html5 launch at slideshare when I found that slides after a certain number wouldn’t be styled properly in the javascript player That took a while to understand and lead to some under the breath swearing at all things microsoft.
    • Frond end performance stuff. Where milliseconds matter and its is all about network latency, parsing, async loading, caching, compression and page speed scores. Add process queues, web workers, automated jslint checks, jasmine tests, webpagetest.org scores to the mix and my thoughts are all about browsers at the moment. A bunch of jumbled thoughts with me wishing traffic from IE8 would go down. Which I struggle to communicate via words when asked about updates by the result oriented. ;)
    • Push out fixes for security vulnerabilities reported by users in hours, push out a ad disabling feature in a day when adsense warns about shutting you down, design and implement a user mapping store which two services with millions of users are going to use in a week,
    • Start out with a macbook at work, get upgraded to a macbook pro a year later, and then a macbook air a year later. Miss the macbook pro a lot.

It has been a fun year and come to think of it, I am happy it wasn’t doomsday after all!

gem install mysql failing with checking for mysql_query() in -lmysqlclient… no

Aside

If you run into an error similar to the follow while attempting to install mysql gem on OSX Lion

sudo gem install -V mysql -v '2.8.1'
GET http://rubygems.org/specs.4.8.gz
302 Moved Temporarily
-- snipped --
Installing gem mysql-2.8.1
/Library/Ruby/Gems/1.8/gems/mysql-2.8.1/COPYING
-- snipped --
Building native extensions.  This could take a while...
ERROR:  Error installing mysql:
	ERROR: Failed to build gem native extension.

/System/Library/Frameworks/Ruby.framework/Versions/
1.8/usr/bin/ruby extconf.rb
checking for mysql_query() in -lmysqlclient... no
checking for main() in -lm... yes
checking for mysql_query() in -lmysqlclient... no
checking for main() in -lz... yes
checking for mysql_query() in -lmysqlclient... no
checking for main() in -lsocket... no
checking for mysql_query() in -lmysqlclient... no
checking for main() in -lnsl... no
checking for mysql_query() in -lmysqlclient... no
checking for main() in -lmygcc... no
checking for mysql_query() in -lmysqlclient... no
*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of
necessary libraries and/or headers.  Check the mkmf.log file for more
details.  You may need configuration options.

Provided configuration options:
	--with-opt-dir
	--without-opt-dir
	--with-opt-include
	--without-opt-include=${opt-dir}/include
	--with-opt-lib
	--without-opt-lib=${opt-dir}/lib
	--with-make-prog
	--without-make-prog
	--srcdir=.
	--curdir
	--ruby=/System/Library/Frameworks/Ruby.framework/
              Versions/1.8/usr/bin/ruby
	--with-mysql-config
	--without-mysql-config
	--with-mysql-dir
	--without-mysql-dir
	--with-mysql-include
	--without-mysql-include=${mysql-dir}/include
	--with-mysql-lib
	--without-mysql-lib=${mysql-dir}/lib
	--with-mysqlclientlib
	--without-mysqlclientlib
	--with-mlib
	--without-mlib
	--with-mysqlclientlib
	--without-mysqlclientlib
	--with-zlib
	--without-zlib
	--with-mysqlclientlib
	--without-mysqlclientlib
	--with-socketlib
	--without-socketlib
	--with-mysqlclientlib
	--without-mysqlclientlib
	--with-nsllib
	--without-nsllib
	--with-mysqlclientlib
	--without-mysqlclientlib
	--with-mygcclib
	--without-mygcclib
	--with-mysqlclientlib
	--without-mysqlclientlib

Gem files will remain installed in /Library/Ruby/Gems/1.8/gems/mysql-2.8.1 for inspection.
Results logged to /Library/Ruby/Gems/1.8/gems/mysql-2.8.1/ext/mysql_api/gem_make.out

You can fix it passing along the mysql_config5 param to the command. On Lion, if you installed mysql by using the command sudo /opt/local/bin/port install mysql5-server or something similar the command to install the gem is

sudo gem install -V -v '2.8.1' mysql -- --with-mysql-config=/opt/local/bin/mysql_config5 

SpeakMyName

How do you speak your name? Your tongue rolls a certain way to pronounce it, some syllables you stress and some you would prefer left out. Or you might have a name that might not be spellable in any other language at all. (yeah, spellable is a word I made up) My name is Emmanuel. Its not my surname really. And people find it hard to pronounce. I finally end up asking them to call me Jeba. Probably you are one of those people who have given up too.

However a name is not a simple thing. We attach a lot of importance to it. And deep down when a person pronounces it right, we are pleased. And you make a person happy when you speak his/her name properly. Deals have fallen through due to not taking the time to pronounce a name properly. Dale Carniege, in his classic book ‘How to win friends and influence people’, 1936 advices ‘Remember that a person’s name is to that person the sweetest and most important sound in any language.’ in how to get a person to like you.

I have read the book quite a few times, noted the thoughts and moved on. But there are some men and women out there who won’t let the small details slip by. Enter @beachbrake who noticed a speaker correcting the person introducing him on how to pronounce his name ‘right’. She has an idea and a plan. And therein was born speakmyname.biz.

We are techies with passion for technology. We have the tools, we have an idea. And a hackerpad (tekipad?) with awesome food from her mom. What can we do but not roll out a weekend hack. Go visit speakmyname.biz. It still has some rough edges.
1. Click on record (you may need to do it twice, the first time you need to authorize flash to access your microphone so that we do not spy on you),
2. Replay it to confirm it sounds ok,
3. Then upload. You will be given a url which you can share.

Add the to your email signature, on your facebook profile, linkedin profile and anywhere you have your contact information so friends and contacts know how you would like them to speak your name.

As for the technical details? I have used Apache (with Passenger), Ruby on Rails, jQuery, Capistrano and a miscellany of stuff.

Assembla Subversion Repository moving code to trunk

A colleague set up a new subversion repository on assembla and invited me in. Unfortunately he missed importing the code into the trunk directory and as a result all the code was out in the root of the repo.

A bit of googling gave the solution at http://svn.haxx.se/users/archive-2007-10/0600.shtml

Simply put

cd ~/localdir
svn checkout https://path/to/assembla/repo localdir
cd localdir
svn mkdir trunk
for f in *; do svn mv $f trunk; done
svn mkdir branches tags
svn commit -m 'Finally got organized'

Gallery Upgrade Issues

I had an issue today with a gallery upgrade in that I upgraded the gallery to 2.3.1 version as per the documentation. However, the galleries (there were about 14k images in about 9GB) displayed ok, while a couple of them had broken thumbnail placeholders. Gallery’s logs were no help and neither were apache’s logs.

I tried to use the maintenance section of the site admin to regenerate all thumbnails and derivatives, but got various errors including ERROR_STORAGE_FAILURE and ERROR_LOCK_FAILURE among a few others. I was also getting quite a lot of mysql server has gone away errors which probabaly were due to mysql query restrictions on the server to prevent abuse.

After a lot of googling and running through the faqs and troubleshooting sections of menalto’s gallery site, finally figured out a set of actions that seemed to temporarily fix the issue.
1. Go to http://site/lib/support, enter the setup password, and click on cache maintenance. Leave the logs and the thumbnails unchecked and run it.
2. In http://site/main.php after login, go to Site Admin>Maintenance>Delete Template Cache. If this gives some errors, it seemed ok to ignore it.
3. Open the database via phpmyadmin and run find the max value of g_id in g2_Entity. Increment the value by 1 and insert that value to the row in g2_Sequenceid (There should be only one row and if the value of the query ‘select max(g_id) from g2_Entity’ is 34523, the row in g2_Sequenceid should be 34524)

Now rerun the generate all thumbnails and derivatives from Site Admin>Maintenance

I still have issues running it as the memory limit seems to setup at 32mb. Working on fixing that.

ExtJS line Charts and improper string data from PHP

While working on the main dashboard for the current extjs project I am working I had to create a line chart which showed the performance over the last 1 week. This was across 3 different variables.

The code to show that with tips and all as an item in an ExtJS Panel is

new Ext.chart.LineChart({
                    store: new Ext.data.JsonStore({
                        url:PHP_AJAX_URL + '/hometab.php',
                        baseParams:{
                            task:'graphdata'
                        },
                        idProperty: 'gdate',
                        root:'data',
                        fields: ['gdate', 'f1', 'f2','f3'],
                        autoLoad: true
                    }),
                    xField:'gdate',
                    series:[
                    {
                        type:'line',
                        displayName: 'FONE',
                        yField: 'f1',
                        style: {
                            color: 0x889fbb
                        }
                    }, {
                        type: 'line',
                        displayName: 'FTWO',
                        yField: 'f2',
                        style: {
                            color: 0x889fcc
                        }
                    }, {
                        type:'line',
                        displayName: 'FTHREE',
                        yField: 'f3',
                        style: {
                            color: 0x6666bb
                        }
                    }
                    ],
                    tipRenderer: function (chart, record, index, series){
                        if (series.yField=='f1')
                            return Ext.util.Format.number(record.data.f1, '0,0') +
                            ' f1 on ' + record.data.gdate;
                        if (series.yField=='f2')
                            return Ext.util.Format.number(record.data.f2, '0,0')+
                            ' f2 on ' + record.data.gdate;
                        if (series.yField=='f3')
                            return Ext.util.Format.number(record.data.f3, '0,0') + 
                            ' f3 on ' + record.data.gdate;

                    },
                    extraStyle: {
                        padding: 10,
                        animationEnabled: true,
                        legend:{
                            display:'bottom'
                        },
                        xAxis: {
                            color: 0x3366cc,
                            majorGridLines: {
                                size: 0,
                                color: 0xdddddd
                            }
                        },
                        yAxis: {
                            color: 0x3366cc,
                            majorTicks: {
                                color: 0x3366cc,
                                length: 0
                            },
                            minorTicks: {
                                color: 0x3366cc,
                                length: 0
                            },
                            majorGridLines: {
                                size: 0,
                                color: 0xdddddd
                            }
                        }
                    }
                })

Like all other parts of the backend the code was being pulled via a quick mysql_query from the database and provided to the ExtJS frontend via JSON.

        $graph_query="select 
				date(f_date) as gdate,
                sum(f1) as f1,
                sum(f2) as f2,
                sum(f3) as f3
                from stats
				where id=user
                and date(f_date)>date_sub(current_date, interval 7 day)
                group by date(f_date)";
        $graph_recordset=mysql_query($graph_query);
		while($graph_row=mysql_fetch_assoc($graph_recordset)){
			$response['data']=$graph_row;
		}
		$response['success']=true;
		print json_encode($response);

However, the LineChart wasn’t rendering properly and it was showing wierd values for some and not rendering at all for the others. The axes were fine and firebug showed proper values for the JSON string.

After a bit of looking around, it seems that ExtJS does not convert from string numeric values to numeric values. Remember that mysql_fetch_assoc provides an associative array with string values. All that was needed was to manually cast to integer/float values that the LineChart needs.

The bit of modified code is below. Note the casts inside the while loop

        $graph_query="select 
				date(f_date) as gdate,
                sum(f1) as f1,
                sum(f2) as f2,
                sum(f3) as f3
                from stats
				where id=user
                and date(f_date)>date_sub(current_date, interval 7 day)
                group by date(f_date)";
        $graph_recordset=mysql_query($graph_query);
		while($graph_row=mysql_fetch_assoc($graph_recordset)){
			$graph_row['f1']=intval($graph_row['f1']); //or floatval as needed;
			$graph_row['f2']=intval($graph_row['f2]); //or floatval as needed;
			$graph_row['f3']=intval($graph_row['f3]); //or floatval as needed;
			$response['data']=$graph_row;
		}
		$response['success']=true;
		print json_encode($response);

To Cake or not to cake

To Cake or not
I am starting work on a project for a client that involves complicated workflows when the customer orders a product and also a simple user interface. Even thought I have worked with a few php frameworks, this is the first time I am starting solo on a project from scratch. While looking around for the best options that fit the bill, I shortlisted 3 options
1. Core PHP
2. Drupal
3. CakePHP or Zend Framework
Option 1 might be the simplest to start with but would be not be a wise decision since it would be a maintenance and extensibility nightmare. I started working on a prototype for Drupal, but a few weeks down the line, the limits of a CMS for such a project became obvious. The best option now seems to be to use a framework, which should have been obvious from the start in hindsight.
I considered going with Zend but Cake seems to be much lighter and also places more emphasis on convention which supposedly makes me a ‘better’ programmer. Additionally, the fact that Zend seems to be more feature rich that cake actually pushed me more towards cake since the project is quite simple technically. And Zend seems to be too powerful for that.
So I am off to the bakery.
Cheers and Peace!
Jeba Singh Emmanuel
————————————-
Those who would joyously march in rank and file have already earned my contempt, for they were given a large brain by accident when a spinal chord would have sufficed.
–Albert Einstein

I am starting work on a project for a client that involves complicated workflows when the customer orders a product and also a simple user interface. Even thought I have worked with a few php frameworks, this is the first time I am starting solo on a project from scratch. While looking around for the best options that fit the bill, I shortlisted 3 options

1. Core PHP

2. Drupal

3. CakePHP or Zend Framework

Option 1 might be the simplest to start with but would be not be a wise decision since it would be a maintenance and extensibility nightmare. I started working on a prototype for Drupal, but a few weeks down the line, the limits of a CMS for such a project became obvious. The best option now seems to be to use a framework, which should have been obvious from the start in hindsight.

I considered going with Zend but Cake seems to be much lighter and also places more emphasis on convention which supposedly makes me a ‘better’ programmer. Additionally, the fact that Zend seems to be more feature rich that cake actually pushed me more towards cake since the project is quite simple technically. And Zend seems to be too powerful for that.

So I am off to the bakery.

Exim and Multiple Domains – PHP Mail function and junk mail issue

I am now working at a place where I get a chance to home my php, javascript and mysql skills, work with cake and other similar projects The job has System Admin work also and it is fun since I get to learn lots of new things. At the moment, I am just being given debugging and troubleshooting to do on the servers, but it is a matter of time before I impress and blow my team leader away. :D

Meanwhile, one issue that came up was a client with a server that had multiple domains on it. While sending mails with php’s mail function, the Received and other headers were not being set correctly, because of which mails to hotmail and live.com were ending up in the junk folder.

For eg.

Return-Path: <admin@correct.com>
Received: from noc.wrong.com ([76.76.11.105])
by mx.google.com with ESMTP id 42si3780510ywh.71.2009.;
Wed, 11 Nov 2009 22:59:31 -0800 (PST)
Received-SPF: neutral (google.com: .......;
Authentication-Results: mx.google.com; .......
Received: from wronguser by noc.wrong.com with local(Exim 4.69)
(envelope-from <admin@wrong1.com>)ntid 1N8TeT-0007On-F6ntfor jebasingh.emmanuel@gmail.com ; Thu, 12 Nov 2009 01:59:29 -0500

See the envelope-from? That was not being set properly event by using the 5th parameter in php mail as ‘-fadmin@correct.com’

The fix for that was easy, set

trusted_users=domainusername

in /etc/exim.conf.

The trusted_users variable is a colon delimited list of user accounts whose domains should be allowed to send mail as themselves.

Now for the actual code fixes, which can be found here.

General Exim method which doesn’t exactly work as advised. Might need modifications.

WHM specific method.

The problem with the first method was that $interface_address was not set at all for outgoing mail. Since we do not receive incoming mail for our domains, I didn’t get to check how the incoming mails were working out. If you are using WHM, however, you just need to create the files /etc/mailhelo and /etc/mailips and you are good to go after restarting exim. (test with exim -bV first)

I get these headers after the edit.


Return-Path: <admin@correct.com>
Received: from correct.com ([76.76.11.105])
by mx.google.com with ESMTP id 42si3780510ywh.71.2009.;
Wed, 11 Nov 2009 22:59:31 -0800 (PST)
Received-SPF: neutral (google.com: …….;
Authentication-Results: mx.google.com; …….
Received: from correctuser by noc.wrong.com with local(Exim 4.69)
(envelope-from &amp;lt;admin@correct.com&amp;gt;)ntid 1N8TeT-0007On-F6ntfor jebasingh.emmanuel@gmail.com ; Thu, 12 Nov 2009 01:59:29 -0500</pre>

Couldn’t figure out how to set the smtp_active_hostname in exim.conf since $interface_address wasn’t being set. Still, the mails no longer end up in the junk mail folder on gmail, yahoo, aol and hotmail, so I think I am golden.

Took ages to get the above links. Just hope it helps someone else too.