Andy at waxy was kind enough to invite me to Bravo Nation — A site for web-based achievements (kinda like iminlikewithyou meets xbox). After playing with their un-finished drawing tool, I wanted a way to do more with it

Since I fancy myself a hacker, I made a bookmarklet to overlay an image and draw behind it.

I grossly underestimated this task! I won’t bore you with the details (email me if you wanna discuss it: kastner@gmail), but long story short: “It works for me!”

Here’s the bookmarklet code:

Here’s something I made with it: Weighted Companion Cube

Here’s a video of me using it (double click to lock the image):

My Bookmarklet for BravoNation from kastner on Vimeo.

Here’s an image I made on Ze Frank’s Scribbler:
I've made a note here: "Huge Success"

Average Rating: 4.4 out of 5 based on 209 user reviews.

I almost (co)wrote a book.

Sometime last year, Amy Hoy invited me to work on a book with her – “Web Scripting Power Tools”. It was going to be an advanced guide to javascript. Some things diverted my attention and the book project went away.

Amy Hoy doesn’t hate me and today we launched a project that came out of working on the book. Befuddlr!

The code is mostly JS (moo tools), but all the pretty is due to Amy’s keen eye (and keen PS skillz).

Average Rating: 4.6 out of 5 based on 151 user reviews.

I ran into a small problem with xendomain saving and restoring domains on shutdown. It turns out the obscure unix command
cut was to blame.

the way that /etc/init.d/xendomains reads from xm list is to use this cut command:

cut -c0-19

I got it to work by changing that to

cut -f1 -d' '

and replace the $rest with

cut -f2- -d' '

Hope this helps someone (even if it’s just me in the future!)

Average Rating: 4.5 out of 5 based on 215 user reviews.

We knew that Gary’s vid would show up on YouTube, but FROM NBC? that’s insane

Here it is:

Average Rating: 4.4 out of 5 based on 191 user reviews.

Wow… when WLTV started, I had NO idea it would go this far (and I’m starting to get the feeling that this is just the beginning.)

The first few episodes were shot with a crappy sony DVD camcorder and thrown up on our own bandwidth. Some things change, others don’t. Each day Gary still “brings the thunder”. It’s still edited in iMovie. It’s still just Gary, a camera and a camera operator (Chris took over for me a WHILE ago!)

I’m thrilled that I’m a part of WLTV, and so proud of G! (I just wish he’d stop Twittering every 10 seconds ;).)

Average Rating: 5 out of 5 based on 217 user reviews.

I’ve been playing with RubyCocoa lately and really enjoying how easy it is to create OS X GUI apps with just a few lines of Ruby. After playing with this stuff for the past few days, I’m even more excited about Apple’s inclusion of Ruby for Cocoa Development officialy in Leopard.

This post will walk you through the first steps into the RubyCocoa world (frankly, I’m not much beyond the first steps myself!). Before we get to the codin’ let’s get everything set up.

Step 1: Get your Ruby Ready RubyCocoa requires the --enabled-shared configure flag (“build a shared library for Ruby.”) to work from the command line. I’m going to assume that if you’re reading this (and following along), you’re not using OS X’s default Ruby binary (1.8.2). I’m going to also assume you have the ruby source tree somewhere on your harddrive (~/src maybe?). If you have a different setup, adjust accordingly. Go into your source tree and re-configure with your previous ./configure command (which can be found at the top of config.log) while adding –enable-shared to it. Here’s how mine looked:

  ./configure --prefix=/usr/local --enable-pthread --with-readline-dir=/usr/local --enable-shared

When that’s all done, run make followed by sudo make install.

Step 2: Install RubyCocoa
Since your Ruby is in a different location than the OS X default (/usr/local/bin instead of /usr/bin), you need to compile RubyCocoa from source instead of using the binary release. Fetch the latest RubyCocoa version from source forge (0.11.0 as of this writing – 2007-05-28), or grab it from the RubyCocoa SVN.

Then configure, compile and install RubyCocoa:

  $ ruby install.rb config
  $ ruby install.rb setup
  $ sudo ruby install.rb install

Step 3: Install the newcocoa gem
Jumping head-first into the world of Xcode (and away from my beloved TextMate) was a bit too much for me. Justin Palmer’s pointer to newcocoa was the final piece I needed to really get into RubyCocoa. Get it like you would any other gem:

sudo gem install newcocoa

With all that out of the way, let’s get started with our first little app.

I made a short screencast of myself making this app.

Create the project with the newcocoa command

newcocoa HelloWorld

Edit the Rakefile. By default the Rakefile generated with newcocoa has targets to ppc and intel. I haven’t figured out how to make a universal binary yet, but for now remove the -arch (ppc in my case, this was made on a MacBook) line you don’t have.

  cd HelloWorld
  mate Rakefile

Edit the .nib with Interface Builder

  open English.lproj/Main.nib 

Subclass NSObject to create your controller
Subclass NSobject

Name the new Class “Controller”

Right-click on the newly created controller and instantiate it
Instantiate Controller
This gives you a cool icon in the “Instances” tab.

Add a button and text control to your window
Drag Button
(The text control is the same method – on the Cocoa-Text tab drag a “System Font Text” over to your window)
Double click your new button and change the text to “Hello World”. Then double click your text control and remove all the text.

Add 2 outlets and 1 action to your controller. Open the inspector window ( ⌘ ⇧ I) and select the connections page (⌘ 2). Double click the instance of your controller in the Main.nib floating window (it should be a blue cube). Under actions hit Add and type “sayHello:”. Then in the Outlets page add “helloButton” and “textString”.

Link the controller’s outlets and action to the window
Linking Actions and Outlets
While holding down control, click on the Controller instance (blue cube) and drag up to your button. Then double click the “helloButton” outlet. Repeat for the text field (and double click textString). Then, while holding control, click on the Hello Button and drag down to your Controller instance. Now double click sayHello: under actions. This is how you define the connections between an interface (the VIEW) and an instance (the CONTROLLER). (Sidebar: Where are models? We’re not that far yet!)

Save your nib and go back to your terminal

run newcocoa -c
This command inspects your NIB files for subclasses and linked actions/outlets and creates skeleton files for them. Since you named your controller as “Controller”, you now have Controller.rb in your project directory.

Edit Controller.rb
Here is where the bulk of your code will go (or in this project, all of it). You have access to the full Ruby / Cocoa bridge, which has most (all?) of the cocoa API methods available. The only code you’ll be adding is:


inside of def sayHello. Pretty cool huh?

Run Rake. Click your button. Rejoice.

That’s it!

I like to clean up the generated controller file like so:

require 'osx/cocoa'
include OSX

class Controller < NSObject
  ib_outlets :helloButton,  :textLine

  def sayHello(sender)
    @textLine.setStringValue("Hello,  world!")

  def awakeFromNib

`rake` if $0 == __FILE__

The last line let’s me hit ⌘ R inside of textmate to launch my project -Agile!

Extra Credit.
Subclass NSWindow (call it MyWindow) and then set your windows “Custom Class” to “MyWindow”. Run newcocoa -c again (it skips Controller.rb this time) you’ll now have MyWindow.rb. Putting the following code in there will implement an “edge-snapping” effect.

require 'osx/cocoa'
include OSX

class MyWindow < NSWindow
  def awakeFromNib
    @moving = false
  def window_moved(notification)
    unless @moving
      @moving = true

      pillow = 10 # how far from the edge before the "snap"
      # 0, 0 in os x is the LOWER LEFT corner,  not the upper left.
      # set up the objects to grab from
      origin = self.frame.origin
      window = self.frame.size
      screen = self.screen.frame.size
      # the ideals (set the allowances for messed up windows here)
      ideal_left = 0
      ideal_bottom = 0
      ideal_top = screen.height
      ideal_right = screen.width
      # current x and y
      x,  y = origin.x,  origin.y
      # current edges
      top     = origin.y + window.height
      right   = origin.x + window.width
      bottom  = origin.y
      left    = origin.x
      # the snapping code - set the paddings here
      x = ideal_left                    if ((ideal_left - 100)..(ideal_left + pillow)).include?(left)
      y = ideal_top - window.height     if ((ideal_top - pillow)..(ideal_top + 100)).include?(top)
      x = ideal_right - window.width    if ((ideal_right - pillow)..(ideal_right + 100)).include?(right)
      y = ideal_bottom                  if ((ideal_bottom - 100)..(ideal_bottom + pillow)).include?(bottom)
      setFrameOrigin(,  y)) if (x != origin.x or y != origin.y)
      @moving = false      

`rake` if $0 == __FILE__

Average Rating: 4.9 out of 5 based on 256 user reviews.

Active Record, the ORM layer in the Rails cake (and camping, and Merb, etc) is strong magic.

Before stumbling on this trick, I would create new rails projects for every little thing I needed to figure out. Running
rails test_proj -d sqlite3
is just so easy!

Yesterday, I needed to figure out a way to have a search term provide alternates (“dog” might have “puppy”, “hound”, etc.) After thinking about it for a few minutes, I decided I needed to figure out how to play with ActiveRecord without a full rails project. Here it is: ar_playground

#!/usr/bin/env ruby

%w|rubygems active_record irb|.each {|lib| require lib}

:adapter => “sqlite3″,
:database => “test.db”

ActiveRecord::Schema.define do
create_table :fruits, :force => true do |t|
t.column :name, :string

class Fruit < ActiveRecord::Base
validates_presence_of :name

Fruit.create(:name => “apple”)

IRB.start if __FILE__ == $0

This will create a sqlite3 database in the directory where it’s run, and drop you into an IRB shell with all the Classes available for playing.

If you have trouble with sqlite3, you can use mysql, or get sqlite3 running by checking out:
SQLite3 announcement on Jamis’ blog

If you’re curious what I came up with for my problem, here’s the pastie.

Average Rating: 4.8 out of 5 based on 185 user reviews.

Update: I forgot to link to the repos! Here it is:
There is a key for a popular photosharing site in there (rhymes with ticker), please don’t abuse it.

Camping, a ruby “micro-framework” is really a lot of fun once you get into it. It has sessions, ActiveRecord, MVC and a few other niceties that are great for “quick” things that don’t need to be full Rails projects.

So, in my spare time I’ve been playing with rewriting a php tool I wrote a while back for helping me memorize my Peg list. I made it for a few reasons: To play with Camping again, to work on my design skills, and make my old system much more usable.

Peg list by Meta | ateM.

    I wanted anyone to be able to play with the tool, I’ve added a few features that should allow anyone to jump right in, even if they have no interest in memory pegs:

  1. OpenID Logins
    These were pretty easy to get working in Camping. Even so, I’d like to make (or have) a plugin for Camping that would let me drop in OpenID auth anywhere.
  2. an “I’m too lazy for this. Do it for me.” button
    I figured that most people I showed this too wouldn’t really care about pegs. What better way then to pre-populate pegs for those people?
  3. Avatars from Flickr and Twitter
    Why bother writing an image uploader / cropper when I can just take a username and grab an existing avatar? I could add other services easily (like gravatar) and I might do that one day!
  4. Flickr API integration
    This is one of the few things my old tool did have. I’ve expanded it and made searching for an image easier and slicker.
  5. A Favicon!
    I always forget to make favicons. Thanks to Dan at Simplebits (from a recent set of slides he put up), I decided that this project HAD to have a favicon. It wasn’t hard, and ads a bit of polish to the site.

Average Rating: 4.9 out of 5 based on 230 user reviews.

So, I went to the Future of Web Apps summit in London this week. I may have a full post about that soon—but this isn’t it.

During a presentation by Tara Hunt and Chris Messina (Fostering Online Communities), Chris showed a cool new feature of ma.gnolia that really piqued my interest. Despite being a long-time user (my first bookmark was on 12/31/2003), I thought I’d try ma.gnolia (again) with a fresh perspective and an open mind.

Here are a few of my thoughts on the site and app after using it for just a few minutes:

  1. Using OpenID – Good job :)
  2. They need help with their “Blank state” pages (pages that don’t have data yet). When I first signed in, and didn’t have any bookmarks, friends or groups, my main page was a bit bare. Blank slates are a great opportunity to show the user either what the page could look like when they’re really rockin’ or, a call to action on how to start rockin’. 37Signals has lots to say about this subject.
  3. The Dashboard widget is neat. A few complaints about it:
    • it doesn’t allow me to sign in with OpenID (which the main site does)
    • just like their popups, the tag suggestions are based only off MY bookmarks, not other peoples. This is something that may seem small, but by showing what others have tagged a site with (and even helping you type them), you can amplify a common vocabulary.
    • It puts the contents of my clipboard in the description portion… yuch!
  4. My import from still hasn’t happened yet! What gives?
  5. It’s slow. Could be bad timing on my part, or my sketchy WiFi in London, but it’s a lot slower than at this moment. I’m going to reserve judgement on that for now.
  6. It’s NOT just a pretty a clone (anymore) – SHOCKING! I held this belief until talking to Chris about the site, and actually playing with it myself. I now see that I was unfairly judging it (I do think they have an image problem though). What it gives you above and beyond are the community aspects of something like Flickr. A really neat bit is the “give thanks” (which is the feature I alluded to before)
  7. Their pagination really stinks… in a few places, each “page” is 5 or so items… What.The.Hell!
  8. Commas instead of spaces for tagging. This is 100% a personal preference, but I like spaces!

I think they’re doing some good stuff—I’m not ready to throw out just yet, but I will be posting to both services until one of them is less compelling to me.

Average Rating: 4.5 out of 5 based on 291 user reviews.

Dr Nic hit me up with the 5 things meme that’s been floating around for a few months now. It’s one of those parties you think is totally lame until you get your invitation. Without further Ado, I thee blog:

  1. I lived in my car for a few months.
    While I was in San Francisco, I was homeless, but had my car (An Isuzu Rodeo). Each night, I’d drive to the top of a hill near where I had stayed previously, prop up a sheet around all my windows so the cops wouldn’t look in, and sleep on the futon I had brought with me. It’s not as glamours as it sounds.
  2. I got evicted once.
    After a long and strange series of events, I found myself moving back to SF after having moved back to New Jersey with an interesting character. Turns out we didn’t get far because:
  3. I dated a crack-head
    I didn’t know it at the time, but on the road to SF, she started having withdrawal symptoms (from heroin, not crack) and we had to come back (she told me it was the Flu). Another time she stole all our rent money to buy crack.
  4. I can pop my shoulder out of it’s joint—almost to the point of dislocation.
    I decided that this one shouldn’t be about some of the strange happenings in my life… It’s just a trick I can do, and I have a few others. Ask me to demonstrate if you see me.
  5. My Isuzu Rodeo was taken by the city of San Francisco.
    So, while working at Pacific Bell Internet, I didn’t like parking in the faraway lot each day. I’d plop my car in front of 303 2nd ave and invariably get a ticket each afternoon (sometimes even two, score!) I thought, “I’m sure no one’s tracking this – I have out of state plates!” I was wrong. One day, I came out of work to find the spot I had parked in that morning taken by someone else. I thought my car was stolen—turns out the city took it as “Payment.”

Are we done already? I have a few more stories… oh well – next time.
Just to CYA, one of these might be made up :)

I hereby infect:
John K.
Amy Hoy
Chris Wanstrath
Phil Hagelberg
Dan Benjamin

Average Rating: 4.7 out of 5 based on 206 user reviews.