<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>ryan.sh</title><link href="http://ryan.sh/" rel="alternate"></link><link href="http://ryan.sh/feeds/text.atom.xml" rel="self"></link><id>http://ryan.sh/</id><updated>2010-07-07T14:58:00-04:00</updated><entry><title>Which loads faster?</title><link href="http://ryan.sh/2010/07/07/announcing-whichloadsfaster/" rel="alternate"></link><published>2010-07-07T14:58:00-04:00</published><updated>2010-07-07T14:58:00-04:00</updated><author><name>Ryan Witt</name></author><id>tag:ryan.sh,2010-07-07:2010/07/07/announcing-whichloadsfaster/</id><summary type="html">&lt;p&gt;I&amp;#8217;m pleased as punch to announce &lt;a href="http://whichloadsfaster.com/"&gt;whichloadsfaster.com&lt;/a&gt;, an &lt;a href="http://github.com/ryanwitt/whichloadsfaster/"&gt;open-source&lt;/a&gt; web performance tool where pages compete head-to-head in your browser to see who&amp;#8217;s&amp;nbsp;fastest!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://whichloadsfaster.com"&gt;
&lt;img title="Which loads faster?" src="http://farm5.static.flickr.com/4097/4770008437_2318faf48e.jpg"&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It started as an off-hand remark by my buddy, Ricardo: &amp;#8220;You should make a tool that can load two web pages side by side so you can see which one loads faster.&amp;#8221; I backpedaled a little at first, the way an overworked programmer does when someone suggests sticking another iron in the fire: &amp;#8220;Um, I don&amp;#8217;t know if that would really work out without writing a browser plugin.&amp;#8221; This, of course, meant something more like, &amp;#8220;Dude, I&amp;#8217;m lazy, and that sounds like a lot of work just to make another toy for our sales and marketing&amp;nbsp;guys.&amp;#8221;&lt;/p&gt;
&lt;p&gt;Ricardo had me though, it &lt;em&gt;would&lt;/em&gt; be cool to load two pages side-by-side and see the differences in real time. Dan, one of the aforementioned sales and marketing guys, was grinning next to us, enthused in an infectious way we hadn&amp;#8217;t seen nearly enough of since the arrival of his newborn. &amp;#8220;Ok guys,&amp;#8221; I entreated, &amp;#8220;maybe we can do it with iframes. I&amp;#8217;ve been having a lot of fun with &lt;a href="http://jquery.com/"&gt;jQuery&lt;/a&gt; lately, so let me play around with it and see what I come up&amp;nbsp;with.&amp;#8221;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://whichloadsfaster.com/?l=google.com&amp;r=duckduckgo.com"&gt;
&lt;img title="Have you ever used duckduckgo?" src="http://farm5.static.flickr.com/4142/4770771630_b8cc3c511f.jpg" /&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It &lt;em&gt;was&lt;/em&gt; a lot of fun to see two pages race against each other! Performance testing can be rather bland&amp;#8212;staring at waterfalls, repeating tests&amp;#8212;but watching a competition seems to be one of those things that humans are hard-wired to enjoy, and it tickled me like Elmo to think that I could take something I&amp;#8217;m &lt;a href="http://doeswebperformancematter.com/"&gt;passionate&lt;/a&gt; about&amp;#8212;web performance&amp;#8212;and make it a bit more&amp;nbsp;appealing!&lt;/p&gt;
&lt;p&gt;Don&amp;#8217;t get me wrong, there are many &lt;a href="http://www.webpagetest.org/forums/showthread.php?tid=12"&gt;good tools&lt;/a&gt; for web performance testing (notably, the open source &lt;a href="http://webpagetest.org"&gt;webpagetest.org&lt;/a&gt; and &lt;a href="http://showslow.com"&gt;showslow.com&lt;/a&gt;, which I will be working to integrate), but there are a few areas where I think whichloadsfaster adds some wicked weapons to the web performance&amp;nbsp;warchest:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Competition. Since it&amp;#8217;s easy to pit pages against each other, it becomes natural to check the performance of your most (and least) favorite sites, adding to the argument that &lt;a href="http://www.stevesouders.com/blog/2010/05/07/wpo-web-performance-optimization/"&gt;speed is a competitive advantage&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Testing in real time, while you watch. This has a big impact factor because a &amp;#8220;real&amp;#8221; test holds your&amp;nbsp;attention.&lt;/li&gt;
&lt;li&gt;Support for many browsers (&lt;span class="caps"&gt;IE&lt;/span&gt; 8/7/6, Firefox 3.0+, Chrome, Safari, most of mobile WebKit). Because of the detailed and invasive nature of performance testing, most performance tools are browser-specific. We make the tradeoff of collecting fewer events for the convenience of running the tool in every browser with no&amp;nbsp;install.&lt;/li&gt;
&lt;li&gt;Finally, there is a sharing link that developers can send out to run on their friends&amp;#8217; browsers. This feature is something I hope to develop further by adding a beacon &lt;span class="caps"&gt;API&lt;/span&gt; to automatically retrieve the results (see&amp;nbsp;below).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href="http://whichloadsfaster.com/?l=google.com&amp;r=bing.com"&gt;
&lt;img title="Bing is often faster for me on Firefox" src="http://farm5.static.flickr.com/4115/4772157060_ea6eaa134c.jpg"/&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Moving forward, I would like to improve whichloadsfaster in three major&amp;nbsp;areas:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Automation of test results. The &lt;a href="http://github.com/ryanwitt/whichloadsfaster/issues#issue/3"&gt;plan&lt;/a&gt; is to make a beacon &lt;span class="caps"&gt;API&lt;/span&gt; and a couple of example servers to collect the data (php, rails, django). This way, developers can just send out the link and sit back and see their performance results roll in across different locations and browsers. Fully automated testing would be as simple as causing a remote test machine to load the &lt;span class="caps"&gt;URL&lt;/span&gt; you want with your desired browser. This could be done with &lt;a href="http://seleniumhq.org/"&gt;selenium&lt;/a&gt; or a similar library, or possibly even built into whichloadsfaster (have to work around caching&amp;nbsp;issues).&lt;/li&gt;
&lt;li&gt;User perception testing. Since we&amp;#8217;re right in front of the user, we can ask them which page &lt;em&gt;appeared&lt;/em&gt; to load faster and get a better handle on that ephemeral but most important metric, &lt;a href="http://assets.en.oreilly.com/1/event/44/Building%20Performance%20Into%20the%20New%20Yahoo_%20Homepage%20Presentation.pdf"&gt;time to first interaction&lt;/a&gt;. I&amp;#8217;m &lt;a href="http://github.com/ryanwitt/whichloadsfaster/issues#issue/2"&gt;really excited&lt;/a&gt; about this&amp;nbsp;one! &lt;/li&gt;
&lt;li&gt;Integration with other tools. I plan to add a link to compare your pages on webpagetest.org using the video film strip feature, and also to test the individual pages in the waterfall tool. Since this project is about spreading the web performance gospel, I&amp;#8217;m open to linking to any useful performance&amp;nbsp;tool.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;A call for&amp;nbsp;help&lt;/h2&gt;
&lt;p&gt;The one problem that really bugs me is that whichloadsfaster &lt;a href="http://whichloadsfaster.com/?l=nytimes.com&amp;amp;r=myspace.com"&gt;doesn&amp;#8217;t play well&lt;/a&gt; with sites that try to break out of the iframe. This includes major sites that users want to compare, like myspace, twitter and nytimes.com. It&amp;#8217;s a terrible user experience to type in one of these and watch it unexpectedly take over the screen. I&amp;#8217;m completely sympathetic with using &lt;a href="http://seclab.stanford.edu/websec/framebusting/"&gt;framebusting&lt;/a&gt; to avoid clickjacking attacks, but I truly think this project is a legitimate reason to frame a site, and I want to create an excellent user experience (I mean, have you noticed the keyboard&amp;nbsp;shortcuts?). &lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve successfully tested a framebuster-buster that prevents sites from breaking out, but one of the side effects is that it also prevents outgoing links. In the end, the users should at least know what is going on and why the site can&amp;#8217;t be compared. I&amp;#8217;ll continue to work on this, but if you or a developer you know has expertise in this area, I would love suggestions and advice via &lt;a href="mailto:onecreativenerd@gmail.com"&gt;email&lt;/a&gt; or the &lt;a href="http://github.com/ryanwitt/whichloadsfaster/issues#issue/1"&gt;github issue&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Thanks for your &lt;a href="http://groups.google.com/group/whichloadsfaster/"&gt;feedback&lt;/a&gt; and &lt;a href="http://github.com/ryanwitt/whichloadsfaster/"&gt;involvement&lt;/a&gt;. Here&amp;#8217;s to making the web &lt;em&gt;just work&lt;/em&gt; for everybody on the&amp;nbsp;planet!&lt;/p&gt;</summary><category term="code"></category></entry><entry><title>Homemade iPad Case</title><link href="http://ryan.sh/2010/05/12/homemade-ipad-case/" rel="alternate"></link><published>2010-05-12T00:11:21-04:00</published><updated>2010-05-12T00:11:21-04:00</updated><author><name>Ryan Witt</name></author><id>tag:ryan.sh,2010-05-12:2010/05/12/homemade-ipad-case/</id><summary type="html">&lt;p&gt;A few days ago I popped into the &lt;a href="http://www.apple.com/retail/pasadena/"&gt;Pasadena Apple Store&lt;/a&gt; to look at iPad cases. I had &lt;em&gt;thought&lt;/em&gt; that my requirements were fairly simple: a landscape slipcase with easy iPad insertion/removal that can itself be easily moved in and out of my bag. Everything at the store, however, seemed bulky, expensive and&amp;nbsp;inelegant. &lt;/p&gt;
&lt;p&gt;His spidey sense tingling at my obvious indecision (or perhaps just tickled by his curly beard), an impetuously precocious Apple employee approached. His admonition, however, was not one I expected: &amp;#8220;now, nobody from &lt;em&gt;Apple&lt;/em&gt; is telling you this, but if I were you, I&amp;#8217;d &lt;a href="http://www.etsy.com/search_results.php?search_query=ipad+case&amp;amp;search_type=handmade&amp;amp;ref=auto"&gt;go to etsy&lt;/a&gt; and buy a handmade case instead.&amp;#8221; Cue my white liberal guilt.&lt;sup&gt;&lt;a name="homemade-ipad-case-fn1-a" href="#homemade-ipad-case-fn1"&gt;1&lt;/a&gt;&lt;/sup&gt; Being thus rendered unable to feel good about buying yet another petroleum-derived consumer product made by underpaid workers in the third world, I decided to make my own&amp;nbsp;case.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/twocreativenerds/4592663957/" title="finished product"&gt;&lt;img src="http://farm5.static.flickr.com/4008/4592663957_cd2886ba35.jpg" width="500" height="375" alt="finished product" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To be fair, the case is made from &lt;a href="http://www.flickr.com/photos/twocreativenerds/4593525930/in/set-72157623902162655/"&gt;vegetarian leather&lt;/a&gt;, which is still petroleum-derived&lt;sup&gt;&lt;a name="homemade-ipad-case-fn2-a" href="#homemade-ipad-case-fn2"&gt;2&lt;/a&gt;&lt;/sup&gt;, but I rescued the material from a doomed college project &lt;sup&gt;&lt;a name="homemade-ipad-case-fn3-a" href="#homemade-ipad-case-fn3"&gt;3&lt;/a&gt;&lt;/sup&gt; so I think it technically constitutes&amp;nbsp;recycling.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/twocreativenerds/4593285468/" title="soft and fuzzy inside!"&gt;&lt;img src="http://farm4.static.flickr.com/3381/4593285468_1835cf3bd5.jpg" width="500" height="375" alt="soft and fuzzy inside!" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The inside of the case is made from &lt;a href="http://www.flickr.com/photos/twocreativenerds/4593527354/in/set-72157623902162655/"&gt;car headliner fabric&lt;/a&gt;. You know, the kind that you used to get yelled at for picking off the roof of your parents&amp;#8217; Plymouth Volare? No? Was that just&amp;nbsp;me?&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/twocreativenerds/4593526630/" title="two pieces of fabric"&gt;&lt;img src="http://farm5.static.flickr.com/4027/4593526630_88136eb63e.jpg" width="500" height="375" alt="two pieces of fabric" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The entire case is made from two pieces of fabric, folded onto itself in various ways. All edges had to be folded over twice because the veggie leather is backed with fuzzy white stuff which doesn&amp;#8217;t look good when it&amp;#8217;s exposed. The exact dimensions are a closely guarded secret &lt;sup&gt;&lt;a name="homemade-ipad-case-fn4-a" href="#homemade-ipad-case-fn4"&gt;4&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/twocreativenerds/4592908187/" title="sewing seams"&gt;&lt;img src="http://farm2.static.flickr.com/1402/4592908187_a0b56a5463.jpg" width="500" height="375" alt="sewing seams" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Seams were sewn on a &lt;a href="http://blog.sew-classic.com/2009/03/14/classic-singer-301-301a-vintage-sewing-machine-review.aspx"&gt;Singer 301a&lt;/a&gt; that belonged to my late grandmother. I&amp;#8217;m afraid I have a long way to go in learning how to &lt;a href="http://static.onecreativeblog.com/files/singer-301-manual.pdf"&gt;use it properly&lt;/a&gt;, but I hope my attempt would have made her&amp;nbsp;proud.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/twocreativenerds/4593528546/" title="scotch tape ftw"&gt;&lt;img src="http://farm2.static.flickr.com/1100/4593528546_d7bd1d415b.jpg" width="375" height="500" alt="IMG_3183" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Using scotch tape along the seams really helped the machine glide along without bunching the material. The tape can be removed afterward by carefully pulling perpendicular to the seam, otherwise you end up with a bunch of small tape pieces that must be pulled out from under the thread by&amp;nbsp;hand.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/twocreativenerds/4598552485/" title="train buddy"&gt;&lt;img src="http://farm5.static.flickr.com/4051/4598552485_dbd787d332.jpg" width="500" height="375" alt="train buddy" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The finished case works nicely for propping the iPad up while typing on the&amp;nbsp;train. &lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/twocreativenerds/4592664573/" title="ample posterior"&gt;&lt;img src="http://farm4.static.flickr.com/3551/4592664573_2e27c8a3b7.jpg" width="500" height="375" alt="ample posterior" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I enjoyed this project &lt;em&gt;immensely&lt;/em&gt;. It was a real kick to make something I&amp;#8217;ve never attempted before from materials that were lying around. Hope you enjoyed it&amp;nbsp;too!&lt;/p&gt;
&lt;p&gt;More pictures and comments can be found at this project&amp;#8217;s &lt;a href="http://www.flickr.com/photos/twocreativenerds/sets/72157623902162655/"&gt;flickr set &amp;rarr;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Oh, and to my bearded muse in the bright turquoise t-shirt, if you&amp;#8217;re reading this and still haven&amp;#8217;t made up your mind about your own case, I&amp;#8217;ll totally make you one of&amp;nbsp;these.&lt;/p&gt;
&lt;div class="footnotes"&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a name="homemade-ipad-case-fn1"&gt;&lt;/a&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/td&gt;
&lt;td&gt;While I am white, I&amp;#8217;m not as &lt;i&gt;that&lt;/i&gt; liberal and harbor virtually no guilt. &lt;a href="#homemade-ipad-case-fn1-a"&gt; &amp;#8617;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a name="homemade-ipad-case-fn2"&gt;&lt;/a&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/td&gt;
&lt;td&gt;Which means it&amp;#8217;s made from animals that died naturally a long time ago, rather than recently by human hands. &lt;a href="#homemade-ipad-case-fn2-a"&gt; &amp;#8617;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a name="homemade-ipad-case-fn3"&gt;&lt;/a&gt;&lt;sup&gt;3&lt;/sup&gt;
&lt;td&gt;I was trying to make a folding poker table with a nice felt surface and leather border. Then someone stole all the wood pieces I had cut along with the brass hardware. Sad face. &lt;a href="#homemade-ipad-case-fn3-a"&gt; &amp;#8617;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a name="homemade-ipad-case-fn4"&gt;&lt;/a&gt;&lt;sup&gt;4&lt;/sup&gt;
&lt;td&gt;Meaning they were pulled directly from my posterior region and I might not be able to reproduce them if I wanted to. &lt;a href="#homemade-ipad-case-fn4-a"&gt; &amp;#8617;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/div&gt;</summary><category term="article"></category></entry><entry><title>Steam Cars</title><link href="http://ryan.sh/2010/05/02/steam-cars/" rel="alternate"></link><published>2010-05-02T19:26:00-04:00</published><updated>2010-05-02T19:26:00-04:00</updated><author><name>Ryan Witt</name></author><id>tag:ryan.sh,2010-05-02:2010/05/02/steam-cars/</id><summary type="html">&lt;p&gt;A couple Saturdays ago, &lt;a href="http://twitter.com/kriskowal"&gt;@kriskowal&lt;/a&gt; and I found ourselves at a meeting of the Southern California chapter of the &lt;a href="http://www.steamautomobile.com/lcc/index.htm"&gt;Steam Automobile Club of America&lt;/a&gt; of which Kris&amp;#8217;s father is president. It&amp;#8217;s been a long while since I&amp;#8217;ve seen these steam cars in action. Getting to ride on these gentle and majestic contraptions was a real&amp;nbsp;treat:&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://farm3.static.flickr.com/2791/4521104369_68f75c62cd_d.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://farm5.static.flickr.com/4069/4521739960_d89a427b46_d.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;Kris&amp;#8217;s father brought the &lt;em&gt;Dampf &amp;#8216;Bil&lt;/em&gt;, a wood-burning, steam powered go-kart of&amp;nbsp;sorts:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Dampf 'Bil" src="http://farm5.static.flickr.com/4056/4520967851_1d74ddda00_d.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;Kris explains more about how it&amp;nbsp;works:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It&amp;#8217;s a really simple car, a model of the minimal steam powered automobile, built on the chassis of a wood trash-cart.  The steam generator is a Dixon Boilerworks &amp;#8220;fire tube&amp;#8221; boiler; it burns wood under a five gallon reservoir with tubes that allow the heated air to exchange with the water.  It operates between 40 and 75 &lt;span class="caps"&gt;PSI&lt;/span&gt;.  The steam drives two 5&amp;#8221; tall double-acting steam engines, offset by 90 degrees, attached directly to the rear-right wheel with a bike chain (no derailleur).  The boiler is fed by a highly ineffective hydraulic landing gear pump from a 2 gallon antifreeze container repurposed for water.  The boiler also has a garden hose attachment which we use to fill the boiler when cold, and to &amp;#8220;blow down&amp;#8221;: use the boiler&amp;#8217;s remaining pressure to empty the&amp;nbsp;boiler.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Look at it go! (that&amp;#8217;s me&amp;nbsp;riding.)&lt;/p&gt;
&lt;p&gt;&lt;embed height="507" src="http://video.google.com/googleplayer.swf?videoUrl=http%3A%2F%2Fv6.nonxt6.googlevideo.com%2Fvideoplayback%3Fid%3D71b008b26d93d7b9%26itag%3D5%26begin%3D0%26len%3D2147483647%26app%3Dpicasa%26et%3DINVALID%26el%3DINVALID%26ip%3D0.0.0.0%26ipbits%3D0%26expire%3D2848073554%26sparams%3Did%252Citag%252Cip%252Cipbits%252Cexpire%26signature%3D2DE2F8D6F1DDF2475294261C3E762F609D30AFB.62768AC1BB7752D899976AD35526FD24B97E5A89%26key%3Dck1&amp;amp;hl=en&amp;amp;messagesUrl=http%3A%2F%2Fvideo.google.com%2FFlashUiStrings.xlb%3Fframe%3Dflashstrings%26hl%3Den&amp;amp;speedcontrol=0" type="application/futuresplash" width="500" flashvars="fs=true&amp;amp;playerMode=normal" allowfullscreen="true" allowscriptaccess="always" bgcolor="#fff" quality="best" salign="TL" scale="noScale" swliveconnect="true" wmode="opaque" style="width: 500px; height: 396px; "&gt;&lt;/p&gt;
&lt;p&gt;The only problem is that one tends to get covered in soot while driving it (that&amp;#8217;s&amp;nbsp;Kris):&lt;/p&gt;
&lt;p&gt;&lt;img alt="Kris covered in soot" src="http://farm5.static.flickr.com/4061/4520968797_e10a8f8b4a_d.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;As you can see, fun was had by all.&amp;nbsp;:)&lt;/p&gt;</summary><category term="article"></category></entry><entry><title>Easter Dinner</title><link href="http://ryan.sh/2010/04/08/easter-dinner/" rel="alternate"></link><published>2010-04-08T01:01:00-04:00</published><updated>2010-04-08T01:01:00-04:00</updated><author><name>Ryan Witt</name></author><id>tag:ryan.sh,2010-04-08:2010/04/08/easter-dinner/</id><summary type="html">&lt;p&gt;Lamb by yours truly. Potatoes by @ErikDreyer and Diana. Salad by @jasonyo and &lt;span class="caps"&gt;SJ&lt;/span&gt;. Asparagus by steam&amp;nbsp;pot.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://ryan.sh/2010/04/08/easter-dinner/easter-dinner.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;The salad contained spinach, pears, medium-boiled eggs and from-scratch candied walnuts! It was quite a hit. The potatoes had tons of garlic, and complimented the lamb very&amp;nbsp;nicely.&lt;/p&gt;
&lt;p&gt;The lamb is from an &lt;a href="http://www.epicurious.com/recipes/food/views/Grilled-Leg-of-Lamb-with-Rosemary-Garlic-and-Mustard-358196"&gt;epicurious recipie&lt;/a&gt; that I followed pretty closely. We started with two lamb legs from Costco totaling about 8 pounds of meat after trimming the excess fat. I tucked substantially more garlic into the meat than recommended&amp;#8212;approximately 8 cloves cut into about 32 slices&amp;#8212;and let the prepared meat marinate&amp;nbsp;overnight.&lt;/p&gt;
&lt;p&gt;Cooking was done on the propane grill, and turned out to be the biggest disappointment of the meal (at least to me) because although the flavor was great, the smaller pieces of lamb were overcooked. I had the thermometer in one of the larger pieces and cut the heat when the middle of the largest one reached 145&amp;deg;F. In hindsight, I should have measured each piece and pulled it from the heat when it reached 130&amp;deg;F, as recommended by the recipe. Oh well, one of the main reasons to write this down is so I can remember what I did wrong. Aren&amp;#8217;t you glad we live in a world where we can google our past&amp;nbsp;misteaks?&lt;/p&gt;
&lt;p&gt;&amp;#8230;&lt;/p&gt;
&lt;p&gt;You may have noticed the topic of my site inching insidiously toward food. To tell you the truth, I&amp;#8217;m just as surprised as you are. I mean, I&amp;#8217;m supposed to be writing about programming, poetry and bad puns, but I end up taking pictures of dinner&amp;nbsp;instead. &lt;/p&gt;
&lt;p&gt;Well, them&amp;#8217;s tough beans (fava maybe? Haven&amp;#8217;t attempted those yet). The &lt;a href="/tagged/food"&gt;food posts&lt;/a&gt; will likely continue as I have no plans to imperil my excellent relationship with eaten things anytime&amp;nbsp;soon.&lt;/p&gt;
&lt;p&gt;Stay tuned for a large flickr set of food-themed photos! Also expect some posts about my new &lt;a href="http://onecreativeblog.com/post/492168809/espresso-machine-is-here"&gt;espresso machine&lt;/a&gt; as I continue my relentless pursuit of the &lt;a href="http://coffeegeek.com/opinions/coffeeatthemoment/11-12-2002"&gt;god shot&lt;/a&gt;.&lt;/p&gt;</summary><category term="food"></category><category term="espresso"></category></entry><entry><title>The Cylon Among Us</title><link href="http://ryan.sh/2008/11/28/the-cylon-among-us/" rel="alternate"></link><published>2008-11-28T04:42:44-05:00</published><updated>2008-11-28T04:42:44-05:00</updated><author><name>Ryan Witt</name></author><id>tag:ryan.sh,2008-11-28:2008/11/28/the-cylon-among-us/</id><summary type="html">&lt;p&gt;In a shocking confirmation that all this has happened before, and will happen again, Earth scientists have discovered hitherto unnoticed monuments from the ancient Cylon race, hiding in plain sight in the Los Angeles freeway&amp;nbsp;system.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Cylon Monument" src="http://ryan.sh/2008/11/28/the-cylon-among-us/cylon1.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;The monuments are all located in Garden Grove, &lt;a href="http://maps.google.com/maps?f=q&amp;amp;hl=en&amp;amp;geocode=&amp;amp;sll=34.145892,-118.132351&amp;amp;sspn=0.363696,0.696259&amp;amp;g=Pasadena,+CA&amp;amp;ie=UTF8&amp;amp;ll=33.775723,-117.852402&amp;amp;spn=0.091321,0.174065&amp;amp;z=13&amp;amp;layer=c&amp;amp;cbll=33.775623,-117.853332&amp;amp;panoid=muIChTlsmlaqs-r2-kaS4w&amp;amp;cbp=12,204.153831032658,,0,8.063065525549987"&gt;along California State Route 22&lt;/a&gt;, and appear to have been integrated into the freeway&amp;#8217;s sound wall. Mysteriously, no-one, not even Garden Grove residents, seem to have noticed the monuments until now. Construction plans for the sound wall show openings for the monuments, but make no explicit mention of them. Neither Caltrans nor the &lt;abbr title="Orange County Transportation Authority"&gt;&lt;span class="caps"&gt;OCTA&lt;/span&gt;&lt;/abbr&gt; would comment on the construction&amp;nbsp;plans.&lt;/p&gt;
&lt;p&gt;&lt;img alt="They just built the freeway walls around them..." src="http://ryan.sh/2008/11/28/the-cylon-among-us/cylon2.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;Resident Nicki Clyne, a flight mechanic and a regular on the 22, is credited with first noticing the structures. &amp;#8220;It&amp;#8217;s strange to drive past something every day and never see it. When my daughter was born, I was really distracted, but as she got older, I began to notice things that I used to miss. Discovering that something so close was of Cylon origin really threw me for a&amp;nbsp;loop.&amp;#8221;&lt;/p&gt;
&lt;p&gt;&lt;img alt="A look LaForge would be proud of" src="http://ryan.sh/2008/11/28/the-cylon-among-us/cylon_closeup.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;We approached several experts in the field of speculative Cylon anthropology who independently verified that the monuments are indeed of Cylon construction. &amp;#8220;It was the eye mosaic that pushed the monument origin into the realm of statistical certainty&amp;#8221;, said Dr. James Callis, Senior Fellow at the Forensic [cylon] Research Advancement Centre (&lt;span class="caps"&gt;FRAC&lt;/span&gt;). &amp;#8220;Throughout our conception of Cylon history, the &amp;#8216;scanning eye&amp;#8217; has been an iconic design centerpiece for the more mechanical models. Through the process of elimination, we&amp;#8217;ve concluded that the only explanation is that the monuments must have been erected by the ancient&amp;nbsp;Cylon.&amp;#8221;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Will we ever know why they're here?" src="http://ryan.sh/2008/11/28/the-cylon-among-us/cylon3.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;Researchers from &lt;span class="caps"&gt;FRAC&lt;/span&gt; have put forward the theory that the placement of the monuments influenced the 22 freeway&amp;#8217;s route from the very beginning. Caltrans and &lt;span class="caps"&gt;OCTA&lt;/span&gt; refused to comment on this theory, but city officials have welcomed the new additions as part of the rich cultural heritage of Garden Grove, and are in the process of planning a 3 day festival to commemorate the&amp;nbsp;discovery.&lt;/p&gt;
&lt;p&gt;Photo Credit: Vi&amp;nbsp;Tran&lt;/p&gt;</summary></entry><entry><title>Django Login Required Middleware</title><link href="http://ryan.sh/2008/11/10/django-login-required-middleware/" rel="alternate"></link><published>2008-11-10T19:58:00-05:00</published><updated>2008-11-10T19:58:00-05:00</updated><author><name>Ryan Witt</name></author><id>tag:ryan.sh,2008-11-10:2008/11/10/django-login-required-middleware/</id><summary type="html">&lt;p&gt;I&amp;#8217;ve been doing a lot programming in the &lt;a href="http://djangoproject.com"&gt;Django web framework&lt;/a&gt; lately and thought this code snippet that forces a user to login to your site before viewing any pages might come in handy. If you&amp;#8217;re already a djangoperson, &lt;a href="#code"&gt;skip ahead to the code&lt;/a&gt;, otherwise, I&amp;#8217;ll give a bit of&amp;nbsp;background.&lt;/p&gt;
&lt;p&gt;In Django, your code that responds to each incoming request is organized into functions called &lt;em&gt;views&lt;/em&gt; which take your &lt;span class="caps"&gt;HTTP&lt;/span&gt; request and turn it into a page that the user can view. It&amp;#8217;s a common practice in Django to augment your views using a python construct called a &lt;a href="http://askawizard.blogspot.com/2008/09/decorators-python-saga-part-2_28.html"&gt;decorator&lt;/a&gt;. This allows you add additional functionality without having to write a bunch of code. For example, Django provides a decorator called &lt;code&gt;login_required&lt;/code&gt; that takes one of your views and prevents a user from seeing it unless they are logged&amp;nbsp;in:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nd"&gt;@login_required&lt;/span&gt;      &lt;span class="c1"&gt;# This is the decorator! One line... simple.&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Do something here to turn the request into an HTML page.&lt;/span&gt;
    &lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Sometimes it&amp;#8217;s a real pain to use the &lt;code&gt;login_required&lt;/code&gt; decorator all over the views of your complicated site. What if you forget to add it to view that contains sensitive information? Fortunately, Django allows you to write &lt;em&gt;middleware&lt;/em&gt; that gets access to each request so you can add functionality that can be applied to your whole site. My middleware simply intercepts each request and redirects users to the site login page if they haven&amp;#8217;t logged in. It also allows you to give of exceptions (in the form of regular expressions), i.e. pages that can be viewed without logging&amp;nbsp;in:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.http&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;HttpResponseRedirect&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.conf&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;re&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nb"&gt;compile&lt;/span&gt;

&lt;span class="n"&gt;EXEMPT_URLS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LOGIN_URL&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lstrip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))]&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;LOGIN_EXEMPT_URLS&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;EXEMPT_URLS&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;expr&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LOGIN_EXEMPT_URLS&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LoginRequiredMiddleware&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="sd"&gt;    Middleware that requires a user to be authenticated to view any page other&lt;/span&gt;
&lt;span class="sd"&gt;    than LOGIN_URL. Exemptions to this requirement can optionally be specified&lt;/span&gt;
&lt;span class="sd"&gt;    in settings via a list of regular expressions in LOGIN_EXEMPT_URLS (which&lt;/span&gt;
&lt;span class="sd"&gt;    you can copy from your urls.py).&lt;/span&gt;

&lt;span class="sd"&gt;    Requires authentication middleware and template context processors to be&lt;/span&gt;
&lt;span class="sd"&gt;    loaded. You&amp;#39;ll get an error if they aren&amp;#39;t.&lt;/span&gt;
&lt;span class="sd"&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;process_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;user&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;The Login Required middleware&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt; requires authentication middleware to be installed. Edit your&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt; MIDDLEWARE_CLASSES setting to insert&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt; &amp;#39;django.contrib.auth.middlware.AuthenticationMiddleware&amp;#39;. If that doesn&amp;#39;t&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt; work, ensure your TEMPLATE_CONTEXT_PROCESSORS setting includes&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt; &amp;#39;django.core.context_processors.auth&amp;#39;.&amp;quot;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_authenticated&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path_info&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lstrip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nb"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;EXEMPT_URLS&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;HttpResponseRedirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LOGIN_URL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# settings.py&lt;/span&gt;

&lt;span class="n"&gt;LOGIN_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;/login/&amp;#39;&lt;/span&gt;

&lt;span class="n"&gt;LOGIN_EXEMPT_URLS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
 &lt;span class="s1"&gt;r&amp;#39;^about\.html$&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="s1"&gt;r&amp;#39;^legal/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# allow any URL under /legal/*&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;MIDDLEWARE_CLASSES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="c1"&gt;# ...&lt;/span&gt;
    &lt;span class="s1"&gt;&amp;#39;python.path.to.LoginRequiredMiddleware&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;While writing this, I found similar solutions by &lt;a href="http://davyd.livejournal.com/262859.html"&gt;davyd&lt;/a&gt; and a &lt;a href="http://groups.google.com/group/django-users/browse_thread/thread/48da19a450ac7869/6762fcc0a46a1d04?lnk=gst&amp;amp;q=login+required+middleware#6762fcc0a46a1d04"&gt;discussion&lt;/a&gt; on the django-users list, but neither had the flexibility of using regular&amp;nbsp;expressions.&lt;/p&gt;
&lt;p&gt;Please let me know if this was useful to you, or if you find any&amp;nbsp;problems!&lt;/p&gt;</summary><category term="django"></category><category term="github"></category><category term="python"></category><category term="code"></category></entry></feed>