Archive

Archive for the ‘Development’ Category

Bug or Feature? The Instagram vs Foursquare case

November 23rd, 2012 1 comment

TL;DR: the Instagram Foursquare integration has a bug which allows users to checkin remotely and still get points, badges and mayorships when posting pictures.

Long version:

Roughly over one year ago at CAST 2011, I presented a lightning talk entitled “Bug or Feature: The importance of being context driven”, which explored some common bug or feature scenarios we often see here in Brazil.

My intention was to raise the awareness of our fellow testing colleagues that even though we have the power to file bug reports, we should consider the context we find ourselves (and the bugs!) in before doing so.

So, last week, I decided to post some pictures from my trip to the Yahoo! Headquarters in Sunnyvale on Instagram, adding them to my photo map and to their related Foursquare venues.

My use case was simple:

As a Instagram user
I want to be able to upload my pictures to a Foursquare venue
So that other Foursquare users can see them when they explore the venue.

Everything was cool until I received a push notification from Foursquare about a comment left by GC on my checkin at the Y! Design Studio. He was complaining that I had stolen his mayorship and wasn’t even at the Yahoo! HQ (it was Sunday and I was at the San Jose airport).

But hold on a second, I was just uploading pictures! I didn’t want to check into the venue on Foursquare.

I said it was probably a Foursquare bug because we shouldn’t be able to receive points, badges or even mayorships when uploading pictures on Instagram.

Elias jumped into my conversation with GC and brought up the “Bug or feature?” question, saying I should open a feature request.

GC said it was a bug since I was able to take the Y! Design Studio mayorship from him.

Considering that “a bug is something that bugs someone who matters”, GC and I were in sync and I decided to investigate this odd behavior.

Before we jump into conclusions, let’s dive into the Foursquare and Instagram APIs.

Instagram upload endpoint

This is a private endpoint, so I had to sniff the SSL traffic to understand how it works.

In order to reproduce the scenario, I added some pictures to the Yahoo! Brazil office.

Here is the request body (after removing my private access tokens and formatting it to improve readability):

{
"fb_access_token": "FACEBOOK_TOKEN",
"foursquare_access_token": "FOURSQUARE_TOKEN",
"flickr_access_token_key": "FLICKR_TOKEN",
"location": "{\"name\":\"Yahoo!\",\"lng\":-46.684924849648894,\"lat\":-23.595049881369359,\"foursquare_v2_id\":\"4b1e479af964a520591824e3\",\"address\":\"R. Fidêncio Ramos 195\",\"external_source\":\"foursquare\"}",
"caption": "A whole new level of @bigodines keyboards",
"geotag_enabled": true,
"filter_type": 0,
"share_to_flickr": true,
"source_type": 0,
"media_id": "330338251555385834_1222987",
"flickr_access_token_secret": "FLICKR_SECRET",
"media_latitude": -23.594667434692383,
"media_longitude": -46.68516540527344,
"share_to_facebook": true,
"fb_has_publish_actions": true,
"share_to_foursquare": true,
"device_timestamp": 1353599409
}

The response contains a Location object:

"location": {
"external_source": "foursquare",
"name": "Yahoo!",
"foursquare_v2_id": "4b1e479af964a520591824e3",
"address": "",
"lat": -23.595049881,
"pk": 333588,
"lng": -46.68492485,
"external_id": 391328
}

The coordinates on this object differ from the ones in the EXIF data (media_latitude and media_longitude) parameters, so let’s take a look at the Foursquare venue API:

Hitting the Venue endpoint returns this object, along with a lot of information:

venue: {
id: "4b1e479af964a520591824e3"
name: "Yahoo!"
contact: { }
location: {
address: "R. Fidêncio Ramos 195"
crossStreet: "12º Andar"
lat: -23.59504988136936
lng: -46.684924849648894
radius50: 43
radius90: 417
postalCode: "04551-010"
city: "São Paulo"
state: "São Paulo"
country: "Brazil"
cc: "BR"
}

Now we have the following coordinates to work with:

Sent Instagram LAT: -23.595049881369359
Sent Instagram LNG: -46.684924849648894

Received Instagram LAT: -23.595049881
Received Instagram LNG: -46.68492485

Media LAT: -23.594667434692383
Media LNG: -46.685165405273438

Foursquare LAT: -23.59504988136936
Foursquare LNG: -46.684924849648894

It seems to me that Instagram is querying the Foursquare API for the venue’s coordinates, rounding them up (notice the slight difference) and sending them back to Foursquare to checkin AND add a picture to the checkin.

Let’s dig a little deeper and take a look at the Foursquare checkin and photo upload endpoints and see if that hypothesis is true.

Foursquare checkin endpoint

Documentation URL: https://developer.foursquare.com/docs/checkins/add

Description: “Allows you to check in to a place.”

Notes: You can’t add photos using this endpoint.

According to this post from June 2011, Foursquare pushed a change to its API which added the optional “ll” parameter to indicate the user’s real location.

Foursquare photo upload endpoint

Documentation URL: https://developer.foursquare.com/docs/photos/add

Description: “Allows users to add a new photo to a checkin, tip, venue, or page update in general. All fields are optional, but exactly one of the id fields (checkinId, tipId, venueId, pageId) must be passed in.”

Notes: Does not mention if it automatically checks in when called.

Interesting.

So, it seems that when we select to share to Foursquare (share_to_foursquare=true), it also uses the latitude (lat) and longitude (lng) parameters to checkin to Foursquare on the Instagram backend, since no checkin activity was logged on the client side.

Also, as we can see on the photo upload endpoint, Instagram could be using just the venueId to upload the picture without providing a checkinId (which proves that Instagram is checking in before uploading the picture).

Do you want further evidence? Try adding a picture to a venue through Foursquare (Explore > Search for a venue > Select a Venue > Photos > Camera Icon). You will notice that the picture will be added and you won’t checkin to the venue.

What do you think? Bug or feature?

Thanks Elias and GC for the inspiration for this post :)

Google Books Downloader

August 17th, 2012 No comments

A few months ago, I started a pet project to download free books available at Google Books.

My main goal when I started this project was to learn more about JavaScript headless browsers (PhantomJS in this case), which used CasperJS to drive it.

CasperJS was at version 0.6.6 back then and it had a nasty bug that prevented us from downloading binary files with the casper.download() method, so my script initially saved a list of the pages in a wget friendly format.

Now that the bug is fixed, I updated the script to save the pages automatically.

I still haven’t implemented any command line switches, so the book to download is still hardcoded (spoil alert: the book is actually a 1964 issue of the Popular Science magazine, which has a very interesting article on automation :), and you can’t select between saving the wget friendly list or saving the pages automatically.

Feel free to fork the project, improve it and send me pull requests :)

Ignoring DS_Store files on OSX

March 18th, 2012 No comments

Quick tip to permanently ignore .DS_Store files on all Git repositories:

git config –global core.excludesfile ~/.gitignore
echo .DS_Store >> ~/.gitignore

Categories: Development Tags: , , ,