Time-lapse of the University Tower
Time-lapse of the University Tower, originally uploaded by John Wulff.
My first attempt at a time-lapse. I’ll pick a more interesting subject next time.
This American Life on the Economy
The most recent episode of This American Life was especially fantastic. They did a great end-to-end explanation of the mortgage mess and the current credit crunch in the fantastic narrative style they’re so good at.
A special program about the housing crisis. We explain it all to you. What does the housing crisis have to do with the collapse of the investment bank Bear Stearns? Why did banks make half-million dollar loans to people without jobs or income? And why is everyone talking so much about the 1930s? It all comes back to the Giant Pool of Money.
How I Deploy Typo Using Capistrano
I’ve been deploying all of my Rails apps with Capistrano to a MySQL, Nginx, Mongrel, God stack for a while.
I hadn’t been keeping my (this) Typo install up to date because it was such a pain to upgrade it compared to my other apps. Not anymore!
Here is my awesome Capistrano deploy task for Typo. (And my database.yml, god.config, and nginx.conf for good measure).
Any way it can be improved?
deploy.rb:set :application, 'www.johnwulff.com'
set :typo_plugins, [ 'delicious_sidebar', 'flickr_sidebar' ]
set :user, 'rails_admin'
set :deploy_to, "/var/www/#{application}"
# If you change the repository be sure to flush the server's cached checkout.
set :repository, 'http://svn.typosphere.org/typo/tags/release_5_0_3'
set :typo_plugins_url, 'http://svn.typosphere.org/typo/plugins/'
# This will substantially speed things up and save typoshphere.or's bandwidth.
set :deploy_via, :remote_cache
role :app, 'www.johnwulff.com'
role :web, 'www.johnwulff.com'
role :db, 'www.johnwulff.com', :primary => true
namespace :deploy do
task :default do
transaction do
update_code
typo_plugins.each do |plugin|
run "cd #{current_release}; script/plugin install #{typo_plugins_url}#{plugin}"
end
web.disable
symlink
# Copy local database.yml to the new remote release.
put File.read(File.join(File.dirname(__FILE__), 'database.yml')),
File.join(current_release, 'config', 'database.yml')
# Copy local nginx.conf to the new remote release.
put File.read(File.join(File.dirname(__FILE__), 'nginx.conf')),
File.join(current_release, 'config', 'nginx.conf')
# Copy local god.config to the new remote release.
put File.read(File.join(File.dirname(__FILE__), 'god.config')),
File.join(current_release, 'config', 'god.config')
migrate
end
# Stop God watches, load the fresh God config that was just uploaded, and
# then start God watches.
sudo "god stop #{application}"
sudo "god load #{File.join deploy_to, 'current', 'config', 'god.config'}"
sudo "god start #{application}"
# Reload Nginx configuration without restarting Nginx.
sudo "/etc/init.d/nginx reload"
web.enable
# Don't use sudo for cleanup. This takes a bit longer than using sudo, but
# it's not a good idea to give passwordless `sudo rm` permissions to
# anyone.
set :use_sudo, false
cleanup
set :use_sudo, true
end
endproduction:
adapter: mysql
database: johnwulff
username: johnwulff
password: *****
host: localhost#!/usr/bin/env ruby
APPLICATION = 'www.johnwulff.com'
RAILS_ROOT = "/var/www/#{APPLICATION}/current"
%w{9900 9901 9902}.each do |port|
God.watch do |w|
pid_file = File.join RAILS_ROOT, 'tmp', 'pids', "mongrel.#{port}.pid"
log_file = File.join RAILS_ROOT, 'log', "mongrel.#{port}.log"
w.uid = 'rails_admin'
w.gid = 'rails_admin'
w.group = APPLICATION
w.name = "#{APPLICATION}-mongrel-#{port}"
w.interval = 30.seconds # default
w.start = "mongrel_rails start -d -e production -a 127.0.0.1 -c #{RAILS_ROOT} --user rails_admin --group rails_admin -p #{port} -P #{pid_file} -l #{log_file}"
w.stop = "mongrel_rails stop -P #{pid_file}"
w.restart = "mongrel_rails restart -P #{pid_file}"
w.start_grace = 10.seconds
w.restart_grace = 10.seconds
w.pid_file = pid_file
w.behavior(:clean_pid_file)
w.start_if do |start|
start.condition(:process_running) do |c|
c.notify = 'john'
c.interval = 5.seconds
c.running = false
end
end
w.restart_if do |restart|
restart.condition(:memory_usage) do |c|
c.notify = 'john'
c.above = 150.megabytes
c.times = [3, 5] # 3 out of 5 intervals
end
restart.condition(:cpu_usage) do |c|
c.above = 50.percent
c.times = 5
end
end
# lifecycle
w.lifecycle do |on|
on.condition(:flapping) do |c|
c.notify = 'john'
c.to_state = [:start, :restart]
c.times = 5
c.within = 5.minute
c.transition = :unmonitored
c.retry_in = 10.minutes
c.retry_times = 5
c.retry_within = 2.hours
end
end
end
endupstream johnwulff {
server 127.0.0.1:9900;
server 127.0.0.1:9901;
server 127.0.0.1:9902;
}
server {
server_name johnwulff.com;
rewrite ^/(.*) http://www.johnwulff.com/$1 permanent;
}
server {
listen 80;
server_name www.johnwulff.com;
root /var/www/in_out_open/current/public;
access_log /var/www/www.johnwulff.com/shared/log/nginx.access.log main;
client_max_body_size 50M;
# Redirect all traffic to maintenance.html if it exists.
if (-f $document_root/system/maintenance.html){
rewrite ^(.*)$ /system/maintenance.html last;
break;
}
location / {
# redirect feed requests to feedburner, unless its the feedburner agent
if ($http_user_agent !~ FeedBurner) {
rewrite ^/articles.(rss|atom)$ http://feeds.feedburner.com/johnwulff;
rewrite ^/xml/(atom|rss|rss20)/feed.xml$ http://feeds.feedburner.com/johnwulff;
rewrite ^/rss$ http://feeds.feedburner.com/johnwulff;
rewrite ^/feed/(atom|rss|rss20).xml$ http://feeds.feedburner.com/johnwulff;
}
# Forward header information so rails can make use of it.
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect false;
proxy_max_temp_file_size 0;
# check for index.html for directory index
# if its there on the filesystem then rewite
# the url to add /index.html to the end of it
# and then break to send it to the next config rules.
if (-f $request_filename/index.html) {
rewrite (.*) $1/index.html break;
}
# this is the meat of the rails page caching config
# it adds .html to the end of the url and then checks
# the filesystem for that file. If it exists, then we
# rewite the url to have explicit .html on the end
# and then send it on its way to the next config rule.
# if there is no file on the fs then it sets all the
# necessary headers and proxies to our upstream mongrels
if (-f $request_filename.html) {
rewrite (.*) $1.html break;
}
if (!-f $request_filename) {
proxy_pass http://johnwulff;
break;
}
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}Shultzy's New Website and Twitter
Shultzy’s has a new website, check it out.
Also, I found their not-yet-publicized Twitter account. One more reason to frequent Shultzy’s! (I really didn’t need any more reasons to frequent Shultzy’s.)
Jericho
According to TrekMovie.com Jericho, officially cancelled (again) by CBS, is looking for a new home.
This time, instead of peanuts I’m going to send a nice old-fashioned letter to the SciFi channel.
If you’d like to tell SciFi how happy you’d be if they picked up Jericho you can send a letter to:
SciFi Channel
21st Floor
30 Rockefeller Plaza
New York, NY 10112
I’ll be sending a letter on Monday.
Install id3lib-ruby gem on OS X Leopard 2
Posted By: Robin Stocker
Date: 2007-10-28 18:12
Summary: Install on Mac OS X 10.5 (Leopard)
Project: id3lib-ruby
Here’s a quick tip for people having difficulties installing id3lib-ruby on the newest OS X:
In short, here’s how to install id3lib-ruby (after having installed id3lib):
sudo -s ARCHFLAGS="-arch i386" gem install id3lib-ruby
Thanks a lot Robin, I was starting to go crazy…
Food Fight
I don’t normally post videos but this is amazing.
static-gmaps: Google Static Maps API Interface 3
I’ve written my first gem: static-gmaps. It provides a simple interface to the Google Static Maps API.
Usage
map = StaticGmaps::Map.new :center => [ 40.714728, -73.998672 ],
:zoom => 5,
:size => [ 500, 100 ],
:map_type => :roadmap,
:key => 'ABQIAAAA3HdfrnxFAPWyY-aiJUxmqRROGu07ZpoXmWqnENIWDDAF-b-TwhQ4JdQya7b6I5CihUtHtwmmBzWc0Q'
map.markers << StaticGmaps::Marker.new(:latitude => 40,
:longitude => -73,
:color => :blue,
:alpha_character => :b)
map.url => 'http://maps.google.com/staticmap?center=40.714728,-73.998672&key=ABQIAAAA3HdfrnxFAPWyY-aiJUxmqRROGu07ZpoXmWqnENIWDDAF-b-TwhQ4JdQya7b6I5CihUtHtwmmBzWc0Q&map_type=roadmap&markers=40,-73,blueb&size=500x100&zoom=5'Installation
sudo gem install static-gmapsDocumentation
http://static-gmaps.rubyforge.org
Update February 27, 2007: Added markers.
My Beautiful Controller Spec
Today I spent a few hours refining my controller rspec pattern. I’m really pleased with it.
This controller:class AssignmentsController < ApplicationController
def index
if params[:person_id]
@person = Person.find params[:person_id]
@assignments = @person.assignments
@title = "Assignments for #{@person}"
elsif params[:course_id]
@course = Course.find params[:course_id]
@assignments = @course.assignments
@title = "Assignments for #{@course}"
else
@assignments = Assignment.find :all
@title = "All Assignments"
end
@ical_url = url_for({ :format => :ics }.merge(params))
@rss_url = url_for({ :format => :rss }.merge(params))
end
endrequire File.dirname(__FILE__) + '/../spec_helper'
describe AssignmentsController do
describe 'index action GET request with' do
describe 'no parameters' do
before(:each) do get 'index' end
it 'should successfully respond' do response.should be_success end
it 'should assign a title' do assigns[:title].should == 'All Assignments' end
it 'should assign assignments' do assigns[:assignments].should == Assignment.find(:all) end
end
describe 'a valid person_id' do
before(:each) do get 'index', :person_id => (@person = test_person) end
it 'should successfully respond' do response.should be_success end
it 'should assign a title' do assigns[:title].should == "Assignments for #{@person}" end
it 'should assign assignments' do assigns[:assignments].should == @person.assignments end
end
describe 'a valid course_id' do
before(:each) do get 'index', :course_id => (@course = test_course) end
it 'should successfully respond' do response.should be_success end
it 'should assign a title' do assigns[:title].should == "Assignments for #{@course}" end
it 'should assign assignments' do assigns[:assignments].should == @course.assignments end
end
describe 'any valid parameters' do
before(:each) do get 'index' end
it 'should assign a rss_url' do assigns[:rss_url].should == 'http://test.host/assignments.rss' end
it 'should assign an ical_url' do assigns[:ical_url].should == 'http://test.host/assignments.ics' end
end
end
endLiberal use of nesting, alignment, and inline assignments, hooray.
Beautiful specs mean I’m that much more likely to actually write them…
Can it get any better?

