Tuesday, December 13, 2011

Facebook Graph API tweaking: fields

Want to improve the performance of your Facebook Graph API calls? Try trimming your requests down to just the information you need. During recent optimization and testing of some Facebook Graph API client code my colleague Bob determined just how much time could be saved by tuning the API requests. Typical requests result in the return of a default object, for example this URL

https://graph.facebook.com/6547384565867889

returns this album object:

{
  "id": "6547384565867889",
  "from": {
    "name": "John Doe",
    "id": "9834439837"
  }, 
  "name": "Mobile Uploads", 
  "link": "https://www.facebook.com/album.php?fbid=6547384565867889&id=9834439837&aid=743987489", 
  "cover_photo": "748397943639", 
  "privacy": "custom", 
  "count": 1, 
  "type": "album", 
  "created_time": "2011-11-24T16:04:54+0000", 
  "updated_time": "2011-11-24T16:04:55+0000", 
  "can_upload": false
}

The client application doesn't need most of this information, all it needs are the id, name, photo count, and when it was created. By adding the optional fields parameter with a comma separated list of field names to the request:

https://graph.facebook.com/6547384565867889?fields=id,name,count,created_time

an object with only the requested information is returned (apparently Facebook gives us "type" for free):

{
  "id": "6547384565867889", 
  "name": "Mobile Uploads", 
  "count": 1, 
  "created_time": "2011-11-24T16:04:54+0000", 
  "type": "album"
}

Not only does this result in less information being transmitted to the client, more importantly it results in considerably shorter response times from Facebook. It seems that retrieving this information requires significant lookup effort on Facebook's servers and asking for less information means less rummaging through the datastore for all the bits. Bob found that getting 57 albums containing 2,434 photos from his account using the default request took 90 seconds. After adding the fields parameter with only the fields required it took only 40 seconds, less than half the original time! Of course YMMV based on the network, we also found that eliminating likes and comments had the largest effect in reducing response time. If you are working on an application that gets large amounts of data from Facebook it may be worth the effort to consider what information is being provided and only get what the client needs.

Monday, November 28, 2011

Facebook client-side authorization

"OAuth"

This one word can make software developers tremble in fear. Add "Facebook" to it and those same developers start sliding the monitors on their desks together to hide behind, like pioneers circling the wagons at night.

Granted things are better now than they used to be; OAuth 2.0 and the Facebook Graph API are much easier to work with than the old REST API with OAuth 1.0 (Remember signatures? No? You're lucky). However authorizing an app or logging in with Facebook can still be a challenge. I really wanted to be able authenticate as a Facebook app in a single HTML file with javascript interspersed just to see if it could be done in one file. What I've found is, that can't be done, but something almost like it can be.

Originally I had one page that would navigate based on the current Facebook login state which was determined by the parameters passed to the page. Roughly the Facebook authorization workflow was:

  1. App page initially displayed in a Facebook iframe: no access_token parameter.
  2. Navigate the browser window (not the iframe) to the OAuth dialog. Pass the page URL as the redirect parameter.
  3. User authorizes / logs in.
  4. App page is now displayed in the browser window with the access_token (remember we left the Facebook iframe when navigating to the oauth dialog), navigate to the app's Facebook canvas page and include the access_token in the canvas page URL.
  5. App page is displayed in the Facebook iframe and now it has the access_token.

This could work accept the Chrome browser only allows two redirects and this scheme requires three. After flailing with various fruitless searches ("facebook" + "javascript" + "login" does not yield a lot of helpful hits) I found a cached copy of this page that had the missing piece I needed, it used the Facebook Javascript SDK to determine if a user was logged in or not. I changed my code to use this method and then navigate to the oauth dialog or launch the app based on the result. This is the final workflow:

  1. App page initially displayed in a Facebook iframe: app not authorized / user not logged in.
  2. Navigate the browser window (not the iframe) to the OAuth dialog. Pass the app canvas page URL (not the URL of the HTML file) as the redirect parameter.
  3. User authorizes / logs in.
  4. App page is displayed in the Facebook iframe: app authorized / user logged in. Launch the app.

So there you go, authorizing an app and logging into Facebook done entirely client-side with one HTML file that includes the Facebook Javacript SDK (full disclosure: I also included jQuery for convenience though the code could be rewritten to avoid using it). You can try this code or use it by getting the source from this github gist (easy) or copy and paste it from the horribly clipped embedded view below (hard).

Saturday, November 26, 2011

Animated menu for a web page

I'm working on revamping Smashingline and wanted to make the menu at the top a little more interesting. I decided to create a menu with two "pointers." One to point at the item your cursor is currently over (highlighted) and another to indicate the current item (selected). The menu was made with HTML5, Javascript, and CSS. I also used jQuery to animate various elements. I was inspired by the page eCSspert to use only HTML and CSS for the graphic elements.

Essentially the menu consists of a "menu bar" div with "menu item" divs above it. When the cursor passes over the bar its mouseover event is fired and the highlight pointer is shown. When the cursor moves from one menu item to the next the animation is triggered causing the pointer to move. One of the problems with this approach is that when transitioning from one item div to another the bar div fires a mouseout event even though the location of the cursor is still "inside" the bar div. Event propagation is probably one of the most common problems when working with mouseenter and mouseout events. Fortunately jQuery has solved this problem by implementing its own mouseleave event which was introduced by Microsoft and is supported natively in IE. The mouseleave event is only fired when the cursor actually exits the region of an element, no matter the number of child elements. Very handy.

The pointers are constructed from HTML div elements and CSS. Generally each of the two pointers has a base div that is the same width as the menu items. The div's height and setting its overflow property to hidden dictates how much of child div which is rotated 45 degrees is visible.

Finally since you may want the web page to take some action once the user makes a choice a callback can be set on the MenuMarker class. This function is invoked once the animation is finished. The demo here displays an annoying alert dialog with the the text from the menu item displayed.

The source code (in three separate files) is available for download from a Github Gist. These can also be combined into a single HTML file and loaded dynamically as needed using the jQuery load method.

Saturday, March 12, 2011

Creating a Nexus S Wallpaper

So you've got a snazzy Nexus S Android phone and you want to use one of your own photos as wallpaper? Well it certainly can be easy enough, open a picture using the Gallery application then from the menu choose More - Save As - Wallpaper. Drag the crop box around and resize it by touching a side if necessary and your picture becomes the wallpaper. But since only a vertical slice from the wallpaper is shown on screen maybe you couldn't select as precisely as you wanted and an important part of the picture isn't visible. Or maybe you want more control over the final image, like resizing it to the actual wallpaper dimensions.

The first thing you need to understand is that only a small region of the wallpaper is shown at any time. This is because there are five different "desktops" that can be scrolled side-to-side. As the user swipes their finger across the screen the other desktops are shown and the wallpaper image scrolls slightly along with the icons and widgets. Because of this the wallpaper image needs to be wide enough to cover all five of the desktops. It turns out that the final wallpaper size is 960 by 800 pixels. The screen size is 480 by 800, so with each finger swipe the image moves by 1/5.

The starting picture is a 3:2 aspect ratio image. It has been resized so that it is 1200 pixels wide by 800 pixels high.

Original 3:2 aspect ratio photo
Original 3:2 aspect ratio photo

The first thing is to determine what the center screen should look like.
Selection indicating the region that will be visible in the center desktop. Note that the selection is not centered in the picture.
Selection indicating the region that will be visible in the center desktop. Note that the selection is not centered in the picture.

Once that's done the final wall paper region can be defined by expanding the selection so that it's 960 pixels wide.
The final wallpaper 960 pixel wide selection
The final wallpaper 960 pixel wide selection

Finally crop the image and save it to your Nexus S. Use the Gallery application to view the image and choose the Wallpaper menu item; for some reason Google decided that the crop box will never select the whole image, so you'll need to move and resize it to select the whole picture. There you go, your own custom wallpaper.
The final wallpaper image.
The final wallpaper image.
Creative Commons LicenseThis photo is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.

Sunday, December 5, 2010

Loopy DVD Menu Videos

My first DVD using Sony's DVD Architect has a video background for the menus. Being reckless I started creating the video for the menu before learning anything about DVD Architect (DA). I had my video fade up from black at the start and fade down to black at the end. In DA I added the video as the background media then previewed it. The video played and as I anticipated it looped back to the beginning and started again. Seeing this I had an epiphany; if I added a final transition at the end so that the last frame of the video was identical to the first frame at the beginning of the video it would appear as if the menu video was an endless loop. This was quickly followed up with another thought, "Video loops just like every professional DVD menu - doh!" I went back and re-edited and re-rendered my video for looping. In the DA preview I noticed a choppy gap as the video looped but convinced myself it was just an artifact of the preview, the final DVD would be fine.

Later when I watched the actual DVD I saw the choppy transition still existed. At that point I had been working on the DVD and its contents for months and my interest in solving (if it was even possible) a minor issue was very low.

Then recently I happened to be watching the main menu on the documentary "Good Hair" and noticed that when it reached the end of the video there was a brief transition to what appeared to be a different resolution still image of the main menu, then the video started playing again. That got me thinking about the loop transition on my DVD. It turns out that the main reason the loop was choppy was because the length of the menu video was calculated incorrectly.

On the Menu Page Properties under General is an entry for Menu length, the default value is Auto calculate and the length it has calculated is in the read only entry Length just below.

The Menu Page Properties with Auto calculate selected.
The Menu Page Properties with Auto calculate selected.

In the case of my video the calculated length was about 0.2 second longer than the actual video and this seemed to cause problems during playback. The solution was to set the actual length of the video manually. The actual length of the video can be found in the lower right of the Timeline pane, however the length is shown in seconds and frames. This not entirely helpful because the time to be entered in Length must be in minutes, seconds, and milliseconds. To get the time make sure that the media timeline pane is showing; from the menu select View - Timeline. In the time bar above the video right-click and select Time and Frames.
Changing the display to Time and Frames in the Timeline.
Changing the display to Time and Frames in the Timeline.

Zoom in on the timeline so that a hash mark appears for each frame, now click to place the cursor at the last frame you want to show which is probably the last frame. Now right click the timeline bar again and select Time. The length of the video is shown on the left side of the pane right above the video.
Set the display to Time and the actual video length is shown.
Set the display to Time and the actual video length is shown.

Return to the menu properties and click on Auto calculate and a list appears; choose Specify. Now the video time determined above should be copied to the Length value.
Specify the actual video length.
Specify the actual video length.

Preview the menu and you should find that it loops seamlessly from the end of the video back to the beginning. I don't understand why the estimated length doesn't match the actual length, guesses include: slight discrepancies between the audio and the video (i.e. the audio track is longer), the data used to calculate the length is bad or the calculation formula is wrong. In any case it seems easy enough to correct to create professional looking menus with video backgrounds.

I learned a few other interesting possibilities during this exercise. One is that the loop point defines the beginning of the loop, this is how some menu videos have an introductory part that is only shown once along with a location to start loop playback so that there is a seamless loop. Another possibility is that when navigating from menu to menu a "transition video" can be inserted between them. When a viewer selects a button, instead of navigating immediately to the next menu the link connects to a video that has been placed at the root of the DVD file structure. The End Action of the transition video then links to the menu to be displayed. This is a fairly common technique I have seen on several of the more highly produced DVDs.

Saturday, November 20, 2010

Simple Secure Email

"The right of the people to be secure in their persons, houses, papers, and effects, against unreasonable searches and seizures, shall not be violated, and no Warrants shall issue, but upon probable cause, supported by Oath or affirmation, and particularly describing the place to be searched, and the persons or things to be seized."

- the fourth amendment to the United States Constitution

Despite the strained avowals by certain U.S. Supreme Court justices to hold that the Constitution is "dead" it is obvious to anyone with average intelligence that the intention of the fourth amendment is that citizens are allowed to have private correspondence, records, and possessions. It is unlikely that the eighteenth century authors and legislators ever conceived of records that existed in any form other than paper but today people communicate through a wide variety of methods. Unfortunately many of those methods of communication are insecure, including email. Currently email is transmitted through plain text, it is easy to capture this text as it moves across the internet from sender to receiver. To me it seems obvious that long ago it should have become standard for email to be encrypted for transmission (some proprietary services like Blackberry's "push email" encrypt the messages but an increasing number of governments are pressuring Blackberry to give them access to the secret keys that will allow the messages to be decrypted) but automatic encryption is unlikely to happen now for a variety of reasons.

This post will briefly outline a method for sending and receiving encrypted email. First it is important to understand that both the sender and receiver must agree to encrypt their email. If a sender wants to encrypt a message the receiver must have already provided a "public key" to the sender to allow the sender to encrypt a message. These instructions are meant for the everyday email user, it is not a technical discussion of encryption methods.

In this method the encrypted email can not be read in a web browser the way Yahoo Mail or GMail are using Internet Explorer or Firefox. Both reading and encrypting messages are done using the email application Thunderbird. Your computer will need to be connected to the internet for Thunderbird to access your email, but a web browser is not required.

You will need a flash drive (sometimes called a thumb drive). Thunderbird will be installed onto the flash drive.

First create an email account using GMail. If you know what IMAP is, how it works, that it is available on your preferred email service and you can configure it, feel free to use it. Otherwise GMail will be the simplest choice.

Second log into your new GMail account to configure IMAP. Click "Settings" in the upper right. Under Settings click "Forwarding and POP/IMAP." At the bottom is a section labelled "IMAP Access." Click "Enable IMAP" then click the "Save Settings" button.

GMail IMAP settings
GMail IMAP settings

Next download Mozilla Thunderbird Portable from PortableApps.com. Plug the flash drive into your computer and follow the installation instructions. Launch Thunderbird. It will prompt you for information about your email account.
Entering email information into Thunderbird.
Entering email information into Thunderbird.

It is most secure to uncheck "Remember password" but it is much more convenient to leave it checked. Remember that if you lose the flash drive anyone who finds it can use it to access your email account. Click the "Continue" button and the application will get the setup information for GMail. Click "Create Account" and Thunderbird will start and connect to your account.
Thunderbird has automatically configured the settings to get your Gmail.
Thunderbird has automatically configured the settings to get your Gmail.

The final step is to install Enigmail. PortableApps has provided a very simple install procedure and links to the software that is needed. Once Enigmail is added to Thunderbird you will need to setup encryption. Select "OpenPGP" then "Setup Wizard" in Thunderbird Portable. Follow the instructions, unless you know otherwise use the default values. To allow people to easily send you encrypted email you should allow your public key to be placed on a key server. If someone wants to send you email (or you want to send email to someone) the key server can be queried to see if a public key is available for an email address.

Create email normally, the first time a message is sent to a particular email address you will be prompted to select the public key of the email recipient. The outgoing message will be encrypted using the recipient's public key. If the recipient doesn't have a public key then the message cannot be encrypted and will be sent in plain text. When you receive an encrypted message you will be asked to enter your passphrase (created using the OpenPGP Setup Wizard) and the message will be decrypted and displayed.

Remember that wherever you store the private key created during the Setup Wizard must be kept safe. If someone gains access to the flash drive with Thunderbird Portable they can get your private key, and with it your encrypted email can be read.

In summary:

  • Create a GMail account.
  • Enable IMAP for the GMail account.
  • Install Thunderbird Portable on a flash drive.
  • Install OpenPGP and Enigmail on Thunderbird Portable.
  • Create a public / private key pair and share the public key on a keyserver.