Binary Lion Studios

I code for fun and for food.

Octopress migration

I finished migrating my blog from Tumblr over to Octopress this weekend. The idea of a static site generator has always intrigued me. The minimalistic approach to blogging along with an easy setup that can be hosted pretty much anywhere is very appealing. Also, being able to write all my posts in markdown and store them in git as well as Dropbox makes me feel more in control of my content.

Octopress has been getting really popular lately, so it seemed like the obvious choice. It was painless to setup and the default theme is really nice. The code snippet support out of the box is incredible. That was always my biggest complaint with Tumblr. I blog strictly to share code and Tumblr is clearly not made for that.

I’m very happy with Octopress and feel like the ease of writing new posts will help me blog more often. Plus, writing blog posts in Vim just feels right! Thanks for reading.

Note: If you subscribe to the RSS feed, please update it to my new FeedBurner account.

Console alarm clock

Wake up with a warm cup of Coffeescript. I am constantly amazed at how simple it is to write one-off scripts and small utilities with node.js & coffeescript.

I wanted an easy way to set reminders for myself throughout the day. For example, if I put the kettle on the stove, come back to my office and crank Gungor, I’m not going to hear the kettle whistling when the water is boiled. Instead, when I get back to my office I want to open a new tab in Terminal and type:

1
$ remindme +5min "Check the kettle."

Ideally, this will show me a Growl notification and play a sound to remind me to go check on the kettle.

Using node-growl, datejs and play.js the final script is as simple as this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#!/usr/bin/env coffee

nm = "#{__dirname}/node_modules"

require "#{nm}/datejs"

growl = require "#{nm}/growl"
play = require "#{nm}/play"

usage = ->
  console.log '''
    usage: remindme time msg

      time - the time to show the reminder
      msg  - the message to show when the reminder goes off
    '''

main = ->
  [time, msg] = process.argv[2..3]
  if not time? or not msg?
    usage()
    process.exit 1
  showReminder = ->
    play.sound "#{__dirname}/audio/alarm.wav"
    growl msg,
      title: 'Reminder'
      sticky: true
  remindAt = Date.parse(time)
  delta = remindAt - Date.now()
  console.log "reminding you at #{remindAt.toString()}."
  console.log "that is in #{delta}ms, if you were wondering."
  setTimeout showReminder, delta

main()

Now I can leverage the power of datejs on the console, which gives me a lot of flexibility when setting alarms. Again, I’m impressed at the number of quality libs available for node.js and the speed of which an idea can go from concept to working script.

I plan to package this script up as an npm module and make the source available on Github soon.

Lift embed snippet execution failure

If you are getting an Execution Failure while trying to use the builtin embed snippet in Lift, you need to make sure the following are true:

  • the embedded template name must start with an underscore (ie: _sample.html)
  • do not include the .html extension on the name in the tag
  • make sure you have a top level tag in the embedded template that contains all the content For example, this is how to embed a template using designer friendly templates:
1
<div class="lift:embed?what=/templates-hidden/dashboards/_admin"></div>

Then the actual contents of the _admin.html template should look like this:

_admin.html
1
2
3
4
5
6
<div>
  <p>This is an admin template.</p>
  <div>
    ... other content/snippets here ...
  </div>
<div>

If you don’t put a top container around your embedded content, only the first node will get embedded.

Verify In-App Purchase receipts

If you have services that are validating In App Purchase receipts, Apple’s documentation doesn’t clearly state whether you should continue validating those receipts against the sandbox or production environment while the app is in review. The answer is, however, found at the bottom of Technical Note TN2259:

What url should I use to verify my receipt?

  • Use the sandbox url https://sandbox.itunes.apple.com/verifyReceipt while testing your application in the sandbox and while your application is in review.
  • Use the production url http://buy.itunes.apple.com/verifyReceipt once your application is live in the App Store.

Once your application is approved, you should switch your services over to use the production environment.

Ajax with Facebook C# SDK

To make an Ajax call from a Facebook Canvas app, you need to pass the signed request along. The Facebook C# SDK does not use cookies for Canvas apps (yay!), so it needs the signed request to establish context. Using Razor, it might look something like this:

1
2
3
4
var url = "@Url.Action("Action", new { signed_request = Request["signed_request"] })";
$.get(url, function(data) {
    $("#contentHolder").html(data);
});

C functions in Objective-C

If you are including a header .h and implementation file .c for C functions in your Objective-C project and get errors like:

1
error: expected '=', ',', ';', 'asm' or '__attribute__' before 'CGRect'

there is an easy solution. Change the extension of the implementation file from .c to .m.

dd_belatedpng pages blank in iframe

Ran into an issue today when testing a Facebook application in IE6. The page is a canvas page that is rendered in an iFrame. It uses the excellent HTML5 Boilerplate and thus, the dd_belatedpng library to provide transparent PNG support in IE6. I found that whenever the CSS selector passed to fix() matched more than a single element, the entire page would become blank.

I found a workaround on an Adobe thread. Apparently dd_belatedpng sets the position to relative on the HTML tag. This is what was causing the issues. The workaround is to (ugg) modify the dd_belatedpng source and add the following conditional (on line 138 of the non-minified 0.0.8a release):

1
2
3
if (el.nodeName != 'HTML') {
    el.style.position = 'relative';
}

That ensures the HTML tag doesn’t get its position set to relative. It’s a hack, but so is IE6, so I’ll still sleep at night.

error: stdarg.h: No such file or directory

When trying to install PIL on Snow Leopard 10.6.6 with the stock Python 2.6.6 install, I was running into the following error:

1
error: stdarg.h: No such file or directory

The solution was to reinstall Xcode and check the Mac OSX 10.4 SDK (which isn’t selected by default).

Create iOS Development Certificate error

You may see the following error while trying to upload your CSR in Chrome:

We are unable to upload this Certificate file because it is invalid. Please check the file and try again.

I was able to get around this error by uploading the CSR in Safari. Exact same CSR … just a different browser and it worked.

ZipKit example

Quick and easy way to inflate an archive using the fantastic ZipKit.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
- (void)inflateArchive {
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

  NSString *archivePath = [self archivePath];
  ZKFileArchive *archive = [ZKFileArchive archiveWithArchivePath:archivePath];
  [archive setDelegate:self];
  [self setArchiveSize:[[[archive centralDirectory] valueForKeyPath:@"@sum.uncompressedSize"] unsignedLongValue]];
  [archive inflateToDiskUsingResourceFork:NO];

  // do something with inflated archive. 
  // zipkit puts all inflated files in the same directory as the archive.

  [self performSelectorOnMainThread:@selector(inflateComplete) withObject:nil waitUntilDone:NO];

  [pool drain];
}

- (void)inflateComplete {
  // do something after inflate finishes.
}

# pragma mark - ZKArchive delegate methods

- (void)onZKArchive:(ZKArchive *) archive didUpdateBytesWritten:(unsigned long long)byteCount {
  [self setArchiveProgress:[self archiveProgress] + byteCount];

  if ([self archiveSize] <= 0) return;

  [[self progressView] setProgress:(float)[self archiveProgress] / (float)[self archiveSize]];
}

- (BOOL)zkDelegateWantsSizes {
  return YES;
}