Gravity: An orbital mechanics game written in Elm

Recently, I’ve been really excited about Elm. I’m currently using it for the on-hat web application for Lambda Hat. I’ve really enjoyed the FRP style and the Signals control flow mechanism.

When I was first getting started, I put together a little orbital mechanics game I call Gravity. Feel free to check out the source and demo below:

Gravity-animated

Source: https://github.com/stephenbalaban/Gravity

Demo: http://www.stephenbalaban.com/wp-content/uploads/2014/11/Gravity.html

Google Glass Lifestream

I’m happy to announce the launch of our open source Google Glass Lifestream & Backup Tool for Mac OS X. In order for it to work, you must first turn on debug on your Glass: Settings > Device info > Turn on debug (see notes below as to why we do this).

After backing up your Glass to the chosen directory, it can optionally generate a lifestream from the images taken with your Glass. Here’s my latest lifestream:

Stephen Balaban's Lifestream - Created by the Lambda Labs Glass Backup Tool for Mac OS X

You can download the backup tool here:

Download the Google Glass Backup Tool

Simply download and run the LambdaBackup.app file.

The source is available on Github: https://github.com/lambdal/LambdaBackup. The dirty secret is that the entire app is just a shell script wrapped into a .app file! It’s the future of Cocoa development.

Tools used:

  • Platypus – for wrapping the shell script up as an app.
  • CocoaDialog – bash bindings for Cocoa.
  • adb – for moving files back and forth between the Glass without having to implement a PTP client, this is why we need the Glass to be in debug mode.
  • ImageMagick – for creating the optional GIF lifestream at the end.
  • GNU parallel – for downsizing the images in parallel using ImageMagick.

Enjoy!

iOS internationalization from day one

A few days ago we did a private beta release of the Babatuba Collage App. Here’s the map from the first 72 hours:

Babatuba!

Babatuba was to be international from day one, this decision fundamentally directed the product. Many aspects of an application change as a function of your audience’s locality. Sina Weibo is popular in China but not in the United States. Bandwidth varies wildly from nation to nation: we increased image compression to speed up loading times in China. We found the avg. bandwidth by country in the Akamai State of the Internet useful. Ideally this would be calculated individually using bandwidth data on the phone.

Separating code and data is good engineering practice; don’t litter your code with literals, internationalize!

Here’s a 5-minute tutorial & example iOS Project:

iOS Internationalization in 5 minutes

Step 1. Use NSLocalizedString for all string constants

If you use the C pre-processor macro NSlocalizedString, which is defined as #define NSLocalizedString(key, comment) [[NSBundle mainBundle] localizedStringForKey:(key) value:@"" table:nil], you can use the shell script below to generate the body of the .strings file that you will use in the next step. Example:

- (void)viewDidLoad {
    [super viewDidLoad];

    self.labelIntl.text = NSLocalizedString(@"LABEL_TEXT", nil);
    [self.buttonBabatuba setTitle:NSLocalizedString(@"BUTTON_TITLE", nil) 
                         forState:UIControlStateNormal];
}

Step 2. Set up a Localized.strings file & Localize your InfoPlist.strings

Create a Localizable.strings file: File >> New >> File >> iOS >> Resource >> Strings. Select the new file and click Localize.

Strings File
Localize iOS
Localizable.strings

Use the following shell script (included in the example project) to generate the boilerplate for all localizable string in your project:

#!/bin/sh
grep -hor "NSLocalizedString(\@.*)" . | sed s/NSLocalizedString\(@// |
     sed s/,.*$// | uniq | sort | sed 's/$/ = "";/'

This will generate the body of your Localizable.strings file. To set the name of your app as it appears on the springboard, localize your InfoPlist.strings file and add this to each file:

"CFBundleDisplayName" = "$LOCALIZED_NAME";
"CFBundleName" = "$LOCALIZED_NAME";

Step 3. Rejoice!

Just translate the .strings files and you’re set! Kind of ^^. App usage will vary from culture to culture, you will need to localize your product’s features based on usage. However, that’s up to you and your team’s understanding of your target market! You can get the full iOS internationalization example project on GitHub.

There are other great tutorials for Apple’s Internationalization APIs online:

In the mean time, you can participate in the Babatuba beta for just 99¢! It’s been internationalized for English, Spanish, and Chinese (both Simplified and Traditional).

Participate in the Babatuba Beta for iOS

Facebook Graph Search Breaks Your Privacy Settings

Facebook’s new Graph Search is broken.

It was a sunny afternoon in Chinatown. I was taking my new Graph Search invite for a spin. After exhausting the—surprisingly long—list of females under 30 living in San Francisco, who went to MIT and like Seinfeld, I went for something more mundane, but far more sinister. “Photos of My Brother”.

Pesky privacy-conscious sibling not letting you view their photos? There’s a Graph Search for that.™ Low and behold, despite my brother’s draconian privacy settings, despite his profile advertising to me “No photos to show”, that simple search provided dozens of never before seen photos of my fraternal twin. He was outraged.

Facebook Graph Search "Photos of"

Luckily, a single predicate can realign the current implementation with my brother’s, and others’, expectations. If Mallory can’t see a photo on Alice’s profile, don’t show it to Mallory in a “Photos of Alice” Graph Search. This would have prevented the disabling of my brother’s Facebook account and untagging of his photos that ensued. This would fix Graph Search.

You may argue, “Even before Graph Search, Mallory could manually browse the public photos of Alice’s friends and view those photos of Alice.” While this is true, Graph Search makes this formerly Sisyphean task a matter of a few keystrokes. It broke my brother’s privacy settings.

“The new Request Removal Tool!”, you may cry. I’ve used it myself and assisted multiple friends in untagging their newly searchable photos. Here’s the interface and a photo of me enjoying a cup of coffee:

Facebook Request Removal Tool

A “removal” tool that requires you to scroll through your timeline for 15+ minutes, mindlessly clicking check box after check box, is not a removal tool. It’s a digital torture device. We want one-click Graph Search opt-out.

I don’t blame Facebook. The majority of their users don’t seem to care about privacy, and that’s fine for them. But some of us, like my brother, do care. Some of us have every possible privacy setting set to “Only Me”. We expect that to mean only me, not me and people with Graph Search. Regardless of your sharing preferences, you must agree: we deserve a system that respects our privacy. Facebook, please fix Graph Search.

Summary (for those at Facebook working on Graph Search, feel free to bring these points up in your next meeting or standup):

  1. Graph Search, in it’s current implementation, breaks the privacy model
  2. If a photo can’t be seen on my profile, don’t show it in a Graph Search
  3. Make tools and settings which allow us to easily manage our Graph Search privacy

Your thoughts and feelings are welcome. I’d especially like to hear from those currently working on the product. Tweet @stephenbalaban

Interested in hearing more as the story unfolds? Want to learn about an upcoming way to privately share your photos? Drop your email and I’ll keep you updated:

Caching with NSCache, or, The most underrated Objective-C Class

“There are only two hard things in Computer Science: cache invalidation and naming things.” —Phil Karlton

There are four things you need to know about NSCache. The first, and most important: NSCache exists. I recently wrote a cache object in Objective-C, this was a mistake. I Google’d “objective-c cache class”:

NSCache

Unhelpful Google results for “objective-c cache class”.

Top results looked uninteresting and I was feeling saucy; so I implemented one from scratch. I will be happy if this post serves no other purpose than to prevent you from making the same mistake. Now that you know the most important thing about NSCache, here are three more things you should know (especially if you still want to implement your own cache, which I recommend as an exercise). [1]

  1. Apple does not publish NSCache’s auto-removal policy, it is subject to change. I would guess it’s caching algorithm is something like LRU (which is what GNUStep’s implementation uses). [3]
  2. NSCache is thread-safe, no need to @synchronize access.
  3. NSCache does not copy the objects put into it, it keeps (and retains in non-ARC) pointers to cached objects. [1]

So put down that thread-unsafe NSMutableDictionary, pick up your NSCache, and stop reinventing the wheel. Or, at least know that it exists before you go making improvements.

Sources & Further Reading:

[0] Phil Karlton (Who deserves a Wikipedia page but that’s another story)
[1] Apple’s Documentation on the NSCache Object
[
2] http://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used
[3] GNUStep’s implementation of NSCache – NSCache.m

It’s programming from here on out

There comes that point in every project where the “hard” part has been solved. Where the learning curve has been topped and one can start getting into the flow. The hacker equivalent to “smooth sailing from here on out”:

“It’s programming from here on out.”


Happy hacking.

Graph Visualization with GraphViz

I have a few idaes for startups with a graph-like structure and found myself exploring the topic of graph visualization. I decided to see if I could generate some graphs containing hundreds of thousands of edges. Tools of choice: bash, python, and GraphViz1.

RandomSubset(p)

Using my template I first made a graph of a random subset of (p * 100)% of the 2-tuples in the cartesian product between the first X integers:

[(a, b) for a in range(X) for b in range(X) if random() < p]

Here’s the middle of the graph for p=0.02:

Graph of random subset (2%) of the possible pairings of the first 10,000 numbers.

CommonFactors(x, y)

Next, I decided to see what the graph of integers < X that have more than Y factors in common.

[(a, b) for a in range(X) for b in range(X) if len(common_factors(a,b)) > Y]

 

Here’s the graph for x=10 000, y=5:

This is a graph visualization with X=10 000 and Y=5
A focus on the heavily linked part of for x = 10 000, y = 5

A GraphViz example of integers with common factors -- point shape used for nodes

Here’s one for x=10 000, y=30

x=10 000 y=30

I found them all to be quite beautiful.

The Code

If you want to check out the source code, here’s the github: https://github.com/stephenbalaban/biggraphs.

Note: The first image is a section of an earlier iteration of the CommonFactors graph.

[1] GraphViz project: http://graphviz.org – I used the point shape for the nodes here’s the part of the code that describes my graph style:

graph gengraph {
        graph [bgcolor="#FFFFFF", outputorder="edgesfirst", dpi=1000];
        node [width=0.0008, fixedsize=true, shape=point, color="#00000099"];
        edge [penwidth=0.1, color="#00000099"]graph [bgcolor="#FFFFFF", outputorder="edgesfirst", dpi=1000];
        a -- b;
        b -- a;
        a -- c;
        c -- a;
        a -- d;
        b -- d;
        c -- d;
}