« October 2005 | Main | February 2006 »

November 21, 2005

Sweet mischievous Emma

It's hard to imagine how this sweet thing can be so dang mischevious and destructive. In the past few weeks, my lovely 2-year old daughter has done the following:

However, it's hard to be mad when she looks at you with her puppy dog eyes, and says, "I'm sorry daddy."

I think I managed to save 8 of the 10 fish by removing them from the tank as soon as I could. For a day or so, some of the fish weren't acting too well: swimming upside-down, and sideways, but somehow I think the remaining 8 have managed to pull through. Of course the fish tank inhabiter's union is sure to be pressing charges.

Posted by mark at 3:46 PM | Comments (2)

Google-Mart

I ran across an article this morning that I found rather intriguing.

Sam Walton Taught Google More About How to Dominate the Internet Than Microsoft Ever Did

By Robert X. Cringely

Posted by mark at 3:37 PM | Comments (0)

November 17, 2005

IPA

I brewed my first successful all-grain batch of beer last night. I brewed an IPA, and it weighed in at 1.075. I started around 6:00PM, and finished at 1:00AM -- including all of the clean up. It took a bit longer than expected, but I wasn't exactly efficient.The picture below on the right is my attempt to keep the mash at it's optimal temperature (150-158 degrees). I wrapped the whole mash tun in a blanket, and then put another pot over the top. Who knows how much this helped, but I did manage to keep it in the optimal temperature range for 1 hour and 15 minutes.

From Andy, who happened to brew an IPA on the same night:

"My original gravity came in at 1.080 which means that if I get the expected attenuation of 73-77% (attenuation is calculated as [(OG-FG)/(OG-1)] x 100) then my final gravity should come in around 1.022 and my beer will have an alcohol by volume of 7.6%, (1.080 - 1.022) * 131. A VERY respectible IPA."

Given this calculation, my final gravity should be around 1.020 with an alcohol volume of 7.2%. Not too shabby.

Here's the recipe:

Grain:
8lbs English Pale Maris Otter Malt
4lbs US Rye Malt
1lb. German Munich Malt
1lb. Crisp Caramunich Malt 15L
.5lb German light crystal malt

Hops:
1oz. Chinook 60 minutes
2oz. Crystal 60 minutes
1oz. Chinook 30 minutes
1oz. Amarillo 10 minutes
1oz Chinook 10 minutes
-----------
1oz. Chinook - dry hop
1oz. Amarillo - dry hop

Wyeast 1028 London Ale Yeast

For the most part, the process went smoothly. I picked up a few tips for my next batch:



 

Posted by mark at 12:29 PM | Comments (5)

November 15, 2005

Kegging homebrew is a total game changer

I suppose I should clarify, I haven’t kegged my beer yet, just Andy’s, but we’ve kegged 3 of his brews so far, all of which are quite superior (IPA, Nut Brown, and a Double Bastard clone). It’s a nice arrangement, Andy does all the work, and I do most of the consumption. ;-)

We’re using a 5 gallon Cornelius keg—aka Corny keg. First, you attach your C02 to the IN port on the keg. Then dial up the pressure to 25 PSI and leave it for approximately 3 days. Then, when you’re ready to dispense. Dial down pressure to 4 psi, release the pressure from the keg using the release valve on top, and attach the “picnic” dispenser to the OUT port (this can’t be connected while you’re carbonating at 25 PSI since the fittings are only rated to around 11 or 12 PSI). It’s that simple. If it’s not carbonated enough, you can detach the picnic dispenser, dial the pressure back up to 25 until it’s ready. I got the whole system for less than $200 (actually as a birthday present). The largest barrier to entry is the need for a spare refrigerator.

Posted by mark at 9:35 AM | Comments (0)

November 10, 2005

Some AJAX issues and some workarounds

In working with AJAX (which I should probably start calling AJAH, since my responseText is never XML -- but HTML), I've run across two issues. I was able to get both to work, but I thought there might be something I'm missing so here's my solutions, I'd welcome any feeback.

Scenario #1:
I have a website where the UI consists of a series of tabs. The active tab is loaded normally via the request. The unselected tabs are loaded asynchronously via AJAX into hidden divs. The responseText of one of the AJAX requests contains javascript, some that runs immediately in the context of the request, and some javascript functions that need to be stored in the DOM for later onClick events.

The problem: There's an option to the AJAX.Updater method, evalScripts: true, that you can use to cause any Javascript in the resulting responseText to run, and it works great for code that runs within the page immediately, but any declared functions that work when the page is being loaded, are subsequently lost and not stored in the DOM as expected. So, when you click on the tab, and then click an element intended to fire one of those functions, it complains. I was surprised the evalScripts didn't also load the functions into the DOM, but hey, I'm sure there's a perfectly good explanation. In order to get around this problem, I used the onComplete option in the AJAX.Updater method to run a function that searches the responseText for script blocks, and manually inserts them into the DOM. It works great. When doing this, you don't need to use the evalScripts parameter for other Javascript that needs to run immediately. Here's my function:
function insertScriptsInHead(ajaxObj)  {
    var allScriptsRegexp = /<script type="text/javascript">[\s\S]*?</script>/g;
    var results = ajaxObj.responseText.match(allScriptsRegexp);
    var head = document.getElementsByTagName("head")[0];

    if (results)  {
        // loop through all of the script blocks and append them to the head
        for (var i = 0; i < results.length; i++)  {
            var result = results[i].match(/<script type="text/javascript">([\s\S]*?)</script>/);
            var node = document.createElement('script');
            node.type = 'text/javascript';
            node.text = result[1];
            head.appendChild(node);
        }
    }
}
I should point out that I'm only developing for the latest versions of IE and Firefox, so I don't have any clue how this code might work in older browsers. If anyone has any knowledge of how to get Prototype to do this for me, I would love to hear it.

Scenario #2:
I launch a popup window with some AJAX that is fired via an onClick event in the context of the popup. After the AJAX is complete, I want the popup window to close itself via window.close().

The Problem:
For once in my life, I have to say that this works great in IE, but not in Firefox. In Firefox, a few seconds after failing to close the window, the browser will crash.

I was able to workaround this issue by storing a reference to the window object for the popup in the parent. Then, when the AJAX is complete, the popup calls a function in the parent via this command setTimeout('opener.closePopup()', 1000), which can close the window with something like this, popupWindowObj.close(). I'm not sure why I have to wrapper the opener.closePopup() command in a timout, since the AJAX is complete, but it doesn't work without a slight delay. So basically, instead of the popup closing itself, the opener (parent) does.

I actually had another issue very similar to this, in that a popup window was supposed to close itself, and launch an AJAX update method in the opener. However, this also didn't work, and I got it to work via the method described in this blog:
http://dema.ruby.com.br/articles/2005/05/06/be-careful-when-mixing-ajax-and-popup-windows-on-firefox

Again, if anyone has any feedback, I'd appreciate it. If not, I think that both of my workarounds are acceptable.

Posted by mark at 4:53 PM | Comments (6)

AJAX and Prototype

I've been doing a lot of DHTML Javascript and AJAX stuff for work lately. I was using my own library of AJAX functions, and an odd assortment DOM/Element modifying scripts. These methods actually worked quite well, but they seemed a bit disjointed. I recently discovered the Prototype Javascript Framework, and I'm really impressed. I was able to refactor my AJAX code to use Prototype in about 30 minutes. Prototype also offers a bunch of really slick DOM insertion methods that allow you to insert a block of code wherever you want in the DOM with ease. Adding event listeners also seems to be pretty easy. Here are two simple but fantastic shortcuts provided by Prototype:
$("elementid") is the same as document.getElementById("elementid")
$F("elementid") is the same as document.getElementById("elementid").value

The framework page itself has little in the way of documentation. Thankfully, I did find this document which outlines the framework, and shows some examples of use. I've also looked at the Prototype source javascript and it's remarkably clear.

The framework is in production use within the Ruby On Rails framework, so while I'm not a javascript guru by any means, I'm confident that it's sound code, and isn't going anywhere. I highly recommend checking it out.

Posted by mark at 4:11 PM | Comments (0)

Squeezebox network music player

I recently ripped my entire music collection to mp3 (200-300 CD's). I then purchased Slim Devices' Squeezebox network music player. It's awesome.

The Squeezebox plays any audio file on my computer through my home stereo via a wireless connection. Slim Devices has a slick web based application (SlimServer) that you use to search your library, setup playlists, administer the device, play music, adjust volume, shuffle, etc. We hosted a Halloween party at our house this past month, and about 10 minutes before people started arriving, I went to my computer, selected about 50 albums, clicked shuffle, and then play. It worked great.

The device also comes with a remote control that allows you to search for and play albums from the device itself, which sits near your stereo and connects via the standard RCA audio cables. You can also stream internet radio stations and podcasts through to the device, but I've been so busy rediscovering my old CDs that I haven't branched out too much. I'm a Grateful Dead fan, and thanks to Jonathan's Dead on Friday blog, I'm able to download his fantastic recommendations and listen in style. This truly was one of the best $300 dollars I've ever spent. The wired version is only $250.

There is one small caveat. Due to licensing restrictions, you can't stream DRM protected files natively. However, if your DRM files are of the ACC variety, and purchased via Apple iTunes, then you might be able to use JHymn to remove the restriction. I don't have *any* pirated music, and I don't endorse that type of theft at all, but I have no problem decrypting music that I purchased for personal use. I only own 5 albums that I purchased online, but I think they're WMV files, so JHymn isn't an option for me. However, I was able to use audio editing software to record the music as I played them through Windows Media Player (yes Topher, I use Windows). I then had to manually slice up each song into a separate file, and export each to an unprotected mp3 file. It was pretty tedious.

Posted by mark at 11:58 AM | Comments (2)