I’ve been working on a JSON API for mobile clients recently, and in doing so I’ve realised how much you need to repeat serialization options throughout Rails applications despite options generally being model specific.

This little patch solves that problem by allowing you to decorate your Rails models with model-wide serialization options, like so:

1
2
3
4
class Article < ActiveRecord::Base
  has_many :comments
  serialization_options :include => :comments
end

This means that whenever you call to_json or to_xml on an instance of Article, you’ll get the comment association thrown in for you. You’ll find you can clean up your Controllers and remove explicit calling of to_json, which previously would have looked like this:

1
2
3
respond_to do |format|
  format.json :json => @article.to_json :include => :comments
end

But can now be change to this:

1
2
3
respond_to do |format|
  format.json :json => @article
end

While it’s very simple, some people might find it useful. If you do, chuck this in your /lib directory and require it in environment.rb.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
module SerializationOptions
  def serialization_options(options = {})
    class_inheritable_accessor :serialization_options
    self.serialization_options = options.dup
  end
end

ActiveRecord::Base.send(:extend, SerializationOptions)

class ActiveRecord::Serialization::Serializer
  alias_method :old_initialize, :initialize
  def initialize(record, options = {})
    if record.respond_to? :serialization_options
      options = record.serialization_options.merge(options)
    end
    old_initialize(record, options)
  end
end

Opening session at Web Directions today was given to Andy Clarke, who proceeded to wrap it up with an announcement of a group put together to tackle the recent issues regarding submission of proposals and recommendations to the W3C. The eleven involved are:

  • Cameron Adams
  • Jina Bolton
  • Mark Boulton
  • Dan Cederholm
  • Andy Clarke
  • Jeff Croft
  • Aaron Gustafson
  • Jon Hicks
  • Roger Johansson
  • Richard Rutter
  • Jonathon Snook

From what was explained, their aim is to work through the CSS specifications and give feedback and examples for some of the more difficult issues, and then provide a body of work to the W3C and/or browser vendors with the hope that it things along a little faster than is currently the case. More details are sure to appear on the CSS Eleven website.

Here’s a snap of his slide:

Despite the speculative bullshit that always seems to spout from Walt Mossberg and Robert Scoble’s mouths, we still don’t really know what’s driving Apple’s decision to not support Flash content on the iPhone. They’ve also removed the Flash content from their website, which leads me to believe that this issue runs far deeper than I previously thought.

Adobe’s recent announcement of H.264/AAC support (among other things) in their Flash Player 9 product, has overnight turned Adobe’s Flash Player and Apple’s Quicktime Player into competing products. If you read between the lines, however, you might see something interesting:

“Adobe has licensed the x86, PowerPC and ARM versions of MainConcept’s H.264 and AAC decoders”

Keyword, “ARM”. Previously, Adobe have not had a Flash Player 9 SDK for the ARM architecture. For this reason, products like the Opera Browser on the Nintendo Wii have needed to settle for Flash Player 7, or in the case of Apple’s iPhone they’ve decided not to settle at all and instead ignored support for Flash altogether. Now, it seems that Adobe might be planning on releasing an SDK for the ARM architecture since the H.264/AAC support only affects the version 9 product.

Once Adobe releases an SDK, Apple will have the means to support the plugin on the iPhone. As an added benefit, they won’t need to worry about licencing On2’s VP6 codec since the H.264 videos which currently play on the iPhone, iPod and iTV will also play within the Flash Player too. Not only that, but the annoucement from Adobe also mentions support for reading iTunes metadata (“list” atom) embedded in audio and video files.

Adobe are playing straight into Apple’s hands!

So what’s Apple going to do about it? Should they embrace these changes and welcome Adobe with open arms? Keep in mind that according to the Adobe FAQ, “new releases of Flash Player take approximately 12 months to reach 90% penetration”. We’ll see this Flash Player in the wild as a release version sometime in September, so I expect Apple to have at least polarised by then.

I honestly hope that they chose to support the Flash Player. By doing so, they will put the power back in the hands of the content providors. While this doesn’t mean I expect them to re-instate Flash content on their own website, at least we’ll be left with a choice in the matter.

This is in response to Greg Borenstein’s article titled A Beginner’s Guide to Practical Syntactic Magic: the tale of Hpricot’s sudo-constructor and Stuart Halloway’s follow-up article, With great power comes great responsibility.

Both articles make reference to the odd method-naming tricks used in Why The Lucky Stiff’s Hpricot library for parsing XML (commonly HTML). In light of those tricks, I have a question for you all…

Which of the following two snippets of code would you:

  • Prefer to read
  • Be inclined to write
This:
1
2
3
doc = Hpricot.parse(open('http://www.atnan.com'))
title = doc.at('title')
articles = doc.search('.entry')
Or this:
1
2
3
doc = Hpricot(open('http://www.atnan.com'))
title = doc % 'title'
articles = doc/'.entry'
I’m interested in hearing your feedback in the comments below :)

One of the things I found difficult to understand when it comes to writing a Facebook application is how to add a “dynamic” panel to a users’ profile page, and how to auto-add entries to their mini-feed. A couple of examples include:

  • Putting “Nathan has added 5 photos to Flickr” or “Nathan is listening to Computer Camp Love by Datarock” on my mini-feed
  • Adding a dynamic panel to my profile which shows the last 10 patches I have submitted to Ruby on Rails

It turns out this is a fairly trivial exercise with Matt Pizzimenti’s RFacebook gem. The following is a quick run-down of what’s required for adding content to the profiles of users who have installed your (Rails based) Facebook application via a push strategy. I’ve done a gem unpack of hpricot-0.5, json-1.1.0 and rfacebook-0.6.2 to RAILS_ROOT/vendor/plugins.

The “Infinite Session”

In order for you to be able to add content independently of a Facebook user being logged in, you need to have a way of authenticating yourself. When a user is browsing your application through the Facebook interface, the RFacebook library gives you access to the fbsession variable which represents the user who is currently logged into Facebook. The problem is, this session will expire. You can find out when a session will expire by checking the value of fbsession.session_expires.

But surely we don’t want to force a user to log in to Facebook every time we want to update their profile with notifications / new content from our third-party application? So how do we get a session that doesn’t expire? The trick is providing a link to the following URL:

http://www.facebook.com/code_gen.php?v=1.0&api_key=YOUR_API_KEY

Once the user clicks the “Generate” button on that page, every time you call auth.getSession, you’ll get an identical session ID which has a fbsession.session_expires value of 0. While the user is interacting with your Facebook application, you should serialise this to some kind of storage such as the ActiveRecord model of your user so you can use it later:

1
2
3
4
5
6
7
8
9
10
11
class FacebookUser < ActiveRecord::Migration
  def self.up
    create_table :facebook_users do |t|
      t.column :user_id, :string, :null => false
      t.column :infinite_session, :null => false
    end
  end
  def self.down
    drop_table :facebook_users
  end
end

And the sample controller:

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
require 'facebook_rails_controller_extensions'
class FacebookController < ApplicationController
  include RFacebook::RailsControllerExtensions
  
  FB_APP_URL = 'http://apps.facebook.com/my-app-name'
  
  before_filter :require_facebook_login
  before_filter :require_configuration, :except => :configure
  
  def facebook_api_key() 'YOUR_API_KEY'; end
  def facebook_api_secret() 'YOUR_API_SECRET'; end
  def finish_facebook_login() redirect_to FB_APP_URL; end
  
  def require_configuration
    @user = FacebookUser.find_by_user_id(fbsession.session_user_id)
    redirect_to :action => :configure unless @user
  end
  
  def configure
    @user = FacebookUser.find_or_initialize_by_user_id(fbsession.session_user_id)
    unless fbsession.session_expires
      @user.infinite_session = fbsession.session_key
      @user.save!
    end
  end
end

This means we can now run a little script (via cron, if you wish):

1
2
3
4
5
6
7
8
9
10
#!/usr/bin/env /path/to/application/script/runner

require 'facebook_rails_controller_extensions'

session = RFacebook::FacebookWebSession.new('YOUR_API_KEY', 'YOUR_API_SECRET')
FacebookUser.find(:all).each do |user|
  session.activate_with_previous_session(user.infinite_session, user.user_id)
  session.profile_setFBML(:uid => user.user_id, :markup => 'My really dynamic content')
  session.feed_publishActionOfUser(:title => 'added some really dynamic content')
end

You could run this script every 5 minutes, or perhaps even directly call session.feed_publishActionOfUser and session.profile_setFBML from your application when the user does something (such as creating a resource).

If you’ve got any examples of where you’ve used this technique, or have any suggestions as to how it could be done better, I’d love to see them. Please comment below :).

Can AS3 do REST, or not?

June 12th, 2007

I just finished reading Thijs van der Vossen’s article, Flex can’t do REST, and I figured I’d weigh in a with a few of my experiences given that I’ve been doing quite a bit of playing with Rails, Actionscript 3, the Flex framework and Air (previously Apollo).

First and foremost, Thijs is correct and Harris Reynolds must either have a hidden agenda or is kidding himself (perhaps both?).

The issue they’re both talking about lies outside the realm of Flex classes, and right down at the Flash Player level. Brian Riggs’ article that was linked to by Thijs, Making HTTP calls in ActionScript 3, refers to the problematic class as being “AS3’s HTTPService class”, which might have throw people onto the wrong trail. The issue is with flash.net.URLLoader (Flash), not mx.HTTPService (Flex).

So what is this “issue”? It’s all in the response headers, actually. While you can get access to the response codes by listening to the HttpStatusEvent.HTTP_STATUS event when using URLLoader, it’s not going to help you with getting access to response headers. I’d put money on the fact that Adobe is unwilling to provide access to the headers because the functionality is not available in all browsers. Their opinion – as a guess – is that the Flash plugin should operate in an identical fashion across all browsers.

Sucks to be us.

The “proof” of all this can be seen when you take a look at the Air API docs for the HTTPStatusEvent class. There’s a responseHeaders property which spits out an array of URLRequestHeader objects…exactly what we want.

Perhaps someone from Adobe could give us a run-down of whether this the product of internal policies regarding Flash plugin behaviour across browsers?

I love time lapse photography, so the minute I saw Google Street View my first thought was that now I could create timelapse style videos of places I've never been!

Behold, the Golden Gate Bridge (H.264/MPEG-4), seen through the eyes of the Google Street View car.

Oh, and here's a nice panoramic video of Las Vegas Boulevard (H.264/MPEG-4) that I prepared earlier.

Code will come later, but to give you a brief idea of how this is done - I've written a crawler in Ruby which builds a matrix of panorama nodes. I then traverse the graph to find paths that can potentially produce nice videos, stitch the multi-image frames together with ImageMagick's montage application, and then create a MJPEG stream by concatenating each individual frame into a single file. This then gets encoded as an H.264/MPEG-4 video using FFMPEG.

I'll probably get more time to play on the weekend and release the source then when it's in a more usable state.

UPDATE: It appears as though the videos aren't playing properly in Quicktime (or the Quicktime browser plugin). They work fine in VLC and mplayer, though. I used the following command to do the MJPEG -> H.264/MPEG-4 conversion:

ffmpeg -y -i raw.mjpeg -an -f mp4 -vcodec h264 output.mp4

If you know of any way to fix these issues, please comment below :).

UPDATE 2: Given that the videos aren't working in Quicktime for some people, I've uploaded them to a new TileFile Grid.

Shows how much I follow the progress of RoR SVNJamis Buck checked in changeset 6487 2 months ago, which as far as I can tell is derived from my technique of checking dependencies as described in Using Capistrano to check for deployment dependancies.

Nice work Jamis, looks good!

Given that we’re using my original technique at my work, we haven’t had the opportunity to switch over to Capistrano 2 yet…but I’ll get there. I think I’ll need to submit a few patches, though, given that there are some things that aren’t supported yet such as executing a command and checking the results to see if it matches a regular expression. Something like this:

1
2
3
4
5
mysql_setting_max_connections:
  - 2000+
  - echo "SHOW VARIABLES LIKE '%max_connections%'" | mysql
  - !ruby/regexp /max_connections\s*[2-9]000/
  - !ruby/regexp /\d+/

You’ll notice that this is YAML (YAML Ain’t Markup Language). I’m storing dependencies in a file called dependencies.yaml, which gets auto-loaded when I load my DependencyChecker module/plugin. I could also do this:

1
2
3
4
5
python_pil:
  - 1.1.x
  - python -c "import Image; print Image.VERSION"
  - !ruby/regexp /1\.1\.\d/
  - !ruby/regexp /\d\.\d\.\d/

Or perhaps:

1
2
3
4
5
nptl:
  - present
  - /lib/libc.so.6
  - !ruby/regexp /Native POSIX Threads Library/
  - !ruby/regexp /Native POSIX Threads Library/

Doing it like this means I get platform-agnostic dependency checking, which would be a great feature for Capistrano 2’s dependency checking implementation.

Feedback?

Subscription Tees

May 19th, 2007

I just stumbled across an interesting concept of a similar vein to Valleyschwag (which is fairly geeky, this is less-so) – T-Shirt subscriptions. What’s even cooler is that the two companies doing it are based in Australia, namely TeeSub and Swami Safari.

Both are offering similar packages. For TeeSub you pay $39 and you get a tee sent every 6 weeks, and for Swami Safari you get a tee every 5 weeks but the price changes depending on the cost of producing the shirt for that issue (at the time of writing, their first issue was $44.95 and their second issue was $34.95, so you can get a feel for how much it might be for following issues).

I’m not sure who is doing the TeeSub designs but the first issue looks pretty decent and they’re printed on American Apparel tees. With Swami Safari, they get the shirts made up themselves and the designs have been done thus far by James Hancock. I’m fairly sure that even though the shirts aren’t made by American Apparel, the people behind Swami Safari have had experience with well-cut tees through their fashion label “etc.”. If you’ve tried one on, be sure to comment :).

Here’s issue one for TeeSub, and issues one and two for Swami Safari:

It’s going to be interesting to see how quickly this catches on. Hopefully we won’t see as many ripoffs as are commonly seen with Threadless shirts.

Own/Disown a Bash Job?

May 14th, 2007

Bash provides the ability to “disown” a job, which is effectively the same as starting the job with nohup. My problem is that I’d like to reverse the “disown” decision and “own” the job again.

$ my --really --long --process
$ # Oh shit, I forgot to open screen beforehand :(
$ disown -h 1
$ screen
$ own <PID>

Is that even remotely possible? Does anyone else see a use for it?

...perhaps I should just get my act together and spawn a screen session via my .bashrc.

After listening to Mike Downey talking about Apollo during his recent visit to Sydney for WebDU, I can’t help but think that their plans for PDF support within Apollo aren’t going to work on the Mac.

The reason? Mike Downey says, and I quote:

“PDF support will be completely available in Apollo, via the Reader”

That’s unfortunate, because no one installs Adobe Reader on a Mac.

Your average user opens their shiney new Mac and opens an email with a PDF attachment and can’t even tell the difference between whether it’s a PDF or an HTML email. Apple have made it transparent. The same goes for browsing to a PDF in Safari – you don’t launch a different application or get a crazy array of zoom, select and print buttons suddenly appear inside your browser chrome, the PDF displays inline just like any other page.

So what’s going to happen when a Mac user opens up “TPS Reports.app” (built using Apollo) which requires PDF support? There’s going to be a big what-the-fuck moment when they’re asked to install some unknown software called Reader, that’s what’s going to happen.

Is there a solution? I hope so. If Adobe can use Quartz 2D, we’re laughing. For any other fancy schmance stuff beyond the scope of the PDF 1.5 standard, use Adobe Reader.

See? Fixed.

I’ll keep this short and sweet because I promised myself that this blog would be more of a technical rambling than a discussion of current blog memes.

However, I can’t help but wonder why there aren’t more woman standing up and telling people like Anil Dash (specifically, look at his articles “The Old Boys Club Is For Losers” and “The Essentials of Web 2.0 Your Event Doesn’t Cover”) where to stick it. I’d be fuming if someone dropped my name as a potential speaker at a conference purely based on my gender, race, creed or other property unrelated to that of the conference itself. An anecdote may help:

About 6 months ago, my parter graduated from university and needed to find a job. At the time, Google was on a drive to hire more women, and had specifically approached her university requesting that female graduates go along to an open house – so she went along. The decision (on Google’s part) pissed me off.

If Google had approached the university and asked for a list of the graduates with the best marks, she would have been among that list too. Instead, she was invited along because of something she didn’t work for. Her academic achievements required hardship and dedication. The fact that she started out as an X sperm did not – that part was chance.

Thankfully, she wrote up a fantastic résumé, performed well in her interview, and got a job at another respectable IT company who saw merit in her achievements rather than her gender.

This is the way it should be. I’d be just as disappointed to see my Mum or two sisters treated differently in their respective industries (Medical, Law and Architecture).

I guess when you reduce the discussions down to their base level, it’s a question of “do you believe that positive discrimination is necessary in our industry?”, or even any industry.

My opinion, is no.

Accessing FastRI from TextMate

February 2nd, 2007

Firstly, you might want to check out the page for FastRI if you haven’t heard of it. It’s Ruby-RI on crack. Tasty crack.

By now, you’ll probably find this little Textmate command useful. All I need to do now is hit ⌃F, type in the class, method, or combination of the two, hit return and I get the Ruby documentation in seconds.

Here’s the little query input window that pops up:

And then the result window:

And now the command itself:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
require_cmd "${TM_FRI:=qri}" "If you have installed FastRI, then you need to either update \
your <tt>PATH</tt> or set the <tt>TM_FRI</tt> shell variable (e.g. in Preferences / Advanced)"

friOutput=`iconv -f utf-8 -t mac <<END|osascript
  on run argv
          set AppleScript's text item delimiters to {"\n","\r"}
    set searchString to ""
    tell application "TextMate"
      display dialog "FastRI Query:" default answer "" buttons {"Search!"} default button 1
    end tell
    set searchString to the text returned of the result
    set friOutput to do shell script "qri --format plain " & searchString
    return friOutput
  end run
END`

echo "<html><head /><body><pre>"$friOutput"<pre></body></html>"
exit_show_html

Huge thanks to Mauricio Fernandez (MFP) for all his work on FastRI!

We just had to get the cleaners in to mop up our delivery area shortly after it was decended upon by a ravenous pack of developers – hungry for the boatloads of I/O their soon-to-be storage solution brings.

The cause?

48 drives of pure glory. It’ll bring blood to your ears…

...but the hearing loss is well worth it. Trust me.

I just stumbled across someone else who is having the same issue as me…when my Macbook wakes up from sleep I can no longer double-tap to right click. Seems petty, but it has an insane ability to piss me off. Well, knowing that someone has had to put up with the same problem, I was driven to come up with a simple fix.

Edit your crontab:

$ crontab -e

Paste the following:

0-59 * * * *    defaults write "Apple Global Domain" com.apple.trackpad.enableSecondaryClick 1

This will re-enable secondary clicking every minute (poor solution, but it works). If someone knows if it’s possible to trigger a script when coming out of sleep/hibernate, please let me know in the comments.