Michael Buffington

Mongrel and Capistrano

Monday, September 11 2006

Rails and Capistrano, by default, don’t quite handle the concept of deploying to multiple production environments. I often find myself deploying production ready applications to a staging virtual host on the same machine the production virtual host runs on so the client can approve work before pushing it live.

I settled on a pretty clean setup today to make this kind of thing dead simple. I’m assuming you’re already familiar with how to setup mongrel clusters, and that you’ve got the balancer in Apache or whatever forward httpd server figured out and running.

<ol>
	<li>Step one: Create two mongrel cluster config files
	<ol>
		<li>Call the first one staging.cluster.yml</li>
	</ol></li>
</ol><hr />

cwd: “/path/to/staging/yourapp/current”
port: “8000”
environment: production
address: 127.0.0.1
pid_file: “log/staging.pid”
servers: 3

	<ol>
		<li>Call the second one production.cluster.yml</li>
	</ol><hr />

cwd: “/path/to/production/yourapp/current”
port: “8003”
environment: production
address: 127.0.0.1
pid_file: “log/production.pid”
servers: 3

<ol>
	<li>Step two: Modify deploy.rb</li>
</ol><p>require &#8216;mongrel_cluster/recipes&#8217;<br /> <span class="caps">ENV</span>[&#8216;DEPLOY_TO&#8217;] ||= &#8216;staging&#8217;</p>

set :application, “yourapp”
set :repository, “http://path/to/svn/repo”
role :web, “192.168.1.1”
role :app, “192.168.1.1”

set :deploy_to, “/path/to/#{ENV[‘DEPLOY_TO’]}/#{application}”
set :mongrel_conf, “#{current_path}/config/#{ENV[‘DEPLOY_TO’]}.cluster.yml”
set :svn, “/usr/local/bin/svn”

<ol>
	<li>Step three: deploy</li>
</ol><p>No need to setup any custom tasks for each production environment, I simply set an environment variable and tell capistrano to deploy. Because I default <span class="caps">ENV</span>[&#8216;DEPLOY_TO&#8217;] to staging, deploying to staging is dead simple. I made it harder to deploy to production because one would think that if you have a staging step in your deployment processes at all, chances are typing the few extra characters to indicate a production deployment are worth it.</p>

DEPLOY_TO=production cap deploy

CNNi Style Headlines

Saturday, September 09 2006

I got a bit obsessive tonight and set myself up with a challenge. After watching one of CNN’s international news broadcasts, I got interested in recreating their new on screen headline graphics with HTML and Javascript. Here’s what it looks like:

Effect.BlindLeft = function(element) {
element = $(element);
element.makeClipping();
return new Effect.Scale(element, 0,
Object.extend({ scaleContent: false,
scaleY: false,
restoreAfterFinish: true,
afterFinishInternal: function(effect) {
effect.element.hide();
effect.element.undoClipping();
}
}, arguments1 || {})
);
}

Effect.BlindRight = function(element) {
element = $(element);
var elementDimensions = element.getDimensions();
return new Effect.Scale(element, 100,
Object.extend({ scaleContent: false,
scaleY: false,
scaleFrom: 0,
scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
restoreAfterFinish: true,
afterSetup: function(effect) {
effect.element.makeClipping();
effect.element.setStyle({width: ’0px’});
effect.element.show();
},
afterFinishInternal: function(effect) {
effect.element.undoClipping();
}
}, arguments1 || {})
);
}

Effect.DelayedChain = Class.create();
Object.extend(Effect.DelayedChain.prototype, {
initialize: function(effect, elements, options, timeout){
this.elements = elements;
this.effect = effect;
this.timeout = timeout || 100;
this.options = Object.extend({}, options || {});

this.afterFinish = this.options.afterFinish || Prototype.emptyFunction;
this.options.afterFinish = Prototype.emptyFunction;
setTimeout(this.action.bind(this),1);
},
action: function() {
if(this.elements.length){
new Effect[this.effect](this.elements.shift(), this.options);
setTimeout(this.action.bind(this), this.timeout);
} else {
if(this.afterFinish) this.afterFinish();
}
}
});

Effect.Chain = Class.create();
Object.extend(Effect.Chain.prototype, {
initialize: function(effect, elements, options){
this.elements = elements || [];
this.effect = effect;
this.options = options || {};
this.afterFinish = this.options.afterFinish || Prototype.emptyFunction;
this.options.afterFinish = this.nextEffect.bind(this);
setTimeout(this.nextEffect.bind(this), 1);
},
nextEffect: function(){
if(this.elements.length)
new Effect[this.effect](this.elements.shift(), this.options);
else
this.afterFinish();
}
});

.headline_text {
font-family: helvetica;
font-size: 2em;
color: white;
background-color: black;
padding: 4px;
}
.headline_bg {
font-family: helvetica;
font-size: 2em;
color: grey;
background-color: grey;
padding: 4px;
}

Primates learn how
to make blueberry pancakes and blintzes
.
.

/*
elements all sit off in an hidden overflow area at top of -300px.
This is so we can get the rendered width of the text, which we use to build out the divs and such. if it were display:none it’d have no width at all.

headline_bg’s build out from left to right, with about 4 frames total
then the headline words themselves, with black, fill in at about the same speed
*/

// get the widths of our two lines
var widths = [$(‘word_one’).offsetWidth+4,$(‘word_two’).offsetWidth+4];
var heights = [($(‘word_one’).offsetHeight+8)2,($(‘word_two’).offsetHeight+8)2];

// hide, set positions and widths of grey bg
$(‘head_bg_one’).style.display = “none”;
$(‘head_bg_two’).style.display = “none”;
$(‘head_bg_one’).style.width = widths0 + “px”;
$(‘head_bg_two’).style.width = widths1 + “px”;
$(‘head_bg_one’).style.top = -heights0 + “px”;
$(‘head_bg_two’).style.top = -heights1 + “px”;

// hide, set positions and widths of words
$(‘bg_one’).style.display = “none”;
$(‘bg_two’).style.display = “none”;

$(‘bg_one’).style.width = widths0 + “px”;
$(‘bg_two’).style.width = widths1 + “px”;
$(‘bg_one’).style.top = “0px”;
$(‘bg_two’).style.top = “0px”;

$(‘word’).style.height = (heights0) + “px”;

function shakedown() {
new Effect.DelayedChain(‘BlindRight’, [‘head_bg_one’,‘head_bg_two’, ‘bg_one’, ‘bg_two’], { duration: 0.25 }, 100);
}

setTimeout(‘shakedown()’, 100);

See it again.

It’s not perfect, but its fun. This can be dropped into Rails apps pretty easily or adapated to a non rails app. Check out more code after the jump.

Splog Attack

Wednesday, September 06 2006

Watching Luis von Ahn talk about building games to help solve problems with humans that computers can’t figure out is incredibly inspiring to me. He does a great job of breaking down what seems to work, and what doesn’t work, when designing a game that takes otherwise totally boring, menial tasks and turns them into compelling challenges.

While making the menial fun is great, I’m even more inspired by how simple some of these problems are to solve. I’ve mapped out several game ideas that, if executed with the same approach as Luis’ games, would be dead easy to build.

With that said, I’d like to present splog attack. This is what Luis would describe as a symetrical verification game. Player 1 sees a blog entry, and makes a single determination – is it spam or not. Player 2 makes the same determination. If both come to the same conclusion they get points, and both move on to another round.

But there’s a twist, interestingly, thrown in to fight against bots fouling the results. In addition to having to determine if the blog entry is spam, the players see three blog entries at a time from different blogs. Both players get the entries in random order, and must agree on all three blog entries, matching a spam label to the same spam label their counterpart matched. It doesn’t totally eliminate bots from making random choices, but it certainly makes it harder.

So what can you do with the results? Wired Magazine just ran an article talking about some of problems search engines face with detecting spam blogs, and how they are having a difficult time weeding out the good from the bad. It’s very easy for a human to see even just a sentence and make the determination that something isn’t right, but far more difficult for a computer.

Push a particular blog through that filter enough times and you end up having a pretty clear picture of what’s spam and what’s not. Reward players for figuring it out quickly, and they may even outpace the production rate of spam blog bots, turning the tide. Provide search engines with the results, and spam blogs may become irrellavent.

While part of me would love to see the game succeed in killing spam, I’d miss the weird sort of anonymous interaction with another human mind. When you’re both right, it feels great, and out ranking others doing the same thing is a lot of fun, especially knowing it’s helping fight spam blogs.

Foocamp 06 Report

Wednesday, August 30 2006

Aaron Huslage and I were talking about our experience at foocamp this year, and we both agreed that it was nearly religious. Everyone there, in one way or another, has helped shaped the past and current face of anything Internet related, and being able to talk face to face with pioneers and phenoms back to back was a unique and much savored experience.

The highlight of the trip, without a doubt, was playing Werewolf. It had been described to me prior to the trip, and I thought it sounded a bit silly, and not worth trying, but my opinion swayed rapidly. The first night I played, I still hadn’t met a lot of people and didn’t really know people by face, so I found myself unabashedly calling digg‘s CEO Jay Adelson “a shifty looking sort of guy, smug in his shiftiness.” In another game, I double crossed David Hornik. At first it was bitter sweet, as David’s a pretty nice guy, but I was a werewolf, which meant it was my job to secretly kill people off. David was next to me, convinced I wasn’t the werewolf. The second I got a chance, I killed him off, and felt a bit bad about it until I’d later found out that he was planning on getting me killed the next round anyways.

Playing werewolf with people I have massive respect for was great, but just being at the event at all was something I’ll always be thankful for. I learned a ton in a single weekend, made some great connections, and strengthened some of the ideas I’ve been carrying around for a while (ideas of which I’ll beging to unfold here as time goes on).

Knowing that my “good deeds” throughout the next year might help get me another invite makes for serious motivation, and I’m getting started now.

Thanks Tim! (and whoever nominated me to come this year!)

Japan. Toilets.

Thursday, August 24 2006

All I gotta say is there’s a lot of people in Japan who run as fast as they can to a toilet.

[youtube=http://www.youtube.com/watch?v=8gNsDp2N6yM]

I Can't Get Enough

Thursday, August 24 2006

I think I’m going to learn Japanese primarily so I can become better at finding things like this:

[youtube=http://www.youtube.com/watch?v=tVNNduNxbho]

Two Things

Wednesday, August 23 2006

For nearly a month I’ve been ignoring instant messenger. It’s not you, it’s me. It got to the point where even though I’d open iChat and “get online”, I’d hide the app all day, and totally ignore all incoming bips and beeps. It started getting really easy to ignore, and I haven’t really sat down and thought of why I continue to have it on at all until right now.

See, I suspect that if I leave it off for more than a few days, people will begin to wonder if I’m in some kind of trouble. When Buffington isn’t online, surely some sort of crazy must be percolating. So I leave it on so people know I’m alive. After fooCamp this weekend followed by some more travel, I’ll begin to respond. I promise.

Second thing. I’ve been home alone for the past several days and it’s not the thing for me. It’s nice getting a lot of uninterrupted computer time in, keeping that flow going, but it makes me crazy too. I talk out loud a lot, and practice improbably official voices for myself while cooking eggs and beans in the same pan, wondering if tomato soup would help. I practice shifty socked dances while the eggs and beans marinate in tomato soup, and consider adding the tamatillo sauce to my delightful looking meal.

Being alone is what makes people crack. People who’d otherwise lead healthy productive lives turn into babbling lunatics, and stand in the middle of a room wondering what to do next. Not having kids underfoot and tasks to complete spins me right out of control. It is not, for example, acceptable to be writing this with one sock on, sitting on a chair in the kitchen while the TV plays country music videos because it, in my own spoken out loud words (in a very official tone) “y’alls gotta make some kinda peace with yer fellow Americans, and country is the salve that’ll do ’er.”

If not for the Internet and all of her peoples, I’d be making mountains out of mashed potatoes by now.

Swedish Fart

Tuesday, August 22 2006

My linking to this is proof that I’m a dork. A 14 year old dork.

[youtube=http://www.youtube.com/watch?v=MPbB2P4XT_4]

Silent Torture

Tuesday, August 22 2006

I cried real tears watching this. The slapping machine about midway through sent me over the edge.

Graph Paper Generator

Sunday, August 20 2006

When it comes to geometry problems (such as the ones I’m faced with when building isometric perspective games), I typically do better if I can sketch out my desired outcome. Doing so can be a challenge in itself if my sketches aren’t proportionally correct, so I just sort of wing it.

Fed up with winging it, I set out to find some isometric graph paper to purchase, and instead found what I think is one of the coolest sites I’ve ever seen. Behold, the graph paper generator. Pick from several different styles of graph paper and tweak colors and grid size to your hearts content, generating a PDF that you can print when finished.