<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

 <title>footle</title>
 <link href="https://footle.org/atom.xml" rel="self"/>
 <link href="https://footle.org/"/>
 <updated>2026-04-08T04:25:42-07:00</updated>
 <id>https://footle.org</id>
 <author>
   <name>Brad Greenlee</name>
   <email>brad@footle.org</email>
 </author>

 
 
 <entry>
   <title>First Post!</title>
   <link href="https://footle.org/2025/04/14/first-post!/"/>
   <updated>2025-04-14T10:23:44-07:00</updated>
   <id>https://footle.org/2025/04/14/first-post!</id>
   <content type="html">&lt;p&gt;I’m building an iOS app that will make it easy to post to any GitHub-based blog (like this one) from iOS/iPadOS. I’ve finally got the basic pieces together to do an actual post from my phone, and this is it!&lt;/p&gt;

&lt;p&gt;My next step is to set up a Sharing Extension so you can write your post in any app (like Apple Notes) and just share to post.&lt;/p&gt;

&lt;p&gt;Right now the app just supports Jekyll, but it should be easy to adapt to support any GitHub-based workflow.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Screensaver Spelunking</title>
   <link href="https://footle.org/2025/03/21/screensaver-spelunking/"/>
   <updated>2025-03-21T11:14:00-07:00</updated>
   <id>https://footle.org/2025/03/21/screensaver-spelunking</id>
   <content type="html">&lt;p&gt;Macos Sonoma brought to the Mac the &lt;a href=&quot;https://bzamayo.com/watch-all-the-apple-tv-aerial-video-screensavers#9c6b969b62012359e5a4ead2ba3889e8&quot;&gt;amazing aerial screensavers/wallpapers&lt;/a&gt; that can be found on the AppleTV. (I say screensavers/wallpapers because you can choose to have your wallpaper be a frame of whatever your screeensaver is.)&lt;/p&gt;

&lt;p&gt;One thing missing, though, are the descriptions of what is being displayed. If I see some amazing place my first question is “where is that?” On the AppleTV you can view the description by clicking (swiping?) up on the remote. There doesn’t seem to be any secret keys or incantations to get it to display on the Mac, though, even though that information is available. If you go into Settings -&amp;gt; Screen Saver on your Mac, you’ll see descriptions:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/images/screensavers/screensaver-settings.png&quot; alt=&quot;Screensaver Descriptions&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I figured it couldn’t be that hard to (a) find out what the current screensaver is, (b) look up the description somewhere, and (c) find easy way to show that information. It turned out to be not easy, but I did figure it out.&lt;/p&gt;

&lt;h2 id=&quot;the-screensavers&quot;&gt;The Screensavers&lt;/h2&gt;

&lt;p&gt;Searching for “macos where are aerial screensavers stored” gives &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/Library/Application Support/com.apple.idleassetsd/Customer/4KSDR240FPS&lt;/code&gt;. If you open that directory in Finder (run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;open /Library/Application\ Support/com.apple.idleassetsd/Customer/4KSDR240FPS&lt;/code&gt; from the Terminal), you’ll see they’re all MOV videos. Apparently &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;idleassetsd&lt;/code&gt; is the process that handles the downloading and display of the aerial screensavers.&lt;/p&gt;

&lt;p&gt;My first thought was that maybe the descriptions were encoded in the video somehow, but after digging around in them a bit, that turned out not to be the case.&lt;/p&gt;

&lt;h2 id=&quot;the-screensaver-database&quot;&gt;The Screensaver Database&lt;/h2&gt;

&lt;p&gt;I looked in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/Library/Application\ Support/com.apple.idleassetsd/&lt;/code&gt; directory and lo! there was sqlite database: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Aerial.sqlite&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sqlite&amp;gt; .tables
ZASSET             ZUSER              Z_1SUBCATEGORIES   Z_METADATA
ZCATEGORY          Z_1CATEGORIES      Z_2ACTIVEFORUSERS  Z_MODELCACHE
ZSUBCATEGORY       Z_1PINNEDFORUSERS  Z_3ACTIVEFORUSERS  Z_PRIMARYKEY
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Exploring these tables, we find some information, but nothing terribly descriptive:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sqlite&amp;gt; select ZACCESSIBILITYLABEL from ZASSET limit 3;
Iran and Afghanistan
Caribbean
Africa and the Middle East
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;ripgrep-to-the-rescue&quot;&gt;Ripgrep to the Rescue&lt;/h2&gt;

&lt;p&gt;Since I knew the description strings had to be &lt;em&gt;somewhere&lt;/em&gt; on my hard drive, the next obvious move was to just search for them. I picked a word from one of the descriptions that was unlikely to be found elsewhere—”Temblor,” from “California’s Temblor Range”—and fired up &lt;a href=&quot;https://github.com/BurntSushi/ripgrep&quot;&gt;ripgrep&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;gt; rg Temblor /Library/Application\ Support/com.apple.idleassetsd/
&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Nothing. Hmm. After a bit of head-scratching and poking around in other places, I realized that ripgrep by default doesn’t search binary files. So:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;gt; rg --binary Temblor /Library/Application\ Support/com.apple.idleassetsd/
/Library/Application Support/com.apple.idleassetsd/Customer/TVIdleScreenStrings.bundle/sv.lproj/Localizable.nocache.strings: binary file matches (found &quot;\0&quot; byte around offset 12)

/Library/Application Support/com.apple.idleassetsd/Customer/TVIdleScreenStrings.bundle/es_419.lproj/Localizable.nocache.strings: binary file matches (found &quot;\0&quot; byte around offset 12)

...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Bingo! A strings bundle is a collection of localized strings. Given a key that uniquely identifies a string and a language, you can look up the translation of that string in that language.&lt;/p&gt;

&lt;p&gt;The next piece was to find all the string keys. The above &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ZASSET&lt;/code&gt; table has a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ZLOCALIZEDNAMEKEY&lt;/code&gt; column. But, while poking around in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;com.apple.idleassetsd&lt;/code&gt; folder, I found an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;entries.json&lt;/code&gt; file that had everything I needed in one file:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;gt; cat &quot;/Library/Application Support/com.apple.idleassetsd/Customer/entries.json&quot; | jq &quot;.assets[0]&quot;
{
  &quot;id&quot;: &quot;009BA758-7060-4479-8EE8-FB9B40C8FB97&quot;,
  &quot;showInTopLevel&quot;: true,
  &quot;shotID&quot;: &quot;GMT026_363A_103NC_E1027_KOREA_JAPAN_NIGHT&quot;,
  &quot;localizedNameKey&quot;: &quot;GMT026_363A_103NC_E1027_KOREA_JAPAN_NIGHT_NAME&quot;,
  &quot;accessibilityLabel&quot;: &quot;Korea and Japan Night&quot;,
  &quot;pointsOfInterest&quot;: {
    &quot;60&quot;: &quot;GMT026_363A_103NC_E1027_60&quot;,
    &quot;150&quot;: &quot;GMT026_363A_103NC_E1027_150&quot;,
    &quot;0&quot;: &quot;GMT026_363A_103NC_E1027_0&quot;,
    &quot;32&quot;: &quot;GMT026_363A_103NC_E1027_32&quot;,
    &quot;195&quot;: &quot;GMT026_363A_103NC_E1027_195&quot;,
    &quot;22&quot;: &quot;GMT026_363A_103NC_E1027_22&quot;,
    &quot;110&quot;: &quot;GMT026_363A_103NC_E1027_110&quot;,
    &quot;260&quot;: &quot;GMT026_363A_103NC_E1027_260&quot;,
    &quot;180&quot;: &quot;GMT026_363A_103NC_E1027_180&quot;
  },
  &quot;previewImage&quot;: &quot;https://sylvan.apple.com/itunes-assets/Aerials126/v4/51/ff/08/51ff0824-8da5-78f0-e218-9e61264965bb/Space_Korea_Japan_01@2x.png&quot;,
  &quot;includeInShuffle&quot;: true,
  &quot;url-4K-SDR-240FPS&quot;: &quot;https://sylvan.apple.com/itunes-assets/Aerials116/v4/cb/5b/50/cb5b5035-6701-619f-9065-3d7d0e5fbef4/comp_GMT026_363A_103NC_E1027_KOREA_JAPAN_NIGHT_v18_SDR_PS_20180907_240fps_0d0095d4-5875-4d43-a1a8-7dc915b11b9dq24_sRGB_tsa.mov&quot;,
  &quot;subcategories&quot;: [
    &quot;61171241-39F3-4ADE-84AA-9CD4EE4A78DA&quot;
  ],
  &quot;preferredOrder&quot;: 9,
  &quot;categories&quot;: [
    &quot;55B7C95D-CEAF-4FD8-ADEF-F5BC657D8F6D&quot;
  ]
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It looks like you can even get different descriptions based on how far along you are in the screensaver video.&lt;/p&gt;

&lt;h2 id=&quot;the-final-boss-getting-the-active-screensaver&quot;&gt;The Final Boss: Getting the Active Screensaver&lt;/h2&gt;

&lt;p&gt;The last bit of information I needed was determining the active (or last active) screensaver. I think I spent the most time on this. I was not able to find anything. Eventually I realized that some process had to have that file open, and if so, &lt;a href=&quot;https://man7.org/linux/man-pages/man8/lsof.8.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lsof&lt;/code&gt;&lt;/a&gt; would find it.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;idleassetsd&lt;/code&gt; came up empty, so I looked through my process list for other suspects, and found &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WallpaperVideoExtension&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;gt; lsof -Fn -p $(pgrep WallpaperVideoExtension) | grep &quot;.mov&quot;
n/Library/Application Support/com.apple.idleassetsd/Customer/4KSDR240FPS/B8F204CE-6024-49AB-85F9-7CA2F6DCD226.mov
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Boom!&lt;/p&gt;

&lt;h2 id=&quot;putting-it-all-together&quot;&gt;Putting it all Together&lt;/h2&gt;

&lt;p&gt;I threw together a little Mac menu bar app, &lt;a href=&quot;https://github.com/bgreenlee/WallpaperInfo/&quot;&gt;WallpaperInfo&lt;/a&gt;. Most of the logic is in &lt;a href=&quot;https://github.com/bgreenlee/WallpaperInfo/blob/main/WallpaperInfo/Wallpaper.swift&quot;&gt;Wallpaper.swift&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/bgreenlee/WallpaperInfo/blob/main/WallpaperInfo/Wallpaper.swift#L63-L69&quot;&gt;Decode all the assets in entries.json.&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/bgreenlee/WallpaperInfo/blob/main/WallpaperInfo/Wallpaper.swift#L63-L69&quot;&gt;Have a description field on the asset that looks up its localized description string in the strings bundle.&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/bgreenlee/WallpaperInfo/blob/main/WallpaperInfo/Wallpaper.swift#L75-L91&quot;&gt;Use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pgrep&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lsof&lt;/code&gt; to find the aerial video currently active, and use the identifier embedded in the filename to look up the asset.&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The result:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/images/screensavers/screenshot.png&quot; alt=&quot;Wallpaper Info Screenshot&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Sadly, I wouldn’t be able to put this in the App Store because of Apple’s sandboxing rules, but feel free to &lt;a href=&quot;https://github.com/bgreenlee/WallpaperInfo/releases/latest&quot;&gt;download the binary&lt;/a&gt; from my repo.&lt;/p&gt;

&lt;p&gt;It would be nice to have the description on the screensaver itself, like the AppleTV does, but I don’t think that’s possible short of either editing the videos to add descriptions, or running your own version of the screensaver. But given that Apple could easily add this as a feature (please!), I didn’t want to invest too much more time into this. I considered my itch scratched.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Migrating GitHub Pages to Cloudflare</title>
   <link href="https://footle.org/2025/01/14/migrating-github-pages-to-cloudflare/"/>
   <updated>2025-01-14T07:30:00-08:00</updated>
   <id>https://footle.org/2025/01/14/migrating-github-pages-to-cloudflare</id>
   <content type="html">&lt;p&gt;Or, On Becoming a Cloudflare Fanboy.&lt;/p&gt;

&lt;h2 id=&quot;whats-wrong-with-github-pages&quot;&gt;What’s wrong with GitHub Pages?&lt;/h2&gt;

&lt;p&gt;I’d been using GitHub Pages for hosting static sites, including this one, for years. It’s easy and free-ish (I believe they’re free for public repos, and if you’re paying $4/mo, private repos as well).&lt;/p&gt;

&lt;p&gt;One thing you don’t get, though, is any kind of visitor metrics. I know I can get this if I add something like Google Analytics to my sites, but I’m loath to do that for a number of reasons. For one, to be &lt;a href=&quot;https://gdpr.eu/cookies/&quot;&gt;GDPR compliant&lt;/a&gt;, I’d have to add one of those annoying cookie banners to all my sites. Also, ad blockers can block the GA Javascript and skew results. Finally, I don’t want to have to add the GA code to every site.&lt;/p&gt;

&lt;p&gt;If I were hosting the sites myself, I could get the information I need from the web server logs, but if GitHub is hosting the content, they have that info—but they aren’t sharing it.&lt;/p&gt;

&lt;h2 id=&quot;enter-cloudflare-pages&quot;&gt;Enter Cloudflare Pages&lt;/h2&gt;

&lt;p&gt;I’d been using Cloudflare for a while, as early on it was the only way to enable SSL on your GitHub Pages sites (GH now provides SSL for all Pages). But I didn’t know they had their own &lt;a href=&quot;https://pages.cloudflare.com&quot;&gt;“Pages”&lt;/a&gt; offering.&lt;/p&gt;

&lt;p&gt;Turns out it’s super easy to use: just point it to your GitHub repo, tell it what branch you want to deploy from and if there’s any build commands you want to run (plus other optional settings like output directory, environment variables,etc.), and it will publish your site on a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pages.dev&lt;/code&gt; subdomain. Then you can add your own domain name via a CNAME record to that subdomain. If Cloudflare is hosting your DNS it will even update your records for you. And everything gets SSL.&lt;/p&gt;

&lt;p&gt;(Another advantage of Cloudflare’s Pages offering is I can easily set up a dev/staging site by just creating another Pages site and pointing it to a branch in my repo.)&lt;/p&gt;

&lt;p&gt;The analytics it gives you is decent: total requests, unique visitors, bandwidth, % cached, requests by country/region, etc. You can even see breakdown by source IP, browsers, OS, desktop vs mobile (although oddly it’s under the Security section, not Analytics).&lt;/p&gt;

&lt;p&gt;One thing that seems to be missing is a breakdown of traffic by page. It would be nice to see, for example, if particular blog posts are getting more traffic than others, but I’m not seeing that data anywhere. &lt;strong&gt;Update:&lt;/strong&gt; &lt;a href=&quot;https://developers.cloudflare.com/web-analytics/get-started/&quot;&gt;They do have this&lt;/a&gt;, in a separate section (they really need a good UX person to clean up their menus), and it has to be enabled per site. If you are using their DNS proxy, it will automatically inject their Javascript into your site. Otherwise you can manually insert their JS snippet. They don’t use cookies, and it doesn’t look like they are exposing IP addresses anywhere, so no GDPR concerns.&lt;/p&gt;

&lt;h2 id=&quot;going-all-in&quot;&gt;Going All-In&lt;/h2&gt;

&lt;p&gt;After moving a few of my sites over and being generally impressed with the Cloudflare experience, I decided to go all-in and consolidate all my domains (more than 20…yes, I have a domain problem) under Cloudflare. This meant having them be my registrar, DNS, and, where appropriate, hosting the content. Previously my domains were spread out among a few different registrars, and my DNS split between registrars, Digital Ocean, and Cloudflare. Having everything under one roof made a lot of sense.&lt;/p&gt;

&lt;p&gt;The process was pretty straightforward. The only real snag I hit is that by default Cloudflare sets up “Flexible” SSL/TLS, where traffic is encrypted between visitors and Cloudflare, and then connections to your backend are made over HTTP. But if you already have a cert on your backend, and that backend is configured to redirect HTTP traffic to HTTPS, you’ll end up with a redirect loop. The fix is to just go into Cloudflare and change the SSL/TLS mode to “Full”.&lt;/p&gt;

&lt;h2 id=&quot;so-what-does-this-cost&quot;&gt;So What Does This Cost?&lt;/h2&gt;

&lt;p&gt;Nothing. It’s all free…which has been bugging me a bit. Other than registrar fees when transferring domains to them, I haven’t paid them anything. They do have &lt;a href=&quot;https://www.cloudflare.com/plans/&quot;&gt;paid plans&lt;/a&gt;, of course, but the additional features offered—mostly around security—are targeted towards much bigger sites (bot detection, image optimization, cache analytics, web application firewall, etc.). I would actually be happy to pay them &lt;em&gt;something&lt;/em&gt;, but I haven’t hit anything yet to warrant it. However, it seems like the paid plans are all &lt;em&gt;per domain&lt;/em&gt;, so if I did end up needing to pay for something across all my sites, it would get unreasonably expensive (their cheapest paid plan, “Pro,” is $20/mo/domain).&lt;/p&gt;

&lt;h2 id=&quot;fingers-crossed&quot;&gt;Fingers Crossed&lt;/h2&gt;

&lt;p&gt;I do feel a little nervous about going all-in on Cloudflare, as I would going all-in with any company/service, but I’ve been really impressed with them so far. They’ve had some &lt;a href=&quot;https://en.wikipedia.org/wiki/Cloudflare#Controversies&quot;&gt;controversies&lt;/a&gt; in the past, but generally seem like a pretty good company, both technically and ethically. I’ll certainly keep you posted if anything changes.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>A Year of Whatever</title>
   <link href="https://footle.org/2025/01/10/a-year-of-whatever/"/>
   <updated>2025-01-10T10:48:06-08:00</updated>
   <id>https://footle.org/2025/01/10/a-year-of-whatever</id>
   <content type="html">&lt;p&gt;It’s been a bit over a year since I was &lt;a href=&quot;https://www.cnbc.com/2023/12/13/etsy-laying-off-11percent-of-staff-citing-competitive-environment.html&quot;&gt;laid off from Etsy&lt;/a&gt;, where I’d been for 11½ years. Although everyone will tell you not to take a layoff personally, it still stings knowing that someone decided you were not worth keeping around. That said, the layoffs seemed to hit old-timers and remotes particularly hard, so the deck was stacked against me.&lt;/p&gt;

&lt;p&gt;It wasn’t hard for me to decide not to go looking for another full-time job. I’d long fantasized about being an indie software developer, working on my own things and setting my own schedule, so I guess that’s what I was now.&lt;/p&gt;

&lt;p&gt;I started an &lt;a href=&quot;https://greenlee.dev&quot;&gt;LLC&lt;/a&gt; for all the amazing apps I was going to start writing, but then some consulting fell into my lap. (Coincidentally, this same thing happened to me the last time I was laid off, nearly 25 years ago. I had been working in San Francisco during the dot-com boom and when the company went under I was all set to move to &lt;a href=&quot;https://bishopvisitor.com/rock-climbing-bouldering/&quot;&gt;Bishop&lt;/a&gt; and become a climbing bum for a year, when a friend pinged me and I ended up spending the next four years consulting.)&lt;/p&gt;

&lt;p&gt;I spent a couple months with &lt;a href=&quot;https://wikimediafoundation.org&quot;&gt;Wikimedia Foundation&lt;/a&gt; creating &lt;a href=&quot;https://wikitech.wikimedia.org/wiki/Data_Platform/Data_modeling_guidelines&quot;&gt;data modeling guidelines&lt;/a&gt;. I learned that WMF has some really interesting and unique challenges, both technically and politically. It’s a really great group of folks.&lt;/p&gt;

&lt;p&gt;That was followed a by a much bigger consulting opportunity, which lead to starting &lt;a href=&quot;https://fiasco.partners&quot;&gt;another LLC with some friends&lt;/a&gt;. We spend about six months tackling a pretty hairy data engineering challenge. What I learned from that is if you see NetSuite, run.&lt;/p&gt;

&lt;p&gt;Around the paid gigs I also spent some time helping out one friend with their &lt;a href=&quot;https://comprendo.dev&quot;&gt;startup&lt;/a&gt;,  another with his &lt;a href=&quot;https://museumistic.app&quot;&gt;app&lt;/a&gt;, and wrote a web app to help another friend give away &lt;a href=&quot;https://www.eastbaykidicalmass.org&quot;&gt;free bikes to kids&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I’ve been keeping myself pretty busy since that last gig ended. I spent a good amount of time doing a deep dive into &lt;a href=&quot;https://github.com/bgreenlee/WallpaperInfo&quot;&gt;MacOS aerial screensavers/wallpapers&lt;/a&gt;. I wrote a &lt;a href=&quot;https://apps.apple.com/us/app/i-cant-even-news-filter/id6738306756&quot;&gt;Safari extension to redact news articles&lt;/a&gt;. I wrote a &lt;a href=&quot;https://licenseplategame.fun&quot;&gt;little web game&lt;/a&gt;. I also spent a good amount of December doing &lt;a href=&quot;https://adventofcode.com&quot;&gt;Advent of Code&lt;/a&gt;, working on my Swift and SwiftUI skills in the process.&lt;/p&gt;

&lt;p&gt;I’ll write separate posts about all of those projects, but I’m currently mulling over what to do next. I recently got a 3D printer, so playing with that and learning a bit of CAD has been taking a lot of my time, but that’s not nearly as fulfilling as a good project is.&lt;/p&gt;

&lt;p&gt;So after a year of being “indie,” I’m still pretty sure I’m never going back to a full-time jobby-job. I do miss my colleagues at Etsy, and there’s something to be said about being part of a team and a larger mission, but I do not miss all the overhead that comes with working at a “large” company (“work about work”). I love waking up every day knowing that I have zero meetings and what I want to accomplish that day is entirely up to me. Literally whatever.&lt;/p&gt;

&lt;p&gt;Now to just come up with that killer app idea….&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Automating STOP to End</title>
   <link href="https://footle.org/2024/03/31/automating-stop-to-end/"/>
   <updated>2024-03-31T17:48:17-07:00</updated>
   <id>https://footle.org/2024/03/31/automating-stop-to-end</id>
   <content type="html">&lt;p&gt;My friends Sunah Suh, &lt;a href=&quot;https://github.com/stormsweeper&quot;&gt;Anthony Hersey&lt;/a&gt;, and I finally figured out the magic incantations needed to automate sending “STOP” to political text messages. Setting it up is completely non-obvious, so I’ll walk through it step-by-step.&lt;/p&gt;

&lt;p&gt;Note that this is for iOS only. If someone with an Android phone wants to write up their process, I’d be happy to link to it.&lt;/p&gt;

&lt;p&gt;Also, this was done on iOS 17.4. Surely this process will change some day. If you notice something is off, &lt;a href=&quot;mailto:brad@footle.org&quot;&gt;let me know&lt;/a&gt; and I’ll update it.&lt;/p&gt;

&lt;p class=&quot;img-right&quot;&gt;
&lt;img alt=&quot;Shortcuts home screen&quot; src=&quot;/public/images/stop-to-end/s2e01.jpeg&quot; /&gt;
First, open the Shortcuts app and tap the &lt;b&gt;Automation&lt;/b&gt; tab at the bottom.
&lt;/p&gt;

&lt;p class=&quot;img-right&quot;&gt;
&lt;img alt=&quot;Automation home screen&quot; src=&quot;/public/images/stop-to-end/s2e02.jpeg&quot; /&gt;
Tap the &lt;b&gt;plus (+)&lt;/b&gt; in the top right corner.
&lt;/p&gt;

&lt;p class=&quot;img-right&quot;&gt;
&lt;img alt=&quot;Create automation search page&quot; src=&quot;/public/images/stop-to-end/s2e03.jpeg&quot; /&gt;
Start typing &quot;Message&quot; in the search bar, and select &lt;b&gt;Message&lt;/b&gt;.
&lt;/p&gt;

&lt;p class=&quot;img-right&quot;&gt;
&lt;img alt=&quot;Automation When screen&quot; src=&quot;/public/images/stop-to-end/s2e04.jpeg&quot; /&gt;
On the When page, hit &lt;b&gt;Choose&lt;/b&gt; next to &lt;b&gt;Message Contains&lt;/b&gt;.
&lt;/p&gt;

&lt;p class=&quot;img-right&quot;&gt;
&lt;img alt=&quot;Automation When Message Contains screen&quot; src=&quot;/public/images/stop-to-end/s2e05.jpeg&quot; /&gt;
Type in the text to look for, such as &quot;STOP to end&quot;. It appears to be case-insensitive.
&lt;/p&gt;

&lt;p class=&quot;img-right&quot;&gt;
&lt;img alt=&quot;Automation When screen selecting Run Immediately&quot; src=&quot;/public/images/stop-to-end/s2e06.jpeg&quot; /&gt;
Hit &lt;b&gt;Done&lt;/b&gt; and back on the When page, select &lt;b&gt;Run Immediately&lt;/b&gt;. Then tap &lt;b&gt;Next&lt;/b&gt; in the top-right corner.
&lt;/p&gt;

&lt;p class=&quot;img-right&quot;&gt;
&lt;img alt=&quot;When I Get a Message Containing... screen&quot; src=&quot;/public/images/stop-to-end/s2e07.jpeg&quot; /&gt;
Now select &lt;b&gt;New Blank Automation&lt;/b&gt;.
&lt;/p&gt;

&lt;p class=&quot;img-right&quot;&gt;
&lt;img alt=&quot;When I Get a Message Containing... Add Action screen&quot; src=&quot;/public/images/stop-to-end/s2e08.jpeg&quot; /&gt;
Under &lt;b&gt;Next Action Suggestions&lt;/b&gt;, you should see &lt;b&gt;Send Message&lt;/b&gt;. (If not, hit &lt;b&gt;Add Action&lt;/b&gt; and search for &quot;Send Message&quot;.) Tap &lt;b&gt;Send Message&lt;/b&gt;.
&lt;/p&gt;

&lt;p class=&quot;img-right&quot;&gt;
&lt;img alt=&quot;Send Message Action screen&quot; src=&quot;/public/images/stop-to-end/s2e09.jpeg&quot; /&gt;
Tap on the &lt;b&gt;Message&lt;/b&gt; field and type &quot;STOP&quot;.
&lt;/p&gt;

&lt;p class=&quot;img-right&quot;&gt;
&lt;img alt=&quot;Send Message Recipients Shortcut Input&quot; src=&quot;/public/images/stop-to-end/s2e10.jpeg&quot; /&gt;
Now comes the first tricky part. Hold down (long press) on &lt;b&gt;Recipients&lt;/b&gt; and select &lt;b&gt;Shortcut Input&lt;/b&gt;. (If instead it pops open a &quot;To:&quot; page, you didn&apos;t hold down long enough. Cancel and try again.)
&lt;/p&gt;

&lt;p class=&quot;img-right&quot;&gt;
&lt;img alt=&quot;Send Message Recipients Shortcut Input Sender&quot; src=&quot;/public/images/stop-to-end/s2e11.jpeg&quot; /&gt;
Now the next tricky bit. Tap the &lt;b&gt;Shortcut Input&lt;/b&gt; field and select &lt;b&gt;Sender&lt;/b&gt;, then hit &lt;b&gt;Done&lt;/b&gt;.
&lt;/p&gt;

&lt;p class=&quot;img-right&quot;&gt;
That&apos;s it! Now repeat this for different variations of &quot;STOP to....&quot; (&quot;STOP to quit&quot;, &quot;STOP2END&quot;, etc.)
&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>The Case of the Absurdly Large Numbers</title>
   <link href="https://footle.org/2023/01/21/the-case-of-the-absurdly-large-numbers/"/>
   <updated>2023-01-21T18:10:08-08:00</updated>
   <id>https://footle.org/2023/01/21/the-case-of-the-absurdly-large-numbers</id>
   <content type="html">&lt;p&gt;One of the engineers on my team at Etsy, who is working on getting our clickstream events into &lt;a href=&quot;https://developers.google.com/protocol-buffers&quot;&gt;protobuf&lt;/a&gt;, noticed that we were getting some values that were too large for protobuf’s largest integer, uint64. E.g: 55340232221128660000.&lt;/p&gt;

&lt;p&gt;This value was coming from our frontend performance metrics-logging code, and is supposed to represent the sum of the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming/encodedBodySize&quot;&gt;encodedBodySizes&lt;/a&gt; of all the JavaScript or CSS assets on the page. But given that 55340232221128660000 is around 50,000 petabytes, it’s probably not right. There had to be a bug somewhere.&lt;/p&gt;

&lt;p&gt;We were only seeing this on a small percentage of visitors to the site—less than 0.1%. I looked at the web browsers logging these huge values and couldn’t see any obvious pattern.&lt;/p&gt;

&lt;p&gt;My first thought was that we had code somewhere that was concatenating numbers as strings. In JavaScript, if you start with a string and add numbers to it, you get concatenated numbers. E.g.:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;123&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;456&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;123456&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;But I didn’t see anyway that could happen in our code.&lt;/p&gt;

&lt;p&gt;Looking at the different values we were getting, I saw a lot of similar-but-not-quite equal values. For example:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;18446744073709552000
18446744073709556000
18446744073709654000
36893488147419220000
36893488147419310000
55340232221128660000
55340232221128750000
55340232221128770000
73786976294838210000
92233720368547760000
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The fact that they all end in zeros was curious, but I realized that was because they were overflowing &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER&quot;&gt;JavaScript’s max safe integer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I started googling some of the numbers and &lt;a href=&quot;https://stackoverflow.com/questions/21568738/parseint18446744073709551616-returning-18446744073709552000-in-javascript&quot;&gt;got a hit&lt;/a&gt;. I thought it was very odd that one of our seemingly random numbers was showing up on a StackOverflow post. Then I googled “18446744073709551616”. Any guesses what that is?&lt;/p&gt;

&lt;p&gt;2&lt;sup&gt;64&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;36893488147419220000? Approximately 2 * 2&lt;sup&gt;64&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;55340232221128660000 =~ 3 * 2&lt;sup&gt;64&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;etc.&lt;/p&gt;

&lt;p&gt;I realized what was probably happening was when we were adding up all the resources on the page, some of them were returning 2&lt;sup&gt;64&lt;/sup&gt;-1 (the maximum 64-bit unsigned integer), but some were normal, so that explained the variation.&lt;/p&gt;

&lt;p&gt;Now &lt;a href=&quot;https://www.w3.org/TR/resource-timing/#sec-performanceresourcetiming:~:text=readonly%20attribute%20unsigned%20long%20long%20%20encodedBodySize%3B&quot;&gt;encodedBodySize is an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unsigned long long&lt;/code&gt;&lt;/a&gt;, so my first thought was there is a browser bug that was casting a -1 into the unsigned long long, which would give us 2&lt;sup&gt;64&lt;/sup&gt;-1.&lt;/p&gt;

&lt;p&gt;I started digging through browser source code. I found that in WebKit, &lt;a href=&quot;https://github.com/WebKit/WebKit/blob/5f39acd5d511b9b48d7681413534d6d14f8117e5/Source/WebCore/platform/network/NetworkLoadMetrics.h#L109&quot;&gt;the default value for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;responseBodyBytesReceived&lt;/code&gt;&lt;/a&gt; is 2&lt;sup&gt;64&lt;/sup&gt;-1, although &lt;a href=&quot;https://github.com/WebKit/WebKit/blob/3a95196448a44d0b61cdd5e4825c22328cf90b26/Source/WebCore/page/PerformanceResourceTiming.cpp#L296-L297&quot;&gt;that value should be caught and 0 returned instead&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Then I went spelunking in the Chromium source, and found &lt;a href=&quot;https://github.com/chromium/chromium/commit/a378e342dd91b17f9d9fd9a95b382ac94da26875&quot;&gt;this commit&lt;/a&gt;, from less than two weeks ago. (Although &lt;a href=&quot;https://bugs.chromium.org/p/chromium/issues/detail?id=1324812&quot;&gt;the bug was reported back in May 2022&lt;/a&gt;.) Sure enough, it was a default value of -1 getting cast to an unsigned value. Boom! Mystery solved.&lt;/p&gt;

&lt;p&gt;I pushed a fix to our JavaScript to catch these bogus values and hopefully our protos will live happily ever after. Gone are my dreams of finding and fixing a major browser bug, but I’m happy that I can move on with my life.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>The Framework for ML Governance</title>
   <link href="https://footle.org/2021/09/18/the-framework-for-ml-governance/"/>
   <updated>2021-09-18T15:14:51-07:00</updated>
   <id>https://footle.org/2021/09/18/the-framework-for-ml-governance</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;https://info.algorithmia.com/hubfs/The%20Framework%20for%20ML%20Governance.pdf?hsLang=en-us&quot;&gt;The Framework for ML Governance&lt;/a&gt; by &lt;a href=&quot;https://twitter.com/kylegallatin&quot;&gt;Kyle Gallatin&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ML is becoming commoditized, but there hasn’t been much in the way of scalable frameworks to support the delivery and operation of models in production (of course, Algorithmia has one, hence their sponsoring of this report).&lt;/p&gt;

&lt;p&gt;ML needs to follow the same governance standards for software &amp;amp; data as other more traditional software engineering does in your organization. In the development phase, this includes validation and reproducibility of your model, and documentation of your methods and rationale. The delivery and operational phases are much more complex, including things like observability, auditing, cost visibility, versioning, alerting, model cataloging, security, compliance, and much more.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;MLOps is the set of best practices and tools that allow you to deliver ML at scale. ML governance is how you manage those practices and tools, democratizing ML across your organization through nonfunctional requirements like observability, auditability, and security. As ML companies mature, neither of these are “features” or “nice-to-haves”—they are hard requirements that are critical to an ML strategy.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Data scientists can’t do this all by themselves. They need support from the larger organization. The value of ML governance needs to be understood at the highest levels. They should involve infrastructure, security, and other domain experts early on, and be sure to be open in their communication with the rest of the company.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Advent of Code 2020: Swift</title>
   <link href="https://footle.org/2020/12/28/advent-of-code-2020-swift/"/>
   <updated>2020-12-28T08:00:55-08:00</updated>
   <id>https://footle.org/2020/12/28/advent-of-code-2020-swift</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;https://adventofcode.com&quot;&gt;Advent of Code&lt;/a&gt; was a fun diversion this year. It seemed a bit easier than some previous years. Perhaps it helped that I picked a language that I had some experience with, &lt;a href=&quot;https://developer.apple.com/swift/&quot;&gt;Swift&lt;/a&gt;. Here are some quick thoughts on Swift as an AoC language, some general AoC tips, and notes on some of the more interesting puzzles.&lt;/p&gt;

&lt;p&gt;You can find all my 2020 code &lt;a href=&quot;https://github.com/bgreenlee/AdventOfCode/tree/main/2020/Sources&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;swift-for-aoc&quot;&gt;Swift for AoC&lt;/h2&gt;

&lt;p&gt;First, the complaints:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Swift is too pedantic about strings.&lt;/strong&gt; AoC usually involves &lt;em&gt;loads&lt;/em&gt; of string manipulation and parsing, so being able to easily index into strings is super helpful. Swift does not make this easy out-of-the-box. I understand why. &lt;a href=&quot;https://oleb.net/blog/2017/11/swift-4-strings/&quot;&gt;Strings are complicated&lt;/a&gt; in a language like Swift that supports Unicode well. Indexing into an array is expected to be a constant-time operation, but that’s not possible when you have to look at the preceding bytes in order to figure out what the _i_th character is. Still. You can at least make it easier and less ugly than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;myString[myString.index(myString.startIndex, offsetBy: i)]&lt;/code&gt;. Thankfully Swift is easy to monkey-patch, so I added some &lt;a href=&quot;https://github.com/bgreenlee/AdventOfCode/blob/main/2020/Sources/Shared/StringExtensions.swift&quot;&gt;useful extensions&lt;/a&gt; to make it tolerable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Regexes are similarly annoying&lt;/strong&gt; in Swift. Here it just feels like they never properly ported them over from Objective-C. Here’s an example:&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// print the animals found in a string&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;myString&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;The quick brown fox jumped over the lazy dogs.&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;animalsRegex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;NSRegularExpression&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;(fox|dog)&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[])&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;matches&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;animalsRegex&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;matches&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;myString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;NSRange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;myString&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;startIndex&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;myString&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;endIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;myString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;matches&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;numberOfRanges&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nf&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;NSString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;myString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;substring&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;My colleague &lt;a href=&quot;https://github.com/waltflanagan&quot;&gt;Mike Simons&lt;/a&gt; gave me a &lt;a href=&quot;https://github.com/bgreenlee/AdventOfCode/blob/main/2020/Sources/Shared/RegEx.swift&quot;&gt;RegEx&lt;/a&gt; helper he uses, which reduces the above to:&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;animalsRegex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;RegEx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;(fox|dog)&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;matches&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;animalsRegex&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;matchGroups&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;myString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;matches&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;group&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nf&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;group&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Tuples not being hashable&lt;/strong&gt; or even extendable is a pain for a lot of AoC problems. I resorted to using a custom struct for a bunch of problems, but at some point discovered &lt;a href=&quot;https://developer.apple.com/documentation/swift/simd&quot;&gt;SIMD&lt;/a&gt; vectors, which have the added benefit of having arithmetic operators defined for them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I loved&lt;/strong&gt; about Swift:&lt;/p&gt;

&lt;p&gt;Working with a &lt;strong&gt;statically-typed language&lt;/strong&gt; in a proper IDE (&lt;strong&gt;Xcode&lt;/strong&gt;) is such a huge time-saver. Everything is checked as you type (which can be a little annoying when Xcode starts scolding you for not using variables that you’ve defined before you get a chance to write the code that uses them; but you learn to ignore it). You have a full-featured debugger.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.apple.com/swift/playgrounds/&quot;&gt;Playgrounds&lt;/a&gt; are really useful for trying out quick snippets of code.&lt;/p&gt;

&lt;p&gt;Swift is generally a &lt;strong&gt;pleasant, straight-forward language&lt;/strong&gt; to write. There’s not all the overhead of thinking about memory and ownership like there is in Rust, for example.&lt;/p&gt;

&lt;p&gt;It’s actually pretty &lt;strong&gt;performant&lt;/strong&gt;—at least when not running the debug build (I usually got a 10x speed-up when building for release).&lt;/p&gt;

&lt;h2 id=&quot;general-aoc-tips&quot;&gt;General AoC Tips&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Hash maps&lt;/strong&gt;, hash maps, hash maps. Even if the problem seems array-shaped, there’s a good chance a hash map will be more efficient.&lt;/li&gt;
  &lt;li&gt;Many of the problems are grounded in some &lt;strong&gt;basic CS principle&lt;/strong&gt; (day 5 this year being a classic example). Think about what that might be before diving in.&lt;/li&gt;
  &lt;li&gt;Oftentimes part 2 will be part 1 but &lt;strong&gt;MORE&lt;/strong&gt;. Days &lt;a href=&quot;https://adventofcode.com/2020/day/15&quot;&gt;15&lt;/a&gt; (Rambunctious Recitation) and &lt;a href=&quot;https://adventofcode.com/2020/day/23&quot;&gt;23&lt;/a&gt; (Crab Cups) this year were good examples of that. When coding part 1, think about how your solution might scale if you were doing a million times more, or with a million times more data.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;the-puzzles&quot;&gt;The Puzzles&lt;/h2&gt;

&lt;p&gt;Ok, on to specific puzzles. I’m just going to talk about some of the more interesting ones. Spoilers follow:&lt;/p&gt;

&lt;h3 id=&quot;day-5-binary-boarding-code&quot;&gt;&lt;a href=&quot;https://adventofcode.com/2020/day/5&quot;&gt;Day 5: Binary Boarding&lt;/a&gt; (&lt;a href=&quot;https://github.com/bgreenlee/AdventOfCode/blob/main/2020/Sources/05-BinaryBoarding/main.swift&quot;&gt;code&lt;/a&gt;)&lt;/h3&gt;

&lt;p&gt;This is a classic AoC problem in that it disguises basic CS principles. If you were to solve this naively, it might be kind of annoying. but when you realize that the seating strings (e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FBFBBFFRLR&lt;/code&gt;) are just binary numbers, with (F,L) -&amp;gt; 0 and (B,R) -&amp;gt; 1, it becomes trivial. Particularly helpful here was Swift’s ability to convert a binary string to decimal with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Int(binary, radix: 2)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Part 1 just required sorting the list of converted seat numbers and taking the last (highest) one. Part 2, finding the first non-consecutive id, is probably faster just iterating through the sorted list and stopping on the first id that is not one more than the last id (which is what I did originally), but it was more fun and concise to use &lt;a href=&quot;https://nrich.maths.org/2478&quot;&gt;Gauss’ formula&lt;/a&gt; to calculate what the total should be if all the consecutive numbers were present and subtract the actual sum of all numbers.&lt;/p&gt;

&lt;p&gt;For kicks, I did a “no code” version in &lt;a href=&quot;https://docs.google.com/spreadsheets/d/1pgE15V-n5zG6IPb921SJAGYnNPQ7u4Ql_QYS_wNM2V4/edit#gid=0&quot;&gt;a spreadsheet&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;day-7-handy-haversacks-code&quot;&gt;&lt;a href=&quot;https://adventofcode.com/2020/day/7&quot;&gt;Day 7: Handy Haversacks&lt;/a&gt; (&lt;a href=&quot;https://github.com/bgreenlee/AdventOfCode/tree/main/2020/Sources/07-HandyHaversacks&quot;&gt;code&lt;/a&gt;)&lt;/h3&gt;

&lt;p&gt;This was the first day that required some real thought. I started down the path of having a bidirectional graph with each bag having parents and children, but I got bogged down. I think sometimes creating objects complicates things vs. just slinging around string hash maps.&lt;/p&gt;

&lt;h3 id=&quot;day-9-encoding-error-code&quot;&gt;&lt;a href=&quot;https://adventofcode.com/2020/day/9&quot;&gt;Day 9: Encoding Error&lt;/a&gt; (&lt;a href=&quot;https://github.com/bgreenlee/AdventOfCode/tree/main/2020/Sources/09-EncodingError&quot;&gt;code&lt;/a&gt;)&lt;/h3&gt;

&lt;p&gt;This is totally an interview question I would have failed. It’s easy enough doing it the “dumb” (O(n^2)) way that I did it, constructing a lookup table of all sums in the preamble, or, for part 2, &lt;a href=&quot;https://github.com/bgreenlee/AdventOfCode/blob/46162105ed4f803151b9db18c87215e15511118c/2020/Sources/09-EncodingError/Part2.swift&quot;&gt;iterating through every possible sequence&lt;/a&gt; of two consecutive numbers, then three, etc.—also O(n^2). After I finished, a friend shared the &lt;a href=&quot;https://github.com/bgreenlee/AdventOfCode/blob/main/2020/Sources/09-EncodingError/Part2.swift&quot;&gt;“inchworm” technique&lt;/a&gt;, which is O(n). Neat! I totally failed that interview.&lt;/p&gt;

&lt;h3 id=&quot;day-10-adapter-array-code&quot;&gt;&lt;a href=&quot;https://adventofcode.com/2020/day/10&quot;&gt;Day 10: Adapter Array&lt;/a&gt; (&lt;a href=&quot;https://github.com/bgreenlee/AdventOfCode/tree/main/2020/Sources/10-AdapterArray&quot;&gt;code&lt;/a&gt;)&lt;/h3&gt;

&lt;p&gt;Part 2 was fun to figure out. There were very different ways to approach this. I went with recognizing that we were dealing with &lt;a href=&quot;https://en.wikipedia.org/wiki/Power_set&quot;&gt;power sets&lt;/a&gt;. I &lt;a href=&quot;https://github.com/bgreenlee/AdventOfCode/blob/main/2020/Sources/10-AdapterArray/Part2.swift&quot;&gt;wrote up my thinking in my code&lt;/a&gt;, so I won’t duplicate it here. Some friends solved this using &lt;a href=&quot;https://www.educative.io/courses/grokking-dynamic-programming-patterns-for-coding-interviews/m2G1pAq0OO0&quot;&gt;dynamic programming&lt;/a&gt;, which I definitely need to level up on.&lt;/p&gt;

&lt;h3 id=&quot;day-11-seating-system-code&quot;&gt;&lt;a href=&quot;https://adventofcode.com/2020/day/11&quot;&gt;Day 11: Seating System&lt;/a&gt; (&lt;a href=&quot;https://github.com/bgreenlee/AdventOfCode/tree/main/2020/Sources/11-SeatingSystem&quot;&gt;code&lt;/a&gt;)&lt;/h3&gt;

&lt;p&gt;Nothing particularly interesting here—the first of three &lt;a href=&quot;https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life&quot;&gt;Game of Life&lt;/a&gt;-type problems. I just had to share &lt;a href=&quot;https://www.reddit.com/r/adventofcode/comments/kcpdbi/2020_day_11_part_2luaroblox_waiting_room/&quot;&gt;this&lt;/a&gt;, though.&lt;/p&gt;

&lt;h3 id=&quot;day-12-rain-risk-code&quot;&gt;&lt;a href=&quot;https://adventofcode.com/2020/day/12&quot;&gt;Day 12: Rain Risk&lt;/a&gt; (&lt;a href=&quot;https://github.com/bgreenlee/AdventOfCode/tree/main/2020/Sources/12-RainRisk&quot;&gt;code&lt;/a&gt;)&lt;/h3&gt;

&lt;p&gt;Pretty straightforward. Part 2 was fun because I [re-]learned how to &lt;a href=&quot;https://matthew-brett.github.io/teaching/rotation_2d.html&quot;&gt;rotate a vector&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;day-13-shuttle-search-code&quot;&gt;&lt;a href=&quot;https://adventofcode.com/2020/day/13&quot;&gt;Day 13: Shuttle Search&lt;/a&gt; (&lt;a href=&quot;https://github.com/bgreenlee/AdventOfCode/blob/main/2020/Sources/13-ShuttleSearch/main.swift&quot;&gt;code&lt;/a&gt;)&lt;/h3&gt;

&lt;p&gt;This was a fun one. I solved part 1 in bed on my phone with a calculator, and then spent the entire next day working on part 2. I learned about the &lt;a href=&quot;https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm&quot;&gt;Extended Euclidean algorithm&lt;/a&gt; and the &lt;a href=&quot;https://en.wikipedia.org/wiki/Chinese_remainder_theorem&quot;&gt;Chinese remainder theorem&lt;/a&gt;. I used the &lt;a href=&quot;https://en.wikipedia.org/wiki/Chinese_remainder_theorem#Using_the_existence_construction&quot;&gt;existence construction&lt;/a&gt; to solve it, but the simpler solution that many used was &lt;a href=&quot;https://en.wikipedia.org/wiki/Chinese_remainder_theorem#Search_by_sieving&quot;&gt;sieving&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;day-17-conway-cubes-code&quot;&gt;&lt;a href=&quot;https://adventofcode.com/2020/day/17&quot;&gt;Day 17: Conway Cubes&lt;/a&gt; (&lt;a href=&quot;https://github.com/bgreenlee/AdventOfCode/tree/main/2020/Sources/17-ConwayCubes&quot;&gt;code&lt;/a&gt;)&lt;/h3&gt;

&lt;p&gt;Game of Life again! Doing it in 3D and then 4D was a fun twist. Nothing particularly tricky. I just have a &lt;a href=&quot;https://apps.apple.com/us/app/qr-life/id1061418370&quot;&gt;soft spot for GoL&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;day-18-operation-order-code&quot;&gt;&lt;a href=&quot;https://adventofcode.com/2020/day/18&quot;&gt;Day 18: Operation Order&lt;/a&gt; (&lt;a href=&quot;https://github.com/bgreenlee/AdventOfCode/tree/main/2020/Sources/18-OperationOrder&quot;&gt;code&lt;/a&gt;)&lt;/h3&gt;

&lt;p&gt;This was a fun one. I spent a lot of time scratching my head and drawing diagrams, until I remembered it’s a lot easier to parse expressions in &lt;a href=&quot;https://en.wikipedia.org/wiki/Reverse_Polish_notation&quot;&gt;postfix&lt;/a&gt;, and you can use the &lt;a href=&quot;https://en.wikipedia.org/wiki/Shunting-yard_algorithm&quot;&gt;Shunting yard algorithm&lt;/a&gt; to convert infix to postfix.&lt;/p&gt;

&lt;h3 id=&quot;day-19-monster-messages-code&quot;&gt;&lt;a href=&quot;https://adventofcode.com/2020/day/19&quot;&gt;Day 19: Monster Messages&lt;/a&gt; (&lt;a href=&quot;https://github.com/bgreenlee/AdventOfCode/tree/main/2020/Sources/19-MonsterMessages&quot;&gt;code&lt;/a&gt;)&lt;/h3&gt;

&lt;p&gt;Woo, boy! This was a good one. I’d never written a parser before, so this was a learning experience. My &lt;a href=&quot;https://github.com/bgreenlee/AdventOfCode/tree/ac4f6e50be0ba2dcca8e69bfbb77e1f83a034b92/2020/Sources/19-MonsterMessages&quot;&gt;part 1 solution&lt;/a&gt; involved creating a matcher from the grammar, and it was fast and elegant. Part 2 threw in the wrench of recursive rules, which absolutely do not work when building a matcher. I tried a whole bunch of things like adding recursion limits, but I could not get it to work. I ended up moving on and came back to it only after I’d finished all the other days. By then I had heard the term &lt;a href=&quot;https://en.wikipedia.org/wiki/CYK_algorithm&quot;&gt;CYK algorithm&lt;/a&gt; bandied about, and so I did a complete rewrite using that. I spent a bunch of time reading about the algorithm and about &lt;a href=&quot;https://en.wikipedia.org/wiki/Chomsky_normal_form&quot;&gt;Chomsky normal form&lt;/a&gt;. I “cheated” a bit and didn’t write code to convert the provided rules to Chomsky normal form, as there were only a few rules that needed to be tweaked and it was easy enough to do it by hand:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Original&lt;/th&gt;
      &lt;th&gt;Chomsky normal form&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;107: 18 | 47&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;107: &quot;b&quot; | &quot;a&quot;&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;11: 42 31 | 42 11 31&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;11: 42 31 | 42 133&lt;/code&gt; &lt;br /&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;133: 11 31&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;8: 42 | 42 8&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;8: 47 50 | 18 4 | 42 8&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h3 id=&quot;day-20-jurassic-jigsaw-code&quot;&gt;&lt;a href=&quot;https://adventofcode.com/2020/day/20&quot;&gt;Day 20: Jurassic Jigsaw&lt;/a&gt; (&lt;a href=&quot;https://github.com/bgreenlee/AdventOfCode/tree/main/2020/Sources/20-JurassicJigsaw&quot;&gt;code&lt;/a&gt;)&lt;/h3&gt;

&lt;p&gt;This was a favorite. Part 1 was easy once I figured out a way to generate a hash code that uniquely identified a side, irrespective of its orientation:&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;sideToInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;side&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;binary&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;side&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;replacingOccurrences&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                     &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;replacingOccurrences&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;#&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;num&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;binary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;radix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;numReversed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;binary&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;reversed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()),&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;radix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;numReversed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;^&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;numReversed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Once you have that, your corners are the tiles that have two “singleton” sides (i.e. unique to that tile). No assembling necessary…for part 1. Part 2 did require assembling, and that was a bit tedious. It was a cool problem, though.&lt;/p&gt;

&lt;h3 id=&quot;day-23-crab-cups-code&quot;&gt;&lt;a href=&quot;https://adventofcode.com/2020/day/23&quot;&gt;Day 23: Crab Cups&lt;/a&gt; (&lt;a href=&quot;https://github.com/bgreenlee/AdventOfCode/tree/main/2020/Sources/23-CrabCups&quot;&gt;code&lt;/a&gt;)&lt;/h3&gt;

&lt;p&gt;Classic AoC problem where the simple solution for part 1 utterly fails in part 2. I actually got the answer to part 2 after letting my dumb-but-optimized part 1 solution run overnight, but while it was running, mulling it over in bed, I realized that this was a linked list problem. I fixed it in the morning and the runtime went from ~ 7 hours to 0.2 sec.&lt;/p&gt;

&lt;h3 id=&quot;day-24-lobby-layout-code&quot;&gt;&lt;a href=&quot;https://adventofcode.com/2020/day/24&quot;&gt;Day 24: Lobby Layout&lt;/a&gt; (&lt;a href=&quot;https://github.com/bgreenlee/AdventOfCode/tree/main/2020/Sources/24-LobbyLayout&quot;&gt;code&lt;/a&gt;)&lt;/h3&gt;

&lt;p&gt;This was surprisingly easy for this late in the calendar, although my first naive attempt trying to map it to a 2D coordinate system failed. But I googled “hexagonal grid coordinate system” and found &lt;a href=&quot;https://www.redblobgames.com/grids/hexagons/&quot;&gt;this cool page&lt;/a&gt;. I used the cube coordinate system and it was easy-peasy.&lt;/p&gt;

&lt;p&gt;Part 2: Yay, more Game of Life! I’m sorely tempted to write a visualization for this.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Humanize</title>
   <link href="https://footle.org/2020/10/10/humanize/"/>
   <updated>2020-10-10T18:27:47-07:00</updated>
   <id>https://footle.org/2020/10/10/humanize</id>
   <content type="html">&lt;p&gt;I scratched an itch last week and actually wrote some code (these days my primary IDE is Google Docs). Check out &lt;a href=&quot;https://github.com/bgreenlee/humanize&quot;&gt;humanize&lt;/a&gt;, which replaces any large numbers in text piped into it with shortened versions using &lt;a href=&quot;https://en.wikipedia.org/wiki/Metric_prefix&quot;&gt;SI prefix&lt;/a&gt; symbols (K, M, G, T, etc.). So “File size: 972917401236” becomes “File size: 973G”.&lt;/p&gt;

&lt;p&gt;This came about because I was debugging an issue with a &lt;a href=&quot;https://parquet.apache.org&quot;&gt;Parquet&lt;/a&gt; file using &lt;a href=&quot;https://github.com/apache/parquet-mr/tree/master/parquet-tools&quot;&gt;parquet-tools&lt;/a&gt;, whose output looks like:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;% parquet-tools meta part-01373-r-01373.gz.parquet | grep &quot;row group&quot;
row group 1:           RC:100 TS:121513011 OFFSET:4 
row group 2:           RC:100 TS:44877183 OFFSET:14293218 
row group 3:           RC:111 TS:28645460 OFFSET:19704281 
row group 4:           RC:168 TS:31794536 OFFSET:23387243 
row group 5:           RC:363 TS:28078938 OFFSET:27531686 
row group 6:           RC:15547 TS:899825873 OFFSET:31242035 
row group 7:           RC:9963 TS:47930700 OFFSET:142353955 
row group 8:           RC:20100 TS:911417774 OFFSET:155302131 
row group 9:           RC:20100 TS:889810662 OFFSET:269749697 
row group 10:          RC:10100 TS:855908709 OFFSET:382090935 
row group 11:          RC:7282 TS:1532744480 OFFSET:486019001 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Tired of squinting and counting digits to see how big some of these numbers were, I figured there’d be some easy bash/sed way to convert these numbers into something more readable. It is pretty easy to do this for isolated numbers using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;numfmt&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;% echo &quot;1234567890&quot; | numfmt --to=si --round=nearest
1.2G
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;But that doesn’t work on numbers embedded in text:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;% echo &quot;This is a big number: 1234567890&quot; | numfmt --to=si --round=nearest
numfmt: invalid number: ‘This’
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;GNU sed can do a replacement with the result of a function, but it’s rather ugly:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;% echo &quot;This is a big number: 1234567890&quot; | sed -re &apos;s/[0-9]+/`numfmt --to=si --round=nearest &amp;amp;`/g;s/.*/echo &amp;amp;/;e&apos;
This is a big number: 1.2G
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;But I’m doing this work on a Mac, which does not come with GNU sed (or numfmt, for that matter, although you can &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;brew install coreutils&lt;/code&gt; to get gnumfmt). I started working on a perl one-liner to do it, but decided this was something that needed to exist on its own, and should be easy for anyone to install.&lt;/p&gt;

&lt;p&gt;I chose to write it in Go because it has an easy way for people to install binaries with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;go get&lt;/code&gt;. (Rust has something similar with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cargo install&lt;/code&gt;, but Go is more common in my workplace.) The problem with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;go get&lt;/code&gt; is that you have to run it again to upgrade, so for my fellow Mac users I added a &lt;a href=&quot;https://brew.sh&quot;&gt;Homebrew&lt;/a&gt; tap.&lt;/p&gt;

&lt;p&gt;Long story short:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;% parquet-tools meta part-01373-r-01373.gz.parquet | grep &quot;row group&quot; | humanize -binary
row group 1:           RC:100 TS:116Mi OFFSET:4 
row group 2:           RC:100 TS:43Mi OFFSET:14Mi 
row group 3:           RC:111 TS:27Mi OFFSET:19Mi 
row group 4:           RC:168 TS:30Mi OFFSET:22Mi 
row group 5:           RC:363 TS:27Mi OFFSET:26Mi 
row group 6:           RC:15Ki TS:858Mi OFFSET:30Mi 
row group 7:           RC:10Ki TS:46Mi OFFSET:136Mi 
row group 8:           RC:20Ki TS:869Mi OFFSET:148Mi 
row group 9:           RC:20Ki TS:849Mi OFFSET:257Mi 
row group 10:          RC:10Ki TS:816Mi OFFSET:364Mi 
row group 11:          RC:7Ki TS:1Gi OFFSET:464Mi
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

</content>
 </entry>

 
 
 <entry>
   <title>ReadBot</title>
   <link href="https://footle.org/2018/03/01/readbot/"/>
   <updated>2018-03-01T18:12:42-08:00</updated>
   <id>https://footle.org/2018/03/01/readbot</id>
   <content type="html">&lt;p&gt;I wrote a Slack bot, &lt;a href=&quot;https://github.com/bgreenlee/readbot&quot;&gt;ReadBot&lt;/a&gt;, to both scratch an itch and check out the current state of Slack integration. As a bonus, I got to spend some time getting familiar with &lt;a href=&quot;https://glitch.com&quot;&gt;Glitch&lt;/a&gt;, a pretty cool live coding platform.&lt;/p&gt;

&lt;p&gt;ReadBot lets you connect your &lt;a href=&quot;https://goodreads.com&quot;&gt;Goodreads&lt;/a&gt; and &lt;a href=&quot;https://getpocket.com&quot;&gt;Pocket&lt;/a&gt; accounts to Slack, and then adding a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bookmark&lt;/code&gt; (🔖) reactji to a message with an Amazon book link in it will add that book to your Goodreads “to-read” shelf, or any other URL to your Pocket account.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;https://api.slack.com&quot;&gt;Slack API&lt;/a&gt; and documentation has improved immensely since I last checked it out a couple years ago. I was clearly not the only one to get confused by profusion of integration options (bot? slash command? webhook?) , so they’ve improved their API landing pages to &lt;a href=&quot;https://api.slack.com/slack-apps&quot;&gt;help guide you&lt;/a&gt;. There are also plenty of tutorials to get you started.&lt;/p&gt;

&lt;p&gt;One of the fears when diving into an API integration is whether that API—or even integrations in general—are going to be supported in the future. Many developers have been burned by neglected, &lt;a href=&quot;https://developers.facebook.com/blog/post/2018/01/30/instagram-graph-api-updates/&quot;&gt;deprecated&lt;/a&gt; or even &lt;a href=&quot;https://techcrunch.com/2014/11/16/netflix-api/&quot;&gt;shutdown&lt;/a&gt; APIs. Slack, however, seems to be encouraging integrations whole-heartedly with its &lt;a href=&quot;https://slack.com/apps&quot;&gt;app directory&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;One challenge of creating a new Slack integration has been Slack’s requirement that it be served over SSL. While &lt;a href=&quot;https://letsencrypt.org&quot;&gt;Let’s Encrypt&lt;/a&gt; has made this a lot easier, setting up an SSL-enabled server is still a significant hurdle to clear just to start developing your integration. This is where &lt;a href=&quot;https://glitch.com/&quot;&gt;Glitch&lt;/a&gt; comes in.&lt;/p&gt;

&lt;p&gt;Glitch is a collaborative live coding environment made by &lt;a href=&quot;https://fogcreek.cohttps://fogcreek.com/&quot;&gt;Fog Creek Software&lt;/a&gt;. It’s super easy to get started, especially since you can find existing public projects on the site and “remix” them to make them your own. And every project has its own SSL-enabled hostname, right out of the box.&lt;/p&gt;

&lt;p&gt;Glitch apps are Node.js-based (they seem to allow Python apps as well, but support is currently unofficial). The app restarts itself on the fly as you edit (although this can be disabled), so your app is always live. Autocomplete package search makes installing new packages a breeze. You can do pretty much everything you need to through the UI, but if you need, you can drop into a shell and do whatever you like to your instance.&lt;/p&gt;

&lt;p&gt;There’s no built-in revision/commit history, but you can export your project to GitHub (as well as import from GitHub). Since your app is just a regular Node app, it’s perfectly portable to any other environment.&lt;/p&gt;

&lt;p&gt;One general issue with writing Slack bots is that in order to continue working on your app after it is in production, you need to have separate development apps and endpoints. It would be nice if Slack made this a little easier, perhaps by allowing you to specify separate production and development endpoints, slash commands, etc.&lt;/p&gt;

&lt;p&gt;I have no plans on publishing ReadBot to the Slack App Directory because I don’t want to have to maintain another production service. If you’re interested in doing so, go for it.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Rescuing Windows with Hammerspoon</title>
   <link href="https://footle.org/2018/01/23/rescuing-windows-with-hammerspoon/"/>
   <updated>2018-01-23T21:02:42-08:00</updated>
   <id>https://footle.org/2018/01/23/rescuing-windows-with-hammerspoon</id>
   <content type="html">&lt;p&gt;I recently got a new monitor and it came with a problem. For some reason when I attached or detached my laptop, many of my windows would end up off the edge of the screen, and I’d have to drag them back over one by one. It was annoying enough that I decided I’d write an app to “rescue” them.&lt;/p&gt;

&lt;p&gt;I figured it wouldn’t be too hard. Get a list of active windows, see which are off-screen, and move them over. But it was hard. My code only half-worked. And for some reason I couldn’t get Chrome windows to move.&lt;/p&gt;

&lt;p&gt;I started looking around and found &lt;a href=&quot;https://github.com/tmandry/Swindler&quot;&gt;Swindler&lt;/a&gt;. It seemed to be just what I needed and confirmed that I wasn’t completely incompetent:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Writing window managers for macOS is hard. There are a lot of systemic challenges, including limited and poorly-documented APIs. All window managers on macOS must use the C-based accessibility APIs, which are difficult to use and are surprisingly buggy themselves.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But then I saw &lt;a href=&quot;http://www.hammerspoon.org/&quot;&gt;Hammerspoon&lt;/a&gt; listed at the bottom of the Swindler README, under Related Projects. Intrigued, I checked it out. It was just what I needed.&lt;/p&gt;

&lt;p&gt;Hammerspoon lets you write Lua scripts to interact with the MacOS system, and it’s pretty powerful. The &lt;a href=&quot;http://www.hammerspoon.org/go/&quot;&gt;Getting Started Guide&lt;/a&gt; gives a good sense of some of the things you can do with it.&lt;/p&gt;

&lt;p&gt;I’d never written Lua before, but with plenty of examples to crib from and good &lt;a href=&quot;http://www.hammerspoon.org/docs/index.html&quot;&gt;API documentation&lt;/a&gt;, it didn’t take me long to come up with a little script that did just what I needed:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/77f1fbeb673eb674ed6065b189dec4d3.js&quot;&gt; &lt;/script&gt;

&lt;p&gt;I have that file saved at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.hammerspoon/rescuewindows.lua&lt;/code&gt;, and in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.hammerspoon/init.lua&lt;/code&gt; I have:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;local rescueWindows = require &quot;rescuewindows&quot;
hs.hotkey.bind({&quot;cmd&quot;, &quot;alt&quot;, &quot;ctrl&quot;}, &quot;R&quot;, rescueWindows)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So when it hit ⌃⌥⌘R, all my off-screen windows slide over to my main screen. Nice!&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Going "Serverless"</title>
   <link href="https://footle.org/2018/01/15/going-serverless/"/>
   <updated>2018-01-15T16:13:13-08:00</updated>
   <id>https://footle.org/2018/01/15/going-serverless</id>
   <content type="html">&lt;p&gt;When my friend Nelson and I set out to build our location tracking app &amp;amp; accompanying website, &lt;a href=&quot;https://wanderin.gs&quot;&gt;Wanderings&lt;/a&gt;, we started down the familiar path of choosing our stack. Flask seemed like a reasonable choice. Postgres for the database. SqlAlchemy for the ORM? Sure, I guess. We figured we’d try hosting on GCP, mostly to learn more about the platform. Do we bother with containers? Meh, leave those for the youngsters. And so on.&lt;/p&gt;

&lt;p&gt;But the more we thought about hosting our own service, the less enthused we were. The GCP costs were piling up, and we didn’t really want to be responsible for having a copy of our users’ location data. One of the driving ideas behind Wanderings was having a location tracker where you controlled your own data. Why should you trust us with a copy of it?&lt;/p&gt;

&lt;p&gt;I should back up and talk a little about what Wanderings is and how it works.&lt;/p&gt;

&lt;p&gt;Back in 2011 there was a small uproar when it was revealed that Apple was apparently &lt;a href=&quot;https://arstechnica.com/gadgets/2011/04/how-apple-tracks-your-location-without-your-consent-and-why-it-matters/&quot;&gt;tracking your every move&lt;/a&gt; with your iPhone. Out of that grew a project, &lt;a href=&quot;http://nytlabs.com/projects/openpaths.html&quot;&gt;OpenPaths&lt;/a&gt;, that allowed you to generate your own location data, and have full control over it. The app used very little energy, so you could just start it and forget it.&lt;/p&gt;

&lt;p&gt;However, with the release of iOS 11, OpenPaths stopped working, and its accompanying website, &lt;a href=&quot;https://openpaths.cc&quot;&gt;openpaths.cc&lt;/a&gt;, no longer resolved. It appeared to be no longer maintained. There were some other location tracking apps out there, including &lt;a href=&quot;https://www.google.com/maps/timeline&quot;&gt;Google Timeline&lt;/a&gt;, &lt;a href=&quot;https://fogofworld.com/en/&quot;&gt;Fog of World&lt;/a&gt;, and &lt;a href=&quot;http://strutapp.com/&quot;&gt;Strut&lt;/a&gt;, but none that had the combination of strong privacy guarantees , simplicity, and low-energy usage that we were looking for. So we decided to make our own.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;https://itunes.apple.com/us/app/wanderings-travel-tracking/id1292503352?ls=1&amp;amp;mt=8&quot;&gt;Wanderings iPhone app&lt;/a&gt; is pretty basic. It uses iOS’ significant location change service to only update your location when you move by a significant amount. It also relies on wifi and cellular for location information rather than power-hungry GPS. It does all this in the background, so you can start it once and forget it.&lt;/p&gt;

&lt;p&gt;New location data is uploaded to your private, secured CloudKit database on iCloud, so you are the only one with access to your data.&lt;/p&gt;

&lt;p&gt;So back to our server conundrum.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/images/wanderings-screenshot.png&quot; alt=&quot;Wanderings Screenshot&quot; class=&quot;embed-left&quot; /&gt;
One of our requirements was a website that would render the full heat map of your travels, let you export that data, and eventually let you do a lot of interesting things with your data. Of course, it doesn’t make sense to re-download all your location data every time you visit (especially since CloudKit only lets you pull 200 records per request) so we needed some kind of cache of your data in the app, as in a database.&lt;/p&gt;

&lt;p&gt;But we don’t really want your data. And we really don’t want to deal with maintaining a server somewhere, either.&lt;/p&gt;

&lt;p&gt;Fortunately, for a few years now browsers have supported &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API/Basic_Concepts_Behind_IndexedDB&quot;&gt;IndexedDB&lt;/a&gt;, an embedded transactional database with sizable &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API/Browser_storage_limits_and_eviction_criteria#Storage_limits&quot;&gt;storage limits&lt;/a&gt;. We realized if we used this as our cache, the app could be a static site (&lt;a href=&quot;http://www.somebits.com/weblog/tech/good/webapps-with-json.html&quot;&gt;something Nelson had explored&lt;/a&gt; years ago), which we can host cheaply anywhere. In fact, we ended up just using &lt;a href=&quot;https://pages.github.com/&quot;&gt;GitHub Pages&lt;/a&gt; to host the site right out of our repository.&lt;/p&gt;

&lt;p&gt;Using a browser-embedded database has the downside of having to re-download all your data when you go to a new browser or if you’ve cleared your cache, but we think that’s an acceptable trade-off to have complete control of your data.&lt;/p&gt;

&lt;p&gt;So check it out and let us know what you think. Send your bugs/feature requests/love to &lt;a href=&quot;mailto:support@wanderin.gs&quot;&gt;support@wanderin.gs&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Code Signing Will Kill Me Yet</title>
   <link href="https://footle.org/2016/03/31/code-signing-will-kill-me-yet/"/>
   <updated>2016-03-31T15:25:19-07:00</updated>
   <id>https://footle.org/2016/03/31/code-signing-will-kill-me-yet</id>
   <content type="html">&lt;p&gt;This is one of those &lt;em&gt;I-spent-long-enough-stumped-on-this-issue-I-should-write-it-up-for-future-generations&lt;/em&gt; posts.&lt;/p&gt;

&lt;p&gt;I wrote a little app at work (which I’ll talk about in a future post), and I was having a strange code signing issue. The app would sign just fine:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;spctl &lt;span class=&quot;nt&quot;&gt;--assess&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; Orwell.app
Orwell.app: accepted
&lt;span class=&quot;nb&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;Developer ID
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;But then if I zipped it up and sent it to someone, when they unzipped it, OS X would tell them that it was damaged and should be thrown away:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/images/app-is-damaged.png&quot; alt=&quot;Blech&quot; class=&quot;center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Sure enough, if I zip and unzip the app, and verify the code signing again, I get:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;spctl &lt;span class=&quot;nt&quot;&gt;--assess&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; Orwell.app
Orwell.app: a sealed resource is missing or invalid
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After much hair-pulling, I found &lt;a href=&quot;https://developer.apple.com/library/ios/technotes/tn2318/_index.html&quot;&gt;Technical Note TN2318: Troubleshooting Failed Signature Verification&lt;/a&gt;, which says:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The file prefixed with “._” is problematic and a was the result of copying certain Mac OS X files to a non-HFS+ formatted disk. These files are referred to as Dot files, Apple Double files, or resource forks. They are invisible to Finder but can be removed using the dot_clean utility.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sure enough:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;find Orwell.app &lt;span class=&quot;nt&quot;&gt;-name&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;._*&quot;&lt;/span&gt;
Orwell.app/Contents/Resources/app/node_modules/applescript/._package.json
Orwell.app/Contents/Resources/app/node_modules/applescript/lib/._applescript.js
Orwell.app/Contents/Resources/app/node_modules/applescript/samples/._execString.js
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;dot_clean Orwell.app
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;find Orwell.app &lt;span class=&quot;nt&quot;&gt;-name&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;._*&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Running &lt;a href=&quot;https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/dot_clean.1.html&quot;&gt;dot_clean&lt;/a&gt; before I signed the app fixed the issue.&lt;/p&gt;

&lt;p&gt;(Orwell is an &lt;a href=&quot;http://electron.atom.io/&quot;&gt;Electron&lt;/a&gt; app, hence the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node_modules&lt;/code&gt; dir, in case you were wondering.)&lt;/p&gt;

</content>
 </entry>

 
 
 <entry>
   <title>Fixing A Swift Memory Leak</title>
   <link href="https://footle.org/2015/10/10/fixing-a-swift-memory-leak/"/>
   <updated>2015-10-10T10:57:00-07:00</updated>
   <id>https://footle.org/2015/10/10/fixing-a-swift-memory-leak</id>
   <content type="html">&lt;p&gt;I wrote a Mac menu bar app for internal use at Etsy that show the status of a number of internal systems and pops up a notification if any of them change status—for example, if a problem is detected and someone puts a hold on our &lt;a href=&quot;https://github.com/etsy/PushBot&quot;&gt;deployment queue&lt;/a&gt;. &lt;img src=&quot;/public/images/fixing-leak/etsy-internal-status-menu.png&quot; alt=&quot;EtsyInternalStatus.app&quot; class=&quot;embed-right&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Some months ago, a colleague noticed the app was leaking memory. I put off looking at it until recently, when I noticed that my own instance was eating up 3+ GB of memory.&lt;/p&gt;

&lt;p&gt;Fortunately, Apple provides some great tools for tracking down leaks. One is &lt;a href=&quot;https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/InstrumentsUserGuide/Introduction/Introduction.html&quot;&gt;Instruments&lt;/a&gt;, an incredibly powerful tool that I know &lt;em&gt;thiiis&lt;/em&gt; (&lt;em&gt;puts thumb and forefinger a millimeter apart&lt;/em&gt;) much about. But I know enough to inspect a process for leaks.&lt;/p&gt;

&lt;p&gt;I started Instruments, selected the Leaks profiling template, and attached it to my leaky app, and saw this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/images/fixing-leak/instruments-1.png&quot; alt=&quot;Holy leak, Batman!&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Yup, that’s a leak. You can also drill down to see where the leak is coming from:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/images/fixing-leak/instruments-2.png&quot; alt=&quot;Drilling down to the leak&quot; /&gt;&lt;/p&gt;

&lt;p&gt;So the leak is obviously in the networking code, seemingly in Apple’s part of it.&lt;/p&gt;

&lt;p&gt;I should pause here to say a bit about how the app works. It’s pretty simple: every 3 seconds, it fetches an internal status web page, parses out the statuses from an HTML table (writing a JSON endpoint for the status page is on my todo list!), and updates the menu accordingly.&lt;/p&gt;

&lt;p&gt;The networking code in the app was pretty simple:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-swift&quot; data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;session&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;NSURLSession&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sharedSession&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;dataTaskWithURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// check for error, do something with the data&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;resume&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;a href=&quot;https://developer.apple.com/library/mac/documentation/Foundation/Reference/NSURLSession_class/&quot;&gt;NSURLSession&lt;/a&gt; was introduced with in Mavericks and iOS 7 as a replacement for NSURLConnection.&lt;/p&gt;

&lt;p&gt;I tried setting the cache sizes to 0, and invalidating the session when I was done, as recommended in &lt;a href=&quot;http://www.drdobbs.com/architecture-and-design/memory-leaks-in-ios-7/240168600&quot;&gt;this article&lt;/a&gt;, which seems to describe the same leak:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-swift&quot; data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// THIS CODE DID NOT HELP!&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;configuration&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;NSURLSessionConfiguration&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;defaultSessionConfiguration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;configuration&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;URLCache&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;NSURLCache&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;memoryCapacity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;diskCapacity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;diskPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;session&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;NSURLSession&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;configuration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;configuration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;defer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;finishTasksAndInvalidate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;dataTaskWithURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;But this didn’t help. What &lt;em&gt;did&lt;/em&gt; end up working was using an ephemeral session:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-swift&quot; data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;session&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;NSURLSession&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;configuration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;NSURLSessionConfiguration&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ephemeralSessionConfiguration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;dataTaskWithURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;With that in place, here’s what Instruments showed me:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/images/fixing-leak/instruments-no-leaks.png&quot; alt=&quot;No leaks!&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Yay! No leaks!&lt;/p&gt;

&lt;h4 id=&quot;we-dont-need-no-stinkin-gui&quot;&gt;We Don’t Need No Stinkin’ GUI&lt;/h4&gt;

&lt;p&gt;If you’re more of a command-line gal, there’s another way to investigate leaks built into OS X: the &lt;strong&gt;&lt;a href=&quot;https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/leaks.1.html&quot;&gt;leaks&lt;/a&gt;&lt;/strong&gt; command:&lt;/p&gt;

&lt;pre&gt;
$ &lt;b&gt;leaks EtsyInternalStatus&lt;/b&gt;
Process:         EtsyInternalStatus [24147]
Path:            /Applications/EtsyInternalStatus.app/Contents/MacOS/EtsyInternalStatus
Load Address:    0x105eaf000
Identifier:      com.etsy.EtsyInternalStatus
Version:         1.2.3 (1.2.3)
Code Type:       X86-64
Parent Process:  ??? [1]

Date/Time:       2015-09-02 20:33:26.173 -0700
Launch Time:     2015-09-02 20:30:44.447 -0700
OS Version:      Mac OS X 10.10.5 (14F27)
Report Version:  7
Analysis Tool:   /Applications/Xcode-beta.app/Contents/Developer/usr/bin/leaks
Analysis Tool Version:  Xcode 7.0 (7A192o)
----

leaks Report Version:  2.0
Process 24147: 25225 nodes malloced for 15639 KB
Process 24147: &lt;b&gt;615 leaks for 5321984 total leaked bytes.&lt;/b&gt;
Leak: 0x10a02f000  size=135168  zone: MallocHelperZone_0x105f65000  length: 5020
...
&lt;em&gt;&amp;lt;snipped 7800 lines of leaked memory dumps&amp;gt;&lt;/em&gt;
&lt;/pre&gt;

&lt;p&gt;Now, the fixed version:&lt;/p&gt;

&lt;pre&gt;
$ &lt;b&gt;leaks EtsyInternalStatus&lt;/b&gt;
Process:         EtsyInternalStatus [85066]
Path:            /Applications/EtsyInternalStatus.app/Contents/MacOS/EtsyInternalStatus
Load Address:    0x102d2f000
Identifier:      com.etsy.EtsyInternalStatus
Version:         1.2.4 (1.2.4)
Code Type:       X86-64
Parent Process:  ??? [1]

Date/Time:       2015-10-10 10:27:29.556 -0700
Launch Time:     2015-10-10 10:16:11.476 -0700
OS Version:      Mac OS X 10.10.5 (14F27)
Report Version:  7
Analysis Tool:   /Applications/Xcode.app/Contents/Developer/usr/bin/leaks
Analysis Tool Version:  Xcode 7.0.1 (7A1001)
----

leaks Report Version:  2.0
Process 85066: 62741 nodes malloced for 6598 KB
Process 85066: &lt;b&gt;0 leaks for 0 total leaked bytes.&lt;/b&gt;
&lt;/pre&gt;

&lt;p&gt;The eagled-eyed among you might have noticed that about a month elapsed between me running those checks (life intervened), and there was an Xcode release in the meantime. Turns out that when I ran the leak check again on the leaky version of the app, it was fine! I’m guessing that it was a bug in Apple’s networking code after all, and it got fixed in the latest release.&lt;/p&gt;

&lt;p&gt;Try out &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;leaks&lt;/code&gt; on some of the other apps you have running. You’ll find that leak-free apps are oddly rare, and some are downright eggregious (my beloved Sublime Text text editor, in which I’m writing this post, shows “577841 leaks for 44554352 total leaked bytes.” Oof).&lt;/p&gt;

&lt;p&gt;For more information, see Apple’s documentation on &lt;a href=&quot;https://developer.apple.com/library/mac/documentation/Performance/Conceptual/ManagingMemory/Articles/FindingLeaks.html&quot;&gt;Finding Memory Leaks&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>On "Working" Outside of Work Hours</title>
   <link href="https://footle.org/2015/08/08/on-working-outside-of-work-hours/"/>
   <updated>2015-08-08T22:53:58-07:00</updated>
   <id>https://footle.org/2015/08/08/on-working-outside-of-work-hours</id>
   <content type="html">&lt;p&gt;Etsy’s culture puts a very strong emphasis on &lt;a href=&quot;http://whoownsmyworklifebalance.com/&quot;&gt;work-life balance&lt;/a&gt;. As someone who has mostly worked for startups, this took some adjusting to. The fact that Etsy IRC and email pretty much goes silent outside of normal business hours struck me as odd initially. But, I really appreciate it. Startups are stressful, and they left me feeling that there was always something work-related that I should be doing whenever I had some “free time.”&lt;/p&gt;

&lt;p&gt;However, I love my work. I love the people I work with and the projects I work on. I love solving problems. I love coding. I wish I had more time to spend doing it. Having a family puts a massive dent in your free time. Don’t get me wrong, I love my family and am [usually] happy to spend any available time with them, but I so miss having large blocks of time to myself to just get into the zone.&lt;/p&gt;

&lt;p&gt;So when I or other colleagues mention coding (or even checking email) after hours, or on vacation, we’re often castigated for doing so. I love that my colleagues are looking out for my well-being, but hey, &lt;a href=&quot;https://www.youtube.com/watch?v=QereR0CViMY&quot;&gt;we’re all individuals&lt;/a&gt;. If you have no desire to be anywhere near a computer outside of work hours, that’s awesome. It’s pretty cool to work at a company where that’s not only possible, but encouraged, isn’t it? But please don’t judge me for thinking that my ideal vacation would be go somewhere alone, with my laptop and a fast internet connection, and just code.&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;If you’ll excuse me, I’ve got to get to bed. I like to wake up crazy early so I have a couple hours of alone time with my laptop.&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;There is an argument that a senior engineer working after-hours sets a bad example for more junior engineers, making them feel like they should be doing the same. This is certainly something to be cognizant of, but so long as the prevailing culture makes it clear that this is in no way expected behavior, it should not be an issue. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Two Tools for Packaging Mac Apps</title>
   <link href="https://footle.org/2015/04/19/two-tools-for-packaging-mac-apps/"/>
   <updated>2015-04-19T06:25:00-07:00</updated>
   <id>https://footle.org/2015/04/19/two-tools-for-packaging-mac-apps</id>
   <content type="html">&lt;p&gt;I ran across two apps yesterday that make packaging Mac apps for distribution a breeze:&lt;/p&gt;

&lt;p&gt;To easily build a professional DMG-based installer, look no further than &lt;a href=&quot;http://www.araelium.com/dmgcanvas&quot;&gt;DMG Canvas&lt;/a&gt;. There’s a free version with some limitations, but honestly $15 is a bargain for such a useful tool.&lt;/p&gt;

&lt;p&gt;For more complex installs, you might need to create a .pkg file, in which case grab the free (and ungoogleable) &lt;a href=&quot;http://s.sudre.free.fr/Software/Packages/about.html&quot;&gt;Packages&lt;/a&gt; app by Stéphane Sudre.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Write a Mac Menu Bar App in Swift</title>
   <link href="https://footle.org/2015/03/26/write-a-mac-menu-bar-app-in-swift/"/>
   <updated>2015-03-26T06:19:42-07:00</updated>
   <id>https://footle.org/2015/03/26/write-a-mac-menu-bar-app-in-swift</id>
   <content type="html">&lt;p&gt;This past week I taught an &lt;a href=&quot;https://blog.etsy.com/news/2013/about-us-etsy-school/&quot;&gt;Etsy School&lt;/a&gt; class on how to &lt;a href=&quot;http://footle.org/WeatherBar/&quot;&gt;write an OS X menu bar (aka status bar) app in Swift&lt;/a&gt;, and the walk-through is now public. I hope you find it useful.&lt;/p&gt;

&lt;p&gt;If you have any suggestions on improving it, &lt;a href=&quot;mailto:brad@footle.org&quot;&gt;let me know&lt;/a&gt;. (&lt;a href=&quot;https://github.com/bgreenlee/WeatherBar/pulls&quot;&gt;Or better yet, submit a PR!&lt;/a&gt;)&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Sublime Text Guide</title>
   <link href="https://footle.org/2014/11/09/sublime-text-guide/"/>
   <updated>2014-11-09T07:16:54-08:00</updated>
   <id>https://footle.org/2014/11/09/sublime-text-guide</id>
   <content type="html">&lt;p&gt;I’m a big fan of the &lt;a href=&quot;http://www.sublimetext.com/&quot;&gt;Sublime Text&lt;/a&gt; text editor, and I’ve become one of its biggest evangelists at Etsy. A few months ago I gave an internal presentation/tutorial session on it, and used those notes to create a guide on our internal wiki. I’ve ported that guide to my blog so I can spread the Good Word to others. Since the &lt;a href=&quot;https://github.com/bgreenlee/bgreenlee.github.io&quot;&gt;source code for my blog&lt;/a&gt; is available publicly, I’m also hoping that people will help make it even better.&lt;/p&gt;

&lt;p&gt;So head over to my &lt;a href=&quot;/sublime-text/&quot;&gt;Sublime Text Guide&lt;/a&gt; and let me know what you think.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Speeding up Jekyll's LSI</title>
   <link href="https://footle.org/2014/11/06/speeding-up-jekylls-lsi/"/>
   <updated>2014-11-06T08:51:59-08:00</updated>
   <id>https://footle.org/2014/11/06/speeding-up-jekylls-lsi</id>
   <content type="html">&lt;p&gt;Jekyll’s Latent Semantic Indexing (LSI) indexes your posts to create the “Related Posts” section you see at the bottom of the individual post pages. However, if you have more than a handful of posts, it is very slow, and it seems to get exponentially slower as the number of posts increase. I ran it on this site, with ~140 posts, and I finally killed it after 3 hours.&lt;/p&gt;

&lt;p&gt;There’s a fix for this, though, buried in the README for &lt;a href=&quot;https://github.com/jekyll/classifier-reborn&quot;&gt;classifier-reborn&lt;/a&gt;, the library used to do the post classification. Install &lt;a href=&quot;http://www.gnu.org/software/gsl&quot;&gt;GNU GSL&lt;/a&gt; and &lt;a href=&quot;https://rubygems.org/gems/rb-gsl&quot;&gt;rb-gsl&lt;/a&gt;. On OS X with &lt;a href=&quot;http://brew.sh/&quot;&gt;homebrew&lt;/a&gt;, it’s as easy as:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;brew &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;gsl
gem &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;rb-gsl
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Indexing time for me went from, well, 3-∞ hours to less than 5 seconds.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Fun with Swift Extensions</title>
   <link href="https://footle.org/2014/11/04/fun-with-swift-extensions/"/>
   <updated>2014-11-04T22:04:55-08:00</updated>
   <id>https://footle.org/2014/11/04/fun-with-swift-extensions</id>
   <content type="html">&lt;p&gt;As promised, a post on extensions in Swift.&lt;/p&gt;

&lt;p&gt;This isn’t going to be an in-depth tutorial. Extensions have been covered better elsewhere, most notably in &lt;a href=&quot;https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Extensions.html&quot;&gt;Apple’s excellent documentation&lt;/a&gt;. I just want to show a couple extensions I’ve written: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Array#find&lt;/code&gt;, and comparison operators for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSDate&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;arrayfind&quot;&gt;Array#find&lt;/h3&gt;

&lt;p&gt;If you want to find a value in a Swift Array, you can use the global generic &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;find&lt;/code&gt; function:&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;arr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;23&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;idx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// Some(2)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;However, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;find&lt;/code&gt; only lets you search for a static value, and what I really wanted was the ability to find the first value that satisfied a test function. For example, say I want to find the first odd number in an array. Let’s extend Array so we can do that.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;extension&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Array&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Bool&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;nil&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;arr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;23&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;idx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// Some(2)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The extension defines a method, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;find&lt;/code&gt;, on Array, that takes as an argument a function mapping an element of type T to a Bool, and returns an optional Int. In other words, we pass in a test function, and it returns the index of the first value in the array for which that function is true. If no such values are found, it returns nil.&lt;/p&gt;

&lt;p&gt;But wait! you say. Why write an extension when you can just add a new signature to the global &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;find&lt;/code&gt; function so that it will take a test function rather than a value? FINE. Be that way.&lt;/p&gt;

&lt;p&gt;You can, um, find the method signature of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;find&lt;/code&gt; in &lt;a href=&quot;https://developer.apple.com/library/ios/documentation/General/Reference/SwiftStandardLibraryReference/Algorithms.html#//apple_ref/doc/uid/TP40014608-CH15-DontLinkElementID_14&quot;&gt;Apple’s documentation&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CollectionType&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Generator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Equatable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;domain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Generator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That looks a bit complicated, and CollectionTypes and Generators are a topic for another day, but all you really need to know is that in order to conform to the CollectionType protocol, you need to define a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;startIndex&lt;/code&gt; and an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;endIndex&lt;/code&gt;, and be subscriptable. C.Generator.Element is the type of items in the collection. So instead of passing in a value of type C.Generator.Element to find, we want to pass in a test function that takes a C.Generator.Element and returns a Bool. The rest looks very much like our Array extension:&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CollectionType&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Generator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Equatable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;domain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Generator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Bool&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;domain&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;startIndex&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;domain&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;endIndex&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;domain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;arr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;23&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;idx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// Some(2)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;comparison-operators-for-nsdate&quot;&gt;Comparison Operators for NSDate&lt;/h3&gt;

&lt;p&gt;NSDate annoyingly does not implement the Comparable protocol, meaning that instead of:&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;someDate&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;anotherDate&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You have to do:&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;someDate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;compare&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;anotherDate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;NSComparisonResult&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;OrderedAscending&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;someDate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;isEqualToDate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;anotherDate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Let’s fix that. According to &lt;a href=&quot;https://developer.apple.com/library/ios/documentation/General/Reference/SwiftStandardLibraryReference/Comparable.html#//apple_ref/doc/uid/TP40014608-CH16-SW1&quot;&gt;Apple’s docs&lt;/a&gt;, we only need to implement &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;==&lt;/code&gt; to conform to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Comparable&lt;/code&gt; protocol. Pretty clever, since with just those two, you can derive &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;=&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;gt;&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;gt;=&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;!=&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;extension&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;NSDate&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Comparable&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;lhs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;NSDate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;rhs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;NSDate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Bool&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lhs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;compare&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rhs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;NSComparisonResult&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;OrderedAscending&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lhs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;isEqualToDate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rhs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;lhs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;NSDate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;rhs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;NSDate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Bool&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lhs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;isEqualToDate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rhs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The first line just says that we are extending &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NSDate&lt;/code&gt; to conform to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Comparable&lt;/code&gt; protocol. You can leave this out, but then you’ll have to implement all the other comparison operators.&lt;/p&gt;

&lt;p&gt;The rest is pretty straight-forward. The only curious bit is why the operators are implemented in the global scope, rather than within the extension. I.e. you’d think you could do this:&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// This does not work!&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;extension&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;NSDdate&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Comparable&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;NSDate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Bool&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;compare&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So why not? Operators aren’t methods in Swift, but global functions. They have precedence over methods, and have varying rules around associativity. You can even make up your own operators if you want. Be sure to read NSHipster’s &lt;a href=&quot;http://nshipster.com/swift-operators/&quot;&gt;great article on Swift operators&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Swift Compiler Bugs</title>
   <link href="https://footle.org/2014/11/04/misleading-swift-compiler-errors/"/>
   <updated>2014-11-04T05:27:31-08:00</updated>
   <id>https://footle.org/2014/11/04/misleading-swift-compiler-errors</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;https://developer.apple.com/swift/&quot;&gt;Swift&lt;/a&gt; is a great language, and far more enjoyable to program in than Objective-C, but it is still in its infancy, and bugs abound. One of the more frustrating is compiler errors that are flat-out wrong. Take a look at this (in Xcode 6.1):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/images/could_not_find_member.png&quot; alt=&quot;Could not find member&quot; /&gt;&lt;/p&gt;

&lt;p&gt;“Could not find member ‘date’?” Trust me when I tell you that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;date&lt;/code&gt; is indeed a member of a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Todo&lt;/code&gt; object. So what’s going on? Let’s tweak it a bit:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/images/could_not_find_member_better.png&quot; alt=&quot;Cannot invoke&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Ah, there we go. Turns out you can’t actually compare dates like that (hmm…I smell a follow-up post on writing extensions). Here’s how you do it:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/images/could_not_find_member_fixed.png&quot; alt=&quot;Fixed&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Here’s another one. The following is essentially a no-op:&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&amp;lt;&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That’s just a for loop from zero up to, but not including, zero. And this code is fine, doing what it is supposed to do—nothing.&lt;/p&gt;

&lt;p&gt;However, try making the ending value of the loop less than the starting value. This should be equivalent to the above:&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;...&lt;/code&gt; operator means “up to and including”. So this should also be a no-op (and it is in most programming languages). But:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/images/for_loop_boom_1.png&quot; alt=&quot;For Loop Boom&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Even worse, it will actually crash on the first executable line of code:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/images/for_loop_boom_2.png&quot; alt=&quot;For Loop Boom 2&quot; /&gt;&lt;/p&gt;

&lt;p&gt;None of this should scare you away from using Swift. It’s a fun language to work with, and ends up being much more concise than Objective-C. Just keep in mind that there are still bugs to be worked out, and if you’re getting errors that just make no sense, there’s a fair chance you’ve hit one.&lt;/p&gt;

</content>
 </entry>

 
 
 <entry>
   <title>The Importance of Sucking</title>
   <link href="https://footle.org/2014/11/03/the-importance-of-sucking/"/>
   <updated>2014-11-03T10:09:52-08:00</updated>
   <id>https://footle.org/2014/11/03/the-importance-of-sucking</id>
   <content type="html">&lt;p&gt;One of the defining charactaristics of a successful programmer is being OK with the feeling that you have no idea what you’re doing. I’ve been programming for over 30 years and it still happens to me regularly. The key is pushing on through that dark period, trusting that eventually you’ll catch a glimmer of light and it will slowly start to make sense.&lt;/p&gt;

&lt;p&gt;There are a few tricks I’ve picked up to help me get over that initial hump. The first is to find a tutorial someone has written, and just follow along, just to get &lt;em&gt;something&lt;/em&gt; working. Once I have something working, no matter how basic, not only do I start to get a better sense of how all the pieces fit together, but I can start tweaking it and learn from how it responds.&lt;/p&gt;

&lt;p&gt;Can’t find a good tutorial? Great! Here’s your opportunity to give back, and write your own. There’s really no better way to learn. Start with doing the most basic thing imaginable. Just get something working. Write down your steps as you go. Then add to it, write it down, repeat. You’ll eventually have something coherent that you can post, and you’ll earn a ton of internet karma points.&lt;/p&gt;

&lt;p&gt;It also really helps if you have a specific project to work on, otherwise the tutorial can be a bit of a dead end, and your effort can feel purposeless. Don’t have a project, and can’t think of one? Rewrite something you’ve already written. Ask friends and family if there’s an app they wish they had. Write a basic version of an app that you’re too cheap to buy. Write a &lt;a href=&quot;http://todomvc.com/&quot;&gt;todo app&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Start small, though; the bigger the project, the less likely you are to finish it. &lt;a href=&quot;http://en.wikipedia.org/wiki/Minimum_viable_product&quot;&gt;Minimum viable product (MVP)&lt;/a&gt; isn’t just Silicon Valley jargon; it applies equally well to personal projects. Do the simplest, dumbest thing possible. It’s easy to iterate and improve once you have something working, and you can always throw it all away and rewrite it once you feel you know what you’re doing.&lt;/p&gt;

&lt;p&gt;The feeling of sucking at something and being completely lost is a part of learning. Everyone starts out that way. If you’re actively avoiding sucking, you’re not learning. Get lost. Seriously, find someplace to get yourself lost. You’ll be better for it. Then tell us about it when you inevitably emerge from the darkness.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Prose.io</title>
   <link href="https://footle.org/2013/09/29/prose-io/"/>
   <updated>2013-09-29T00:00:00-07:00</updated>
   <id>https://footle.org/2013/09/29/prose-io</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;http://prose.io&quot;&gt;Prose.io&lt;/a&gt; is a content editor for GitHub. It supports &lt;a href=&quot;http://jekyllrb.com/&quot;&gt;Jekyll&lt;/a&gt; sites (like this one), and provides &lt;a href=&quot;http://daringfireball.net/projects/markdown/&quot;&gt;Markdown&lt;/a&gt; previews. I’m writing this post using it.&lt;/p&gt;

&lt;p&gt;I’m sure I looked at Prose some time ago, but must have decided something was lacking. But I just took a look at it again, and it’s just what I need. In fact, I had started a similar project myself not long ago, and now I feel relieved that I can officially call it dead and stop fretting about having stalled out on it.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>The Future of Programming</title>
   <link href="https://footle.org/2013/07/31/the-future-of-programming/"/>
   <updated>2013-07-31T15:42:37-07:00</updated>
   <id>https://footle.org/2013/07/31/the-future-of-programming</id>
   <content type="html">&lt;blockquote&gt;
  &lt;p&gt;The most dangerous thought that you can have as a creative person is to think that you know what you’re doing. Because once you think you know what you’re doing, you stop looking around for other ways of doing things.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;— &lt;a href=&quot;http://worrydream.com&quot;&gt;Brett Victor&lt;/a&gt;, &lt;a href=&quot;http://vimeo.com/71278954&quot;&gt;The Future of Programming&lt;/a&gt;&lt;/p&gt;

&lt;iframe src=&quot;http://player.vimeo.com/video/71278954?title=0&amp;amp;byline=0&amp;amp;portrait=0&quot; width=&quot;500&quot; height=&quot;281&quot; frameborder=&quot;0&quot; webkitallowfullscreen=&quot;&quot; mozallowfullscreen=&quot;&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;He’s posted references and follow-up notes at &lt;a href=&quot;http://worrydream.com/dbx/&quot;&gt;http://worrydream.com/dbx/&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Why is Git Rejecting Me?</title>
   <link href="https://footle.org/2013/06/26/why-is-git-rejecting-me/"/>
   <updated>2013-06-26T21:21:21-07:00</updated>
   <id>https://footle.org/2013/06/26/why-is-git-rejecting-me</id>
   <content type="html">&lt;p&gt;Every Git user, from novice to expert, gets this error message at some point, maybe even daily:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git push origin main
To git@github.com:bgreenlee/myrepo.git
 &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;rejected]        main -&amp;gt; main &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;non-fast-forward&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
error: failed to push some refs to &lt;span class=&quot;s1&quot;&gt;&apos;git@github.com:bgreenlee/myrepo.git&apos;&lt;/span&gt;
hint: Updates were rejected because a pushed branch tip is behind its remote
hint: counterpart. Check out this branch and merge the remote changes
hint: &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;e.g. &lt;span class=&quot;s1&quot;&gt;&apos;git pull&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; before pushing again.
hint: See the &lt;span class=&quot;s1&quot;&gt;&apos;Note about fast-forwards&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;git push --help&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;details.&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;There are a couple ways this can happen, but it all boils down to this: &lt;strong&gt;the remote repository you’re pushing to has one or more commits that you don’t have in your local repository&lt;/strong&gt;. Don’t worry, though, the fix is easy, although how to go about it depends on what you’re trying to do.&lt;/p&gt;

&lt;h2 id=&quot;refresher-rebase-vs-merge&quot;&gt;Refresher: Rebase vs. Merge&lt;/h2&gt;

&lt;p&gt;Before we dive in, a quick refresher on rebase vs. merge. These are two general strategies for combining two branches.&lt;/p&gt;

&lt;p&gt;Consider the following case:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  main: A -&amp;gt; B -&amp;gt; C
my-fix:       \-&amp;gt; D
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here, you created a branch named “my-fix” from main while it was at commit B. While you were working on your fix, someone else pushed commit C to main. You finish your fix and commit it to the my-fix branch. That’s commit D above.&lt;/p&gt;

&lt;p&gt;Now you’re ready to merge your my-fix branch back into main. There are two ways to go about this.&lt;/p&gt;

&lt;h3 id=&quot;merge&quot;&gt;Merge&lt;/h3&gt;

&lt;p&gt;You can do:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;git checkout main
git merge my-fix&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This will resolve the differences between the two branches by doing a three-way merge using commits C and D and their common ancestor, B. It does this by creating an additional merge commit, which we’ll call M:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;main: A -&amp;gt; B -&amp;gt; C -&amp;gt; M(B,C,D)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;rebase&quot;&gt;Rebase&lt;/h3&gt;

&lt;p&gt;You can also do:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;git checkout my-fix
git rebase main
git checkout main
git merge my-fix&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The first checkout is just to make sure you’re starting on the right branch. You may already be on the my-fix branch, in which case you can skip it.  What git rebase main does is “rewind” your branch to the point at which it diverged from main, B, then apply all the commits from main made after that point (C), then “replay” your commits to my-fix (D). What you get is:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;my-fix: A -&amp;gt; B -&amp;gt; C -&amp;gt; D’
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note that I used D’ above. This is because while the content of the commit is the same as your original commit D, it’s technically a different commit, with a different SHA. This will be important later.&lt;/p&gt;

&lt;p&gt;The last two commands switch back to main and then merge my-fix with main. &lt;strong&gt;Since at this point my-fix has everything that main has, plus one extra commit, the merge is just a “fast-forward”, meaning that all git has to do is move the HEAD pointer to D’—no merge commit is required.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now, merging vs. rebasing is somewhat of a religious issue, although in my experience, most organizations prefer rebasing, as it keeps the commit history from getting cluttered with merge commits. I am going to go on the assumption that rebasing is the preferred method.&lt;/p&gt;

&lt;p&gt;Now, let’s get back to fixing our problem.&lt;/p&gt;

&lt;h2 id=&quot;scenario-1-pull-then-push&quot;&gt;Scenario 1: Pull, then Push&lt;/h2&gt;

&lt;p&gt;This is the most common scenario, and simplest fix. Say you’ve made some changes in the main branch of your local repository, then go to push them to the main branch of the remote repository. If your push is rejected, what has most likey happened is that someone else pushed some changes to the remote main while you were making your changes, and you need to pull them down to your repo before you can push your changes up. So do a ‘git pull –rebase’, then push again.&lt;/p&gt;

&lt;h2 id=&quot;scenario-2-force-push&quot;&gt;Scenario 2: Force Push&lt;/h2&gt;

&lt;p&gt;Let’s say you’ve been working on your own branch, and suddenly git is rejecting you. Now you know that no one else has been pushing commits to that branch, so what happened?&lt;/p&gt;

&lt;p&gt;Most likely, you updated your local branch by rebasing against main. Again, this “rewinds” the commits in your branch to the point where they diverged from main, then pulls in the commits from main that you don’t have, then “replays” the commits in your branch that weren’t in main &lt;strong&gt;as new commits&lt;/strong&gt;. So when you go to push those to your remote branch, even though it may look like the commits are the same, the SHAs are different, so git will refuse to update the remote branch.&lt;/p&gt;

&lt;p&gt;One way around this is to force push:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;git push &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; origin my-fix&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This tells git that you don’t care about what’s on the remote branch, just update it with what you have locally. &lt;strong&gt;This can be dangerous. Don’t do it unless you know what you’re doing.&lt;/strong&gt; You would only ever want to do this if you are sure that you are the only one working on that branch, and that you have all the commits locally that are on the remote branch (i.e. you didn’t push changes from another machine). If that’s not the case, and, say, a coworker had pushed some of her own changes to your branch, you will overwrite those changes. Now, chances are they will be recoverable (she probably still has them in her local repository), but digging yourself out will be painful.&lt;/p&gt;

&lt;p&gt;If you are in a situation where you’ve rebased your branch and meanwhile your colleagues have pushed changes to the remote branch, one way to get back on track is to  cherry-pick their commits into your branch, and then force-push your branch (after telling your colleagues to hold off on pushing):&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;git fetch  &lt;span class=&quot;c&quot;&gt;# to make sure your repo knows about their commits&lt;/span&gt;
git log origin/my-fix  &lt;span class=&quot;c&quot;&gt;# to see what their commits are, and copy the shas&lt;/span&gt;
git cherry-pick &amp;lt;sha1&amp;gt;
git cherry-pick &amp;lt;sha2&amp;gt;
git push &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; origin my-fix&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Your colleagues will then have to delete their local branch and pull it down again.&lt;/p&gt;

&lt;p&gt;I’m sure I’ll get some hate mail for suggesting force push as a viable option, so I’ll reiterate: don’t do this unless you know what you’re doing. Even if you do know what you’re doing, you’re playing with fire, as a developer at my company learned when he accidentally force-pushed to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;origin main&lt;/code&gt;, which brought most of the engineering team to a halt while we figured out what got blown away and reconstructed main. (To git’s credit, it is hard to do real irreversible damage; between the &lt;a href=&quot;http://gitready.com/intermediate/2009/02/09/reflog-your-safety-net.html&quot;&gt;reflog&lt;/a&gt; and commits stored in your colleagues’ repos, you can almost always recover. It just may take some time to sort things out.)&lt;/p&gt;

&lt;p&gt;I should also note that it is possible to disable force-pushing on a per-repository basis (unfortunately not per-branch, AFAIK, but there are hoops you can jump through).&lt;/p&gt;

</content>
 </entry>

 
 
 <entry>
   <title>BetterExplained</title>
   <link href="https://footle.org/2012/12/21/betterexplained/"/>
   <updated>2012-12-21T20:25:26-08:00</updated>
   <id>https://footle.org/2012/12/21/betterexplained</id>
   <content type="html">&lt;p&gt;Excellent explanations of some complex math &amp;amp; programming topics. My favorite: &lt;a href=&quot;http://betterexplained.com/articles/an-interactive-guide-to-the-fourier-transform/&quot;&gt;An Interactive Guide To The Fourier Transform&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Snow Fall</title>
   <link href="https://footle.org/2012/12/20/snow-fall/"/>
   <updated>2012-12-20T22:32:38-08:00</updated>
   <id>https://footle.org/2012/12/20/snow-fall</id>
   <content type="html">&lt;p&gt;Amazing multimedia (that word is so 90s, but nothing more appropriate comes to mind) story of a fatal avalanche at Stevens Pass. Just look.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>TIL: John Hammond</title>
   <link href="https://footle.org/2012/05/18/til-john-hammond/"/>
   <updated>2012-05-18T16:36:25-07:00</updated>
   <id>https://footle.org/2012/05/18/til-john-hammond</id>
   <content type="html">&lt;p&gt;I don’t know how I managed to avoid learning about &lt;a href=&quot;http://en.wikipedia.org/wiki/John_H._Hammond&quot;&gt;John H. Hammond&lt;/a&gt; until now. A recent Radiolab episode, &lt;a href=&quot;http://www.radiolab.org/blogs/radiolab-blog/2012/apr/16/crossroads/&quot;&gt;Crossroads&lt;/a&gt;, introduced him to me.&lt;/p&gt;

&lt;p&gt;John Hammond was responsible for discovering and promoting some of the greatest musical talent of the 20th century: Benny Goodman, Count Basie, Billie Holiday, Pete Seeger, Aretha Franklin, George Benson, Leonard Cohen, Bob Dylan, Stevie Ray Vaughn, and Bruce Springsteen, among others. He was also responsible for introducing the world to the music of the great blues man Robert Johnson, who was the focus of the Radiolab piece.&lt;/p&gt;

&lt;p&gt;On top of that, he was a civil rights pioneer, playing a large role in integrating the music industry.&lt;/p&gt;

&lt;p&gt;(Incidentally, he appears to be no relation to &lt;a href=&quot;http://en.wikipedia.org/wiki/Laurens_Hammond&quot;&gt;Laurens Hammond&lt;/a&gt;, the inventor of the &lt;a href=&quot;http://en.wikipedia.org/wiki/Hammond_organ&quot;&gt;Hammond organ&lt;/a&gt;.)&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>A Year with MongoDB</title>
   <link href="https://footle.org/2012/04/13/a-year-with-mongodb/"/>
   <updated>2012-04-13T13:45:22-07:00</updated>
   <id>https://footle.org/2012/04/13/a-year-with-mongodb</id>
   <content type="html">&lt;p&gt;Nice summary of issues with running MongoDB at scale.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>rise4fun</title>
   <link href="https://footle.org/2012/04/13/rise4fun/"/>
   <updated>2012-04-13T13:44:16-07:00</updated>
   <id>https://footle.org/2012/04/13/rise4fun</id>
   <content type="html">&lt;p&gt;Software engineering tools from Microsoft Research.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>The Rise of the New Groupthink</title>
   <link href="https://footle.org/2012/01/14/the-rise-of-the-new-groupthink/"/>
   <updated>2012-01-14T09:12:36-08:00</updated>
   <id>https://footle.org/2012/01/14/the-rise-of-the-new-groupthink</id>
   <content type="html">&lt;p&gt;“Research strongly suggests that people are more creative when they enjoy privacy and freedom from interruption.”&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Learning and the Narcissism of Small Differences</title>
   <link href="https://footle.org/2011/12/28/learning-and-the-narcissism-of-small-differences/"/>
   <updated>2011-12-28T14:41:15-08:00</updated>
   <id>https://footle.org/2011/12/28/learning-and-the-narcissism-of-small-differences</id>
   <content type="html">&lt;p&gt;I started working with python full-time about a year-and-a-half ago. I was coming from having mostly done ruby and javascript for the last few years, and my prior exposure to python was relatively brief.&lt;/p&gt;

&lt;p&gt;I fairly quickly found a bunch of annoyances in python that I carped about frequently. Can’t resolve circular references? Ruby has no problem with that. Class and static methods tacked on via decorators? Those should be first-class concepts in any modern programming language. Not to mention that the python style of programming (and the circular reference issue) encouraged having multiple classes in a single file, or even files with bare, classless functions (i.e. modules). And what kind of crap is “&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if __name__ == &apos;__main__&apos;:&lt;/code&gt;”? Yeah, I did a lot of grumbling.&lt;/p&gt;

&lt;p&gt;But a funny thing happened. I kept working with it, learned to do things the “python way,” and most of these things turned out to be not such a big deal. I found a lot to like about python. The lack of extraneous characters for defining blocks (a.k.a. significant whitespace) was refreshing, and made for more readable code. It has a deep and well-documented standard library, and the quality of external libraries I’ve come across has generally been extraordinarily high. I had come to enjoy writing python.&lt;/p&gt;

&lt;p&gt;When learning something new, the natural reaction is to compare it to what we already know. That’s how the brain works, by making associations. The easy trap to fall into, however, is jumping to the conclusion that because it doesn’t quite fit the patterns that you’ve learned–because it is different–it is inferior or broken. This is often compounded by the normal frustrations any beginner encounters, especially when you’re in an environment where you’re expected to hit the ground running.&lt;/p&gt;

&lt;p&gt;I believe this is related to what Sigmund Freud termed &lt;a href=&quot;http://en.wikipedia.org/wiki/Narcissism_of_small_differences&quot;&gt;the narcissism of small differences&lt;/a&gt;, the idea that people with relatively minor differences in viewpoint tend to be more combative than those with major differences.&lt;/p&gt;

&lt;p&gt;Over time, as you learn and start to see more of the whole picture, those annoying differences become smaller and smaller, often disappearing entirely. In fact, you’ll likely come to appreciate some of those differences.&lt;/p&gt;

&lt;p&gt;It takes effort to fight those initial narcissistic tendencies. The next time you’re thrown into a foreign environment, make a conscious effort to keep an open mind, and bite your tongue until you’ve given it some time. After you’ve mastered the subject, then you’re entitled to bitch about it.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Christopher Hitchens, 1949 - 2011</title>
   <link href="https://footle.org/2011/12/16/hitchens/"/>
   <updated>2011-12-16T14:08:40-08:00</updated>
   <id>https://footle.org/2011/12/16/hitchens</id>
   <content type="html">&lt;p&gt;“To be the father of growing daughters is to understand something of what Yeats evokes with his imperishable phrase ‘terrible beauty.’ Nothing can make one so happily exhilarated or so frightened: it’s a solid lesson in the limitations of self to realize that your heart is running around inside someone else’s body. It also makes me quite astonishingly calm at the thought of death: I know whom I would die to protect and I also understand that nobody but a lugubrious serf can possibly wish for a father who never goes away.”&lt;/p&gt;

&lt;p&gt;– Christopher Hitchens, “Hitch-22”&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Apache Considered Harmful</title>
   <link href="https://footle.org/2011/11/23/apache-considered-harmful/"/>
   <updated>2011-11-23T11:15:52-08:00</updated>
   <id>https://footle.org/2011/11/23/apache-considered-harmful</id>
   <content type="html">&lt;p&gt;A &lt;a href=&quot;http://www.futurealoof.com/posts/apache-considered-harmful.html&quot;&gt;recent article by Mikeal Rogers &lt;/a&gt; about the Apache Software Foundation’s outmoded idea of open source contributions struck a chord with me.&lt;/p&gt;

&lt;p&gt;Some time ago I submitted a &lt;a href=&quot;https://github.com/cloudera/flume/pull/12&quot;&gt;pull request&lt;/a&gt; to Flume, making a very minor change to get something to compile again after code reorganization had broken it. About a week later, I got a comment from one of Cloudera’s engineers saying that the patch looked good, but that since they were in the process of moving to Apache Incubator, could I follow some &lt;a href=&quot;https://github.com/cloudera/flume/wiki/HowToContribute&quot;&gt;extra steps&lt;/a&gt;. The extra steps (create an account on Cloudera’s JIRA issue tracker, create an issue for the bug, generate a patch for my change and attach it to the issue) weren’t terribly onerous, but considering I had already moved on (and in fact had decided not to use Flume for my project), and had real work to get done, I put it on the back burner and eventually forgot all about it.&lt;/p&gt;

&lt;p&gt;The genius of git and GitHub is how easy it is to contribute to projects. Fork, fix, submit. &lt;a href=&quot;https://github.com/defnull/bottle/commits/master?author=bgreenlee&quot;&gt;I&lt;/a&gt; &lt;a href=&quot;https://github.com/AloneRoad/mogilelocal/commits/master?author=bgreenlee&quot;&gt;submit&lt;/a&gt; &lt;a href=&quot;https://github.com/github/github-services/commits/master?author=bgreenlee&quot;&gt;patches&lt;/a&gt; &lt;a href=&quot;https://github.com/spagalloco/airbrake-api/commit/e9abeefb8b5cd573c6bd0902e4775a32cab2c8b8&quot;&gt;to&lt;/a&gt; &lt;a href=&quot;https://github.com/boto/boto/commits/master?author=bgreenlee&quot;&gt;projects&lt;/a&gt; &lt;a href=&quot;https://github.com/defunkt/gist/commits/master?author=bgreenlee&quot;&gt;all&lt;/a&gt; &lt;a href=&quot;https://github.com/collectiveidea/tinder/commits/master?author=bgreenlee&quot;&gt;the&lt;/a&gt; &lt;a href=&quot;https://github.com/rails/rails/commits/master?author=bgreenlee&quot;&gt;damn&lt;/a&gt; &lt;a href=&quot;https://github.com/datamapper/extlib/commits/master?author=bgreenlee&quot;&gt;time&lt;/a&gt; because barrier to contribution is so low. Like most developers, I’ve got a job that keeps me busy, and any roadblocks big enough to take me out of my flow are usually going to stop me.&lt;/p&gt;

&lt;p&gt;Someone more patient than I submitted a &lt;a href=&quot;https://issues.cloudera.org/browse/FLUME-669&quot;&gt;“proper” patch&lt;/a&gt; for my Flume issue about a month later, so my conscience is clear. I hope, however, that the ASF eventually embraces the new open source reality. Their software will be better for it.&lt;/p&gt;

</content>
 </entry>

 
 
 <entry>
   <title>Google Analytics A Potential Threat to Anonymous Bloggers</title>
   <link href="https://footle.org/2011/11/17/google-analytics-a-potential-threat-to-anonymous-bloggers/"/>
   <updated>2011-11-17T04:42:05-08:00</updated>
   <id>https://footle.org/2011/11/17/google-analytics-a-potential-threat-to-anonymous-bloggers</id>
   <content type="html">&lt;p&gt;Interesting post from Andy Baio about tracking down an anonymous blogger via Google Analytics, and the trickiness of remaining anonymous in general.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;In about 30 minutes of searching, using only Google and eWhois, I was able to discover the identities of seven of the anonymous or pseudonymous bloggers, and in two cases, their employers. One blog about Anonymous’ hacking operations could easily be tracked to the founder’s consulting firm, while another tracking Mexican cartels was tied to a second domain with the name and address of a San Diego man.&lt;/p&gt;
&lt;/blockquote&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Cracking Siri</title>
   <link href="https://footle.org/2011/11/15/cracking-siri/"/>
   <updated>2011-11-15T13:57:43-08:00</updated>
   <id>https://footle.org/2011/11/15/cracking-siri</id>
   <content type="html">&lt;p&gt;Reverse-engineering Siri’s wire protocol.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>How Dark Sky Works</title>
   <link href="https://footle.org/2011/11/09/how-dark-sky-works/"/>
   <updated>2011-11-09T10:13:57-08:00</updated>
   <id>https://footle.org/2011/11/09/how-dark-sky-works</id>
   <content type="html">&lt;p&gt;Interesting approach, showcasing the power of open source machine learning and
computer vision libraries.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>On Parenthood</title>
   <link href="https://footle.org/2011/10/24/on-parenthood/"/>
   <updated>2011-10-24T12:40:12-07:00</updated>
   <id>https://footle.org/2011/10/24/on-parenthood</id>
   <content type="html">&lt;p&gt;Someday I’ll write my own take on parenthood, and I hope it’s half as good as Jeff Atwood’s.&lt;/p&gt;

&lt;p&gt;As an aside, as the parent of twins, that pie chart is still pretty accurate—only it’s twice as big.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Thump Phreaking</title>
   <link href="https://footle.org/2011/10/19/thump-phreaking/"/>
   <updated>2011-10-19T13:41:28-07:00</updated>
   <id>https://footle.org/2011/10/19/thump-phreaking</id>
   <content type="html">&lt;p&gt;Proof-of-concept out of Georgia Tech using the iPhone 4’s accelerometer as a keylogger.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Jewish [Math] Problems</title>
   <link href="https://footle.org/2011/10/10/jewish-math-problems/"/>
   <updated>2011-10-10T21:33:31-07:00</updated>
   <id>https://footle.org/2011/10/10/jewish-math-problems</id>
   <content type="html">&lt;blockquote&gt;
  &lt;p&gt;This is a special collection of problems that were given to select applicants during oral entrance exams to the math department of Moscow State University. These problems were designed to prevent Jews and other undesirables from getting a passing grade. Among problems that were used by the department to blackball unwanted candidate students, these problems are distinguished by having a simple solution that is difficult to find. Using problems with a simple solution protected the administration from extra complaints and appeals. This collection therefore has mathematical as well as historical value.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;via &lt;a href=&quot;https://twitter.com/b6n/status/123594885151469568&quot;&gt;@b6n&lt;/a&gt;&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Dart: a language for structured web programming</title>
   <link href="https://footle.org/2011/10/10/dart-a-language-for-structured-web-programming/"/>
   <updated>2011-10-10T05:47:26-07:00</updated>
   <id>https://footle.org/2011/10/10/dart-a-language-for-structured-web-programming</id>
   <content type="html">&lt;p&gt;Dart is a new web programming language from Google. See also the &lt;a href=&quot;http://googlecode.blogspot.com/2011/10/dart-language-for-structured-web.html&quot;&gt;blog post introducing Dart&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>The Man Who Inspired Jobs</title>
   <link href="https://footle.org/2011/10/08/the-man-who-inspired-jobs/"/>
   <updated>2011-10-08T15:12:19-07:00</updated>
   <id>https://footle.org/2011/10/08/the-man-who-inspired-jobs</id>
   <content type="html">&lt;p&gt;“Market research is what you do when your product isn’t any good.”&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Thank you, Steve</title>
   <link href="https://footle.org/2011/10/05/thank-you-steve/"/>
   <updated>2011-10-05T17:49:37-07:00</updated>
   <id>https://footle.org/2011/10/05/thank-you-steve</id>
   <content type="html">&lt;p&gt;My first home computer was an Apple IIe, in 1984. I had already started learning to program (on a TRS-80 Model III), but that IIe was where I really got excited about computers and programming. I wrote utilities and games in BASIC, then 6502 assembly language (I would write the assembler instructions down on paper, then translate those by hand to the byte code), hacked games (&lt;a href=&quot;http://en.wikipedia.org/wiki/The_Bard&apos;s_Tale_(1985_video_game)&quot;&gt;Bard’s Tale&lt;/a&gt; character editor, anyone?), and even taught programming classes to other kids.&lt;/p&gt;

&lt;p&gt;The Steves, Jobs and Wozniak, were always heroes of mine, although it wasn’t until I was older that I truly appreciated Jobs’ brilliance. I always thought that Woz, the engineer, was the one who made the magic happen, but if it weren’t for Jobs, Apple could well have faded with &lt;a href=&quot;http://en.wikipedia.org/wiki/Beagle_Bros&quot;&gt;Beagle Bros&lt;/a&gt; into obscurity.&lt;/p&gt;

&lt;p&gt;Like a majority of people I know, I use Apple products daily, for work, entertainment, and communication. I can’t think of another company that puts as much thought into the quality of their products, both in terms of construction and user experience, and there’s no doubt that Steve Jobs is the one to thank for that.&lt;/p&gt;

&lt;p&gt;I still have that IIe, in a suitcase in my garage. I think I’ll boot it up tonight in tribute. Thanks for everything, Steve. Rest in peace.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/images/thanks-iie.jpg&quot; alt=&quot;IIe Thanks&quot; /&gt;&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Mozilla's Secure Coding Guidelines for Web Applications</title>
   <link href="https://footle.org/2011/10/03/mozillas-secure-coding-guidelines-for-web-applications/"/>
   <updated>2011-10-03T15:49:52-07:00</updated>
   <id>https://footle.org/2011/10/03/mozillas-secure-coding-guidelines-for-web-applications</id>
   <content type="html">&lt;p&gt;See also &lt;a href=&quot;https://www.owasp.org/index.php/Cheat_Sheets&quot;&gt;OWASP’s Cheat Sheet Series&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>O'Reilly's Open Feedback Publishing System</title>
   <link href="https://footle.org/2011/09/25/oreillys-open-feedback-publishing-system/"/>
   <updated>2011-09-25T14:46:39-07:00</updated>
   <id>https://footle.org/2011/09/25/oreillys-open-feedback-publishing-system</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;/2011/07/24/hbase-the-definitive-guide&quot;&gt;Mentioned previously&lt;/a&gt;, O’Reilly’s
Open Feedback Publishing System is a great resource for developers, and a brilliant
move my O’Reilly to get early feedback and corrections on their books before they
go to print.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Qu</title>
   <link href="https://footle.org/2011/09/23/qu/"/>
   <updated>2011-09-23T20:48:00-07:00</updated>
   <id>https://footle.org/2011/09/23/qu</id>
   <content type="html">&lt;p&gt;Qu is a new Ruby queuing and background job-processing library from Brandon Keepers, 
one of the maintainers of &lt;a href=&quot;https://github.com/tobi/delayed_job&quot;&gt;delayed_job&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Experiment in Extreme Schooling</title>
   <link href="https://footle.org/2011/09/20/experiment-in-extreme-schooling/"/>
   <updated>2011-09-20T14:42:00-07:00</updated>
   <id>https://footle.org/2011/09/20/experiment-in-extreme-schooling</id>
   <content type="html">&lt;p&gt;Fascinating article about a New York Times writer who moves to Russia with his family, and immerses his kids in a Russian school.&lt;/p&gt;

&lt;p&gt;What really resonated with me is just how resilient kids are. I often catch myself thinking that my own girls aren’t ready for something, that it will be too hard for them, but that’s a dangerous attitude to have. Much better to believe that they can do anything, because chances are, they can.&lt;/p&gt;

&lt;p&gt;See also the &lt;a href=&quot;http://6thfloor.blogs.nytimes.com/2011/09/20/our-familys-experiment-in-extreme-schooling-a-postscript/&quot;&gt;postscript&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Storm</title>
   <link href="https://footle.org/2011/09/20/storm/"/>
   <updated>2011-09-20T14:04:40-07:00</updated>
   <id>https://footle.org/2011/09/20/storm</id>
   <content type="html">&lt;p&gt;Storm is a distributed “realtime” computation system from Twitter.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>The Kid Should See This</title>
   <link href="https://footle.org/2011/08/28/the-kid-should-see-this/"/>
   <updated>2011-08-28T14:20:00-07:00</updated>
   <id>https://footle.org/2011/08/28/the-kid-should-see-this</id>
   <content type="html">&lt;p&gt;A great collection of “off the grid-for-little-kids” videos. “It’s most likely 
not stuff that was made for them…But we don’t underestimate kids around here.”&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Time</title>
   <link href="https://footle.org/2011/07/31/time/"/>
   <updated>2011-07-31T14:33:15-07:00</updated>
   <id>https://footle.org/2011/07/31/time</id>
   <content type="html">&lt;p&gt;Must-read–especially for programmers–notes about time.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>HBase: The Definitive Guide</title>
   <link href="https://footle.org/2011/07/24/hbase-the-definitive-guide/"/>
   <updated>2011-07-24T14:39:41-07:00</updated>
   <id>https://footle.org/2011/07/24/hbase-the-definitive-guide</id>
   <content type="html">&lt;p&gt;Great guide to HBase, available free (for the time being) online via O’Reilly’s
&lt;a href=&quot;http://ofps.oreilly.com/&quot;&gt;Open Feedback Publishing System&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Pandoc</title>
   <link href="https://footle.org/2011/07/17/pandoc/"/>
   <updated>2011-07-17T21:13:57-07:00</updated>
   <id>https://footle.org/2011/07/17/pandoc</id>
   <content type="html">&lt;p&gt;Pandoc is a universal document converter. Incredibly useful, especially for 
converting Markdown to HTML, PDF, etc.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>PatrickJMT: Just Math Tutorials</title>
   <link href="https://footle.org/2011/06/17/patrickjmt-just-math-tutorials/"/>
   <updated>2011-06-17T21:23:16-07:00</updated>
   <id>https://footle.org/2011/06/17/patrickjmt-just-math-tutorials</id>
   <content type="html">&lt;p&gt;Free video tutorials on hundreds of math topics.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>NASA - The Frontier Is Everywhere</title>
   <link href="https://footle.org/2011/01/17/nasa-the-frontier-is-everywhere/"/>
   <updated>2011-01-17T08:07:55-08:00</updated>
   <id>https://footle.org/2011/01/17/nasa-the-frontier-is-everywhere</id>
   <content type="html">&lt;div class=&quot;video-container&quot;&gt;
&lt;iframe width=&quot;600&quot; height=&quot;335&quot; src=&quot;http://www.youtube.com/embed/oY59wZdCDo0?rel=0&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
</content>
 </entry>

 
 
 <entry>
   <title>My Milkshake</title>
   <link href="https://footle.org/2011/01/15/my-milkshake/"/>
   <updated>2011-01-15T04:07:00-08:00</updated>
   <id>https://footle.org/2011/01/15/my-milkshake</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;http://25.media.tumblr.com/tumblr_lf2yl95ET71qz6k71o1_400.jpg&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Seen at &lt;a href=&quot;http://www.trueburgeroakland.com/&quot;&gt;Trueburger&lt;/a&gt;, Oakland&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Yahoo Account Hacked</title>
   <link href="https://footle.org/2011/01/14/yahoo-account-hacked/"/>
   <updated>2011-01-14T01:43:23-08:00</updated>
   <id>https://footle.org/2011/01/14/yahoo-account-hacked</id>
   <content type="html">&lt;p&gt;My Yahoo account was hacked this morning. The first sign that something was up was an email from Yahoo saying that an email address was added to my account. The address was “bradley_greenlee@yahoo.com”. Tricky. It definitely gave me pause. That’s my name, but I didn’t think I had that account. I went in and deleted it.&lt;/p&gt;

&lt;p&gt;Suddenly Adium went nuts, popping up 20+ dialogs saying “&amp;lt;username&amp;gt; has (retroactively) denied your request to add them to your list.” Huh. Then came the first of a number of emails from friends (basically, Y! IM friends) saying that they had gotten an email from me saying that I was stuck in Wales without my creditcard and passport yada yada. Yup, hacked.&lt;/p&gt;

&lt;p&gt;I was already on my way to changing my password. Unfortunately, my Yahoo account was still tied to my old AT&amp;amp;T DSL account, and I had to remember the username for that before I got in (this actually probably saved my butt, preventing the attacker from changing my password). I did eventually get in, though, and changed it to a nice, long random string.&lt;/p&gt;

&lt;p&gt;So, how did this happen? Well, Yahoo was my spam-bucket account–I used it on a lot of throwaway sites that needed an email address. Unfortunately, I never changed the password from a common one I use on a lot of those same throwaway sites (for sites that I actually care about, I generate a random password, which I store in &lt;a href=&quot;http://agilewebsolutions.com/onepassword&quot;&gt;1Password&lt;/a&gt;). Stupid. I’m sure one of those sites got compromised and were storing their passwords in plaintext.&lt;/p&gt;

&lt;p&gt;I don’t think much damage was done, other than spamming a lot of Y! IM friends. The upside was that I got back in touch with some friends I hadn’t talked to in ages.&lt;/p&gt;

&lt;p&gt;The lesson here is to never trust any site to keep your password secure. Count on it getting compromised at some point. Use a random password for each one, and a tool like &lt;a href=&quot;http://agilewebsolutions.com/onepassword&quot;&gt;1Password&lt;/a&gt; or &lt;a href=&quot;http://lastpass.com/&quot;&gt;LastPass&lt;/a&gt; to keep track of them.&lt;/p&gt;

&lt;p&gt;Most important, never use the same password on your email accounts that you do on any other site. If your email account gets compromised, the attacker can use that account to gain access (via “forgot password”) to any other sites that use that email address.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Digital Publishing Isn't Dead Yet</title>
   <link href="https://footle.org/2010/12/29/digital-publishing-not-dead-yet/"/>
   <updated>2010-12-29T07:05:25-08:00</updated>
   <id>https://footle.org/2010/12/29/digital-publishing-not-dead-yet</id>
   <content type="html">&lt;p&gt;ReadWriteWeb posted a short article today, &lt;a href=&quot;http://www.readwriteweb.com/archives/the_ipad_not_a_savior_to_magazines_as_digital_sale.php&quot;&gt;The iPad Not a Savior of Magazines, as Digital Sales Continue to Fall&lt;/a&gt;. Looking at the current sales trend is pretty silly, however. Of course you’re going to see a big drop-off. Early adopters are eager to check out The Future, but people aren’t going to continue to pay newsstand prices for digital editions of magazines, especially if they’re already paying for a print subscription.&lt;/p&gt;

&lt;p&gt;I don’t think we’ll see much improvement until both Apple and the publishers get over themselves and &lt;a href=&quot;http://www.cultofmac.com/apples-app-subscription-plan-has-been-on-table-for-months-but-print-mags-arent-interested/72151&quot;&gt;come to an agreement on subscription pricing&lt;/a&gt;. At issue is how much access the publishers get to their subscribers’ data. Traditionally, what keeps print publications alive is their ability to resell their subscribers’ information to advertisers. But Apple isn’t about to give that up. So either publishers need to accept that they’re going to have to give up some control in order to play in Apple’s ecosystem, or Apple needs to loosen its grip a bit (less likely).&lt;/p&gt;

&lt;p&gt;Still, I’d wager that in 5 years, digital subscription sales will surpass print.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>RSA Animate - The Secret Powers of Time</title>
   <link href="https://footle.org/2010/10/08/rsa-animate-the-secret-powers-of-time/"/>
   <updated>2010-10-08T03:59:35-07:00</updated>
   <id>https://footle.org/2010/10/08/rsa-animate-the-secret-powers-of-time</id>
   <content type="html">&lt;div class=&quot;video-container&quot;&gt;
&lt;iframe width=&quot;600&quot; height=&quot;335&quot; src=&quot;http://www.youtube.com/embed/A3oIiH7BLmg?rel=0&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
</content>
 </entry>

 
 
 <entry>
   <title>The Swell Season covers Neutral Milk Hotel</title>
   <link href="https://footle.org/2010/08/13/the-swell-season-covers-neutral-milk-hotel/"/>
   <updated>2010-08-13T02:41:12-07:00</updated>
   <id>https://footle.org/2010/08/13/the-swell-season-covers-neutral-milk-hotel</id>
   <content type="html">
</content>
 </entry>

 
 
 <entry>
   <title>Installing Ruby 1.9.2 via rvm on OS X</title>
   <link href="https://footle.org/2010/07/29/installing-ruby-1-9-2-via-rvm-on-os-x/"/>
   <updated>2010-07-29T13:34:10-07:00</updated>
   <id>https://footle.org/2010/07/29/installing-ruby-1-9-2-via-rvm-on-os-x</id>
   <content type="html">&lt;p&gt;It took me a bit of digging to figure this out (it kept failing with readline errors, and then iconv went missing), so I thought I’d share:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;rvm package &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;readline
rvm package &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;iconv
rvm &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;1.9.2 &lt;span class=&quot;nt&quot;&gt;-C&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--enable-shared&lt;/span&gt;,--with-iconv-dir&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$HOME&lt;/span&gt;/.rvm/usr,&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;--with-readline-dir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$HOME&lt;/span&gt;/.rvm/usr&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package&lt;/code&gt; command has been renamed &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pkg&lt;/code&gt; in newer versions of rvm.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>For Jessica</title>
   <link href="https://footle.org/2010/07/29/for-jessica/"/>
   <updated>2010-07-29T01:58:15-07:00</updated>
   <id>https://footle.org/2010/07/29/for-jessica</id>
   <content type="html">&lt;blockquote&gt;
  &lt;p&gt;A couple of weeks ago, a friend of mine and I were talking about a study 
she’d just read, which concluded that people without children were happier than 
people with children; or, to put it more precisely, despite what conventional 
wisdom holds, the study found that having children did not increase anyone’s 
happiness.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;At which all I could do was burst out laughing.  Because, well.  Duh.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Only an academic would undertake a study like this, defining happiness as 
something along the lines of “satisfaction with life” and “feeling rewarded by 
your work.” If there’s an occupation more likely to make you feel incompetent 
and unrewarded than being a parent, I have never heard of it.&lt;/p&gt;
&lt;/blockquote&gt;
</content>
 </entry>

 
 
 <entry>
   <title>The Top Idea</title>
   <link href="https://footle.org/2010/07/21/the-top-idea/"/>
   <updated>2010-07-21T06:01:50-07:00</updated>
   <id>https://footle.org/2010/07/21/the-top-idea</id>
   <content type="html">
</content>
 </entry>

 
 
 <entry>
   <title>The American Scholar: Solitude and Leadership</title>
   <link href="https://footle.org/2010/07/10/solitude-and-leadership/"/>
   <updated>2010-07-10T09:52:12-07:00</updated>
   <id>https://footle.org/2010/07/10/solitude-and-leadership</id>
   <content type="html">&lt;p&gt;&lt;em&gt;If you want others to follow, learn to be alone with your thoughts&lt;/em&gt;&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Michigan Rain</title>
   <link href="https://footle.org/2010/07/05/michigan-rain/"/>
   <updated>2010-07-05T11:10:06-07:00</updated>
   <id>https://footle.org/2010/07/05/michigan-rain</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;http://28.media.tumblr.com/tumblr_l5461zUOFj1qz6k71o1_500.jpg&quot; /&gt;
&lt;br /&gt;
&lt;script type=&quot;text/javascript&quot; language=&quot;javascript&quot; src=&quot;http://assets.tumblr.com/javascript/tumblelog.js?16&quot;&gt;&lt;/script&gt;
&lt;span id=&quot;audio_player_774970550&quot;&gt;[&lt;a href=&quot;http://www.adobe.com/shockwave/download/download.cgi?P1_Prod_Version=ShockwaveFlash&quot; target=&quot;_blank&quot;&gt;Flash 9&lt;/a&gt; is required to listen to audio.]&lt;/span&gt;&lt;script type=&quot;text/javascript&quot;&gt;replaceIfFlash(9,&quot;audio_player_774970550&quot;,&apos;\x3cdiv class=\x22audio_player\x22\x3e&lt;embed type=&quot;application/x-shockwave-flash&quot; src=&quot;http://tumblr.footle.org/swf/audio_player_black.swf?audio_file=http://www.tumblr.com/audio_file/774970550/tumblr_l545xjCa1u1qz6k71&amp;amp;color=FFFFFF&quot; height=&quot;27&quot; width=&quot;207&quot; quality=&quot;best&quot; /&gt;&amp;lt;/embed&amp;gt;\x3c/div\x3e&apos;)&lt;/script&gt;&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>OS X Screen Sharing over SSH</title>
   <link href="https://footle.org/2010/06/18/os-x-screen-sharing-over-ssh/"/>
   <updated>2010-06-18T07:27:15-07:00</updated>
   <id>https://footle.org/2010/06/18/os-x-screen-sharing-over-ssh</id>
   <content type="html">&lt;p&gt;I recently set up a Mac Mini at home, and have found using Screen Sharing to access it invaluable. Not wanting to open up anything other than SSH on my home router, I created the following script to open up a Screen Sharing session over SSH:&lt;/p&gt;

&lt;script src=&quot;http://gist.github.com/444303.js&quot;&gt;&lt;/script&gt;

</content>
 </entry>

 
 
 <entry>
   <title>Peter Callesen - A Single Sheet of Paper</title>
   <link href="https://footle.org/2010/06/03/peter-callesen-a-single-sheet-of-paper/"/>
   <updated>2010-06-03T01:18:32-07:00</updated>
   <id>https://footle.org/2010/06/03/peter-callesen-a-single-sheet-of-paper</id>
   <content type="html">
</content>
 </entry>

 
 
 <entry>
   <title>Raganwald: Optimism</title>
   <link href="https://footle.org/2010/05/18/optimism/"/>
   <updated>2010-05-18T07:10:22-07:00</updated>
   <id>https://footle.org/2010/05/18/optimism</id>
   <content type="html">
</content>
 </entry>

 
 
 <entry>
   <title>Zeldman: Life is Beautiful</title>
   <link href="https://footle.org/2010/05/11/life-is-beautiful/"/>
   <updated>2010-05-11T13:53:05-07:00</updated>
   <id>https://footle.org/2010/05/11/life-is-beautiful</id>
   <content type="html">
</content>
 </entry>

 
 
 <entry>
   <title>"Oh Mary" by theresa andersson</title>
   <link href="https://footle.org/2010/05/07/oh-mary/"/>
   <updated>2010-05-07T14:17:59-07:00</updated>
   <id>https://footle.org/2010/05/07/oh-mary</id>
   <content type="html">&lt;div class=&quot;video-container&quot;&gt;
&lt;iframe width=&quot;600&quot; height=&quot;335&quot; src=&quot;http://www.youtube.com/embed/GJkQvyoWJBk?rel=0&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Richard Feynman and The Connection Machine</title>
   <link href="https://footle.org/2010/03/22/richard-feynman-and-the-connection-machine/"/>
   <updated>2010-03-22T08:46:05-07:00</updated>
   <id>https://footle.org/2010/03/22/richard-feynman-and-the-connection-machine</id>
   <content type="html">&lt;p&gt;I 💖 Feynman&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Panic Cakes</title>
   <link href="https://footle.org/2010/03/19/panic-cakes/"/>
   <updated>2010-03-19T14:43:49-07:00</updated>
   <id>https://footle.org/2010/03/19/panic-cakes</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;http://24.media.tumblr.com/tumblr_kzkfx1t75O1qz6k71o1_500.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;via &lt;a href=&quot;http://thisisnthappiness.com/post/457136469/sketchbook-by-paul-madonna&quot;&gt;this isn’t happiness&lt;/a&gt;&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>New York Times: Christoph Niemann's Abstract City</title>
   <link href="https://footle.org/2010/03/11/christoph-niemanns-abstract-city/"/>
   <updated>2010-03-11T14:44:00-08:00</updated>
   <id>https://footle.org/2010/03/11/christoph-niemanns-abstract-city</id>
   <content type="html">
</content>
 </entry>

 
 
 <entry>
   <title>Out Of A Forest</title>
   <link href="https://footle.org/2010/03/07/out-of-a-forest/"/>
   <updated>2010-03-07T15:48:51-08:00</updated>
   <id>https://footle.org/2010/03/07/out-of-a-forest</id>
   <content type="html">&lt;p&gt;This was the first time I had heard The National. I immediately went out and
bought &lt;a href=&quot;http://www.amazon.com/gp/product/B000O5AYCA/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=footle0c-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=B000O5AYCA&quot;&gt;Boxer&lt;/a&gt;&lt;img src=&quot;http://www.assoc-amazon.com/e/ir?t=&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=B000O5AYCA&amp;amp;camp=217145&amp;amp;creative=399369&quot; width=&quot;1&quot; height=&quot;1&quot; border=&quot;0&quot; alt=&quot;&quot; style=&quot;border:none !important; margin:0px !important;&quot; /&gt;.&lt;/p&gt;

&lt;div class=&quot;video-container&quot;&gt;
&lt;iframe src=&quot;http://player.vimeo.com/video/9335203?title=0&amp;amp;byline=0&amp;amp;portrait=0&quot; width=&quot;601&quot; height=&quot;338&quot; frameborder=&quot;0&quot; webkitallowfullscreen=&quot;&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Pivot</title>
   <link href="https://footle.org/2010/02/09/pivot/"/>
   <updated>2010-02-09T02:49:00-08:00</updated>
   <id>https://footle.org/2010/02/09/pivot</id>
   <content type="html">&lt;div class=&quot;video-container&quot;&gt;
&lt;iframe src=&quot;http://player.vimeo.com/video/9178331?title=0&amp;amp;byline=0&amp;amp;portrait=0&quot; width=&quot;601&quot; height=&quot;338&quot; frameborder=&quot;0&quot; webkitallowfullscreen=&quot;&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Crash</title>
   <link href="https://footle.org/2010/02/05/crash/"/>
   <updated>2010-02-05T02:16:32-08:00</updated>
   <id>https://footle.org/2010/02/05/crash</id>
   <content type="html">&lt;p&gt;
&lt;object type=&quot;application/x-shockwave-flash&quot; width=&quot;600&quot; height=&quot;338&quot; data=&quot;http://www.flickr.com/apps/video/stewart.swf?v=71377&quot; classid=&quot;clsid:D27CDB6E-AE6D-11cf-96B8-444553540000&quot;&gt; &lt;param name=&quot;flashvars&quot; value=&quot;intl_lang=en-us&amp;amp;photo_secret=9dfb00de2f&amp;amp;photo_id=4320733810&amp;amp;hd_default=false&quot; /&gt;&amp;lt;/param&amp;gt; &lt;param name=&quot;movie&quot; value=&quot;http://www.flickr.com/apps/video/stewart.swf?v=71377&quot; /&gt;&amp;lt;/param&amp;gt; &lt;param name=&quot;bgcolor&quot; value=&quot;#000000&quot; /&gt;&amp;lt;/param&amp;gt; &lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot; /&gt;&amp;lt;/param&amp;gt;&lt;embed type=&quot;application/x-shockwave-flash&quot; src=&quot;http://www.flickr.com/apps/video/stewart.swf?v=71377&quot; bgcolor=&quot;#000000&quot; allowfullscreen=&quot;true&quot; flashvars=&quot;intl_lang=en-us&amp;amp;photo_secret=9dfb00de2f&amp;amp;photo_id=4320733810&amp;amp;hd_default=false&quot; height=&quot;338&quot; width=&quot;600&quot; /&gt;&amp;lt;/embed&amp;gt;&lt;/object&gt;
&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Opera 10 Anchor Tag Rendering Bug</title>
   <link href="https://footle.org/2010/02/04/opera-10-anchor-tag-rendering-bug/"/>
   <updated>2010-02-04T14:59:05-08:00</updated>
   <id>https://footle.org/2010/02/04/opera-10-anchor-tag-rendering-bug</id>
   <content type="html">&lt;p&gt;For some time now, &lt;a href=&quot;http://wesabe.com&quot;&gt;Wesabe&lt;/a&gt;’s transaction edit dialog has been broken in &lt;a href=&quot;http://www.opera.com/&quot;&gt;Opera&lt;/a&gt; (10.10 as of this writing). Since it was fine in all other major browsers, and none of us were Opera users, fixing it was never high priority. I thought I’d take a look at it again tonight, though, and just when I was about to give up and go to bed, I managed to track it down.&lt;/p&gt;

&lt;p&gt;If you have an anchor (&lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt;) tag that contains &lt;a href=&quot;http://htmlhelp.com/reference/html40/block.html&quot;&gt;block-level elements&lt;/a&gt; (which is &lt;a href=&quot;http://www.w3.org/TR/html401/struct/links.html#edef-A&quot;&gt;technically not allowed&lt;/a&gt;, but all other browsers seem to be ok with it), such as &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;, the anchor will close itself before the elements it is supposed to contain. E.g.:
&lt;code&gt;
&amp;lt;a&amp;gt;
  &amp;lt;p&amp;gt;hello&amp;lt;/p&amp;gt;
&amp;lt;/a&amp;gt;
&lt;/code&gt;
Will render as:
&lt;code&gt;
&amp;lt;a&amp;gt; &amp;lt;/a&amp;gt;
&amp;lt;p&amp;gt;hello&amp;lt;/p&amp;gt;
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you give the anchor an href, though, even if it is just a blank string (&lt;code&gt;&amp;lt;a href=&quot;&quot;&amp;gt;...&lt;/code&gt;), it renders fine.&lt;/p&gt;

&lt;p&gt;Here’s a page that demonstrates the bug: &lt;a href=&quot;http://footle.org/misc/opera-bug.html&quot;&gt;http://footle.org/misc/opera-bug.html&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Anyway, I filed a bug with the Opera folks. Time for bed.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Better Dictionary: Wordnik</title>
   <link href="https://footle.org/2009/12/22/better-dictionary-wordnik/"/>
   <updated>2009-12-22T02:53:39-08:00</updated>
   <id>https://footle.org/2009/12/22/better-dictionary-wordnik</id>
   <content type="html">&lt;p&gt;Ok, thanks to Google for putting their &lt;a href=&quot;http://www.google.com/dictionary&quot;&gt;dictionary&lt;/a&gt; out there, which I wrote about &lt;a href=&quot;http://blog.footle.org/2009/12/04/google-dictionary-bookmarklet/&quot;&gt;a couple of posts ago&lt;/a&gt;, but the quality of the results pales in comparison to &lt;a href=&quot;http://www.wordnik.com&quot;&gt;Wordnik&lt;/a&gt;, which I’ve just discovered. It won’t do language translation for you, but as far as the English language is concerned, this is pure word porn. So here’s an updated bookmarklet for you:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;javascript:(function(){var%20s;if(window.getSelection){s=window.getSelection();}else%20if(document.selection){s=document.selection.createRange();}window.open(&apos;http://www.wordnik.com/words/&apos;+escape(s));}());&quot;&gt;wordnik&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Just drag that to your bookmarks bar, select a word or phrase on the page, and click. Happy bonus: just clicking on the bookmarklet without highlighting a word first will give you a random word (thanks to Wordnik, not me). Cool!&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Chrome Frame's Shifty User-Agent</title>
   <link href="https://footle.org/2009/12/15/chrome-frames-shifty-user-agent/"/>
   <updated>2009-12-15T06:49:48-08:00</updated>
   <id>https://footle.org/2009/12/15/chrome-frames-shifty-user-agent</id>
   <content type="html">&lt;p&gt;One of the security measures we have in place at Wesabe is to invalidate a session and log the user out if their User-Agent or IP address subnet changes between requests. However, we recently had a number of complaints that users were getting logged out prematurely. Looking at one user’s session in the logs, I noticed that their user agent string had “chromeframe/4.0” appended for some requests, but not others. It turns out that Google’s &lt;a href=&quot;http://code.google.com/chrome/chromeframe/&quot;&gt;Chrome Frame&lt;/a&gt; only &lt;a href=&quot;http://groups.google.com/group/google-chrome-frame/browse_thread/thread/274e4c36aebbc02b/&quot;&gt;modifies the user agent for top-level requests, and not for subsequent requests sent as that page loads&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;It was a compromise to keep code complexity down. In order to tag every request from IE...we have to have hooks in place at many more places (not to mention supporting the different things IE6, 7 and 8 do).  So, as a compromise we decided to keep it down to only the single hook that allows us to tag top level requests.&lt;/blockquote&gt;

&lt;p&gt;This fix on our side was to just strip the chromeframe identifier from the user agent string, although it makes me wonder what other browser extensions cause similar issues and whether invalidating a session when the user agent changes is even a worthwhile security measure.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Google Dictionary Bookmarklet</title>
   <link href="https://footle.org/2009/12/04/google-dictionary-bookmarklet/"/>
   <updated>2009-12-04T07:52:25-08:00</updated>
   <id>https://footle.org/2009/12/04/google-dictionary-bookmarklet</id>
   <content type="html">&lt;p&gt;Google recently launched a decent &lt;a href=&quot;http://www.google.com/dictionary&quot;&gt;dictionary&lt;/a&gt;, so for you logophiles, here’s a bookmarklet that will bring up the definition of whatever text you have selected on the page: &lt;a href=&quot;javascript:(function(){var%20s;if(window.getSelection){s=window.getSelection();}else%20if(document.selection){s=document.selection.createRange();}window.open(&apos;http://www.google.com/dictionary?aq=f&amp;amp;langpair=en|en&amp;amp;hl=en&amp;amp;q=&apos;+s);}());&quot;&gt;gDefine&lt;/a&gt;. Just drag it to your bookmarks toolbar, then double-click a word somewhere and click the button to get a definition.&lt;/p&gt;

&lt;p&gt;It is set to use the English dictionary, but if you want to use it in a different language (or even translate between languages), just change the &lt;code&gt;langpair&lt;/code&gt; parameter from &lt;code&gt;en|en&lt;/code&gt; to, say,&lt;code&gt; fr|fr&lt;/code&gt; for French, &lt;code&gt;de|de&lt;/code&gt; for German, etc. (try a search on the Google Dictionary site in the language you want and look to see what the &lt;code&gt;langpair&lt;/code&gt; parameter is in the url). Also, the &lt;code&gt;hl&lt;/code&gt; parameter controls the language of the results page, so if you want your results to be in that language as well (as opposed to English), change that accordingly.&lt;/p&gt;

&lt;p&gt;Here are a few to get you started:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;javascript:(function(){var%20s;if(window.getSelection){s=window.getSelection();}else%20if(document.selection){s=document.selection.createRange();}window.open(&apos;http://www.google.com/dictionary?aq=f&amp;amp;langpair=fr|fr&amp;amp;hl=fr&amp;amp;q=&apos;+s);}());&quot;&gt;gDefine (French)&lt;/a&gt;
&lt;a href=&quot;javascript:(function(){var%20s;if(window.getSelection){s=window.getSelection();}else%20if(document.selection){s=document.selection.createRange();}window.open(&apos;http://www.google.com/dictionary?aq=f&amp;amp;langpair=es|es&amp;amp;hl=es&amp;amp;q=&apos;+s);}());&quot;&gt;gDefine (Spanish)&lt;/a&gt;
&lt;a href=&quot;javascript:(function(){var%20s;if(window.getSelection){s=window.getSelection();}else%20if(document.selection){s=document.selection.createRange();}window.open(&apos;http://www.google.com/dictionary?aq=f&amp;amp;langpair=de|de&amp;amp;hl=de&amp;amp;q=&apos;+s);}());&quot;&gt;gDefine (German)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And translations:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;javascript:(function(){var%20s;if(window.getSelection){s=window.getSelection();}else%20if(document.selection){s=document.selection.createRange();}window.open(&apos;http://www.google.com/dictionary?aq=f&amp;amp;langpair=fr|en&amp;amp;hl=en&amp;amp;q=&apos;+s);}());&quot;&gt;gTranslate (French&amp;gt;English)&lt;/a&gt;
&lt;a href=&quot;javascript:(function(){var%20s;if(window.getSelection){s=window.getSelection();}else%20if(document.selection){s=document.selection.createRange();}window.open(&apos;http://www.google.com/dictionary?aq=f&amp;amp;langpair=en|fr&amp;amp;hl=en&amp;amp;q=&apos;+s);}());&quot;&gt;gTranslate (English&amp;gt;French)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Bill Cosby on Drums</title>
   <link href="https://footle.org/2009/11/12/bill-cosby-on-drums/"/>
   <updated>2009-11-12T03:45:50-08:00</updated>
   <id>https://footle.org/2009/11/12/bill-cosby-on-drums</id>
   <content type="html">&lt;div class=&quot;video-container&quot;&gt;
&lt;iframe width=&quot;600&quot; height=&quot;407&quot; src=&quot;http://www.youtube.com/embed/WScoPutUeiY?rel=0&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Wanted: 7 Fearless Engineers!</title>
   <link href="https://footle.org/2009/11/10/wanted-7-fearless-engineers-via-rich-coad/"/>
   <updated>2009-11-10T22:32:34-08:00</updated>
   <id>https://footle.org/2009/11/10/wanted-7-fearless-engineers-via-rich-coad</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;http://28.media.tumblr.com/tumblr_ksy8eaOOhW1qz6k71o1_500.jpg&quot; /&gt;&lt;/p&gt;

&lt;p&gt;(via Rich Coad)&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>CYOA</title>
   <link href="https://footle.org/2009/11/10/cyoa/"/>
   <updated>2009-11-10T14:16:20-08:00</updated>
   <id>https://footle.org/2009/11/10/cyoa</id>
   <content type="html">&lt;p&gt;Impressive analysis of Choose Your Own Adventure books, a fixture of my childhood.&lt;/p&gt;

</content>
 </entry>

 
 
 <entry>
   <title>Cell Size and Scale</title>
   <link href="https://footle.org/2009/10/29/cell-size-and-scale/"/>
   <updated>2009-10-29T06:49:54-07:00</updated>
   <id>https://footle.org/2009/10/29/cell-size-and-scale</id>
   <content type="html">
</content>
 </entry>

 
 
 <entry>
   <title>We Could Use More of This</title>
   <link href="https://footle.org/2009/10/28/we-could-use-more-of-this/"/>
   <updated>2009-10-28T14:39:00-07:00</updated>
   <id>https://footle.org/2009/10/28/we-could-use-more-of-this</id>
   <content type="html">&lt;p&gt;There&apos;s a weekly Tuesday evening Ultimate Frisbee game at a field near my house (sadly, I haven&apos;t gotten out to play in ages). Now that it&apos;s getting dark early, they need the lights on in order to play. The city is usually pretty stingy with the lights, but this just came through on the mailing list:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;So here&apos;s the deal with the lights for the lower field...The lady (I forget her name) wants us to help out with getting supplies for their cooking class: taco stuff, corn dogs and fries (maybe potatoes), chicken and rice, stuff like that to teach cooking with.  The reason is, the state is cutting back on funding and she asks us for donations of food to help out with the class.  In turn she said we could have the field and lights as long as we turn off the lights when we&apos;re done and if the soccer teams try to take over she will deal with them for us.  Not a bad deal, plus we&apos;re able to help the families and do a barter.&lt;/p&gt;
  
  &lt;p&gt;So: Bring food and play Tuesday night!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I love it.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>A literary appreciation of the Olson/Zoneinfo/tz database - Jon Udell</title>
   <link href="https://footle.org/2009/10/25/a-literary-appreciation-of-the-olsonzoneinfotz-database-c2-ab-jon-udell/"/>
   <updated>2009-10-25T02:13:34-07:00</updated>
   <id>https://footle.org/2009/10/25/a-literary-appreciation-of-the-olsonzoneinfotz-database-%c2%ab-jon-udell</id>
   <content type="html">
</content>
 </entry>

 
 
 <entry>
   <title>Bill Sosin | Siong Chin</title>
   <link href="https://footle.org/2009/09/30/bill-sosin-siong-chin/"/>
   <updated>2009-09-30T13:41:39-07:00</updated>
   <id>https://footle.org/2009/09/30/bill-sosin-siong-chin</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;http://27.media.tumblr.com/tumblr_kqtjpgxuY11qz6k71o1_500.jpg&quot; /&gt;&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>The Billion Dollar Gram | Information Is Beautiful</title>
   <link href="https://footle.org/2009/09/30/the-billion-dollar-gram-information-is-beautiful/"/>
   <updated>2009-09-30T13:40:28-07:00</updated>
   <id>https://footle.org/2009/09/30/the-billion-dollar-gram-information-is-beautiful</id>
   <content type="html">&lt;p&gt;Billions spent on this. Billions spent on that. It’s all relative, right?&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Muni platform, Embarcadero Station</title>
   <link href="https://footle.org/2009/08/12/muni-platform-embarcadero-station/"/>
   <updated>2009-08-12T03:16:00-07:00</updated>
   <id>https://footle.org/2009/08/12/muni-platform-embarcadero-station</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;http://30.media.tumblr.com/lktIWTwKHr1xgbj2AbDefby3o1_500.jpg&quot; /&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;p&amp;gt;Muni platform, Embarcadero Station&amp;lt;/p&amp;gt;&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>MySQL-Style Output for the Rails Console</title>
   <link href="https://footle.org/2009/03/01/mysql-style-output-for-the-rails-console/"/>
   <updated>2009-03-01T10:42:47-08:00</updated>
   <id>https://footle.org/2009/03/01/mysql-style-output-for-the-rails-console</id>
   <content type="html">&lt;p&gt;While poking around the database in my rails console, I often found myself jumping to the mysql console just so I could get an easier-to-digest view of the data. I finally had enough of this silliness and wrote up a quick function to dump of set of ActiveRecord objects in the mysql report format.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-irb&quot; data-lang=&quot;irb&quot;&gt;&lt;span class=&quot;go&quot;&gt;&amp;gt;&amp;gt; report(records, :id, :amount, :created_at)
+------+-----------+--------------------------------+
| id   | amount    | created_at                     |
+------+-----------+--------------------------------+
| 8301 | $12.40    | Sat Feb 28 09:20:47 -0800 2009 |
| 6060 | $39.62    | Sun Feb 15 14:45:38 -0800 2009 |
| 6061 | $167.52   | Sun Feb 15 14:45:38 -0800 2009 |
| 6067 | $12.00    | Sun Feb 15 14:45:40 -0800 2009 |
| 6059 | $1,000.00 | Sun Feb 15 14:45:38 -0800 2009 |
+------+-----------+--------------------------------+
5 rows in set&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;a href=&quot;http://gist.github.com/72234&quot;&gt;Grab it from GitHub&lt;/a&gt; and stick it in your &lt;code&gt;.irbrc&lt;/code&gt;.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Checking for STDIN in ruby</title>
   <link href="https://footle.org/2008/08/21/checking-for-stdin-inruby/"/>
   <updated>2008-08-21T10:24:06-07:00</updated>
   <id>https://footle.org/2008/08/21/checking-for-stdin-inruby</id>
   <content type="html">&lt;p&gt;A colleague was asking today how he could see if there’s data waiting on &lt;code&gt;STDIN&lt;/code&gt; in ruby (on Linux). On OS X, this is pretty straightforward:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;vg&quot;&gt;$stdin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;stat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;got something: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;STDIN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;nada&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;That doesn’t work in Linux, though. After some digging, I found &lt;a href=&quot;http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/186313&quot;&gt;this post&lt;/a&gt;, which lead to:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;fcntl&apos;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;flags&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;STDIN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fcntl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Fcntl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;F_GETFL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;flags&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Fcntl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;O_NONBLOCK&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;STDIN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fcntl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Fcntl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;F_SETFL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;begin&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;got something: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;STDIN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;rescue&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Errno&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EAGAIN&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;nada&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Which works on both platforms, but is (a) ugly (catching an exception), and (b) requires you to actually try to read from &lt;code&gt;STDIN&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In playing around with that, though, I noticed that &lt;code&gt;STDIN.fcntl(Fcntl::F_GETFL, 0)&lt;/code&gt; returned &lt;code&gt;0&lt;/code&gt; if there was something on &lt;code&gt;STDIN&lt;/code&gt;, and something non-zero (&lt;code&gt;2&lt;/code&gt; in OSX and &lt;code&gt;32770&lt;/code&gt; in Linux) if &lt;code&gt;STDIN&lt;/code&gt; was empty. So now the code is simple again:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;fcntl&apos;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;STDIN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fcntl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Fcntl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;F_GETFL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;got something: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;STDIN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;nada&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;I’m not sure how reliable that is on other platforms (it won’t work on Windows—fcntl is a Unix-y thing). If I’m understanding fcntl.h correctly, a return value of 2/32770 (0x8002) seems to indicate that the io stream in question is open for writing. I’m not sure if that is intended or just a side-effect. Anyone know?&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Leopard External Monitor Annoyance Solved...aka Hide All Apps on a Mac</title>
   <link href="https://footle.org/2008/03/21/leopard-external-monitor-annoyance-solvedaka-hide-all-apps-on-a-mac/"/>
   <updated>2008-03-21T11:20:40-07:00</updated>
   <id>https://footle.org/2008/03/21/leopard-external-monitor-annoyance-solvedaka-hide-all-apps-on-a-mac</id>
   <content type="html">&lt;p&gt;One of the more annoying things about Leopard is that when you plug in an external monitor that is set up to be your primary, your open applications don’t move over to the monitor. I was having to manually drag everything over. Then I realized that if I hid all my apps before plugging in the monitor, when I brought them up again, they’d be in the right place.&lt;/p&gt;

&lt;p&gt;So now the question was: is there an easy way to hide all your apps without cycling through them all? It took a bit of digging, but it turns out there is. Cmd-option-click on an app in the  Dock and it will hide all other apps. So I tried Cmd-option-click on the desktop itself and…voilà!&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Update:&lt;/b&gt; Technically, you’re Cmd-option-clicking on the Finder, so if you have any Finder windows open, they won’t hide. Bummer.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>ConditionsConstructor</title>
   <link href="https://footle.org/2008/02/27/conditionsconstructor/"/>
   <updated>2008-02-27T00:04:59-08:00</updated>
   <id>https://footle.org/2008/02/27/conditionsconstructor</id>
   <content type="html">&lt;p&gt;I hadn’t posted this before because it seemed kind of trivial and silly, but I used it again the other day and decided maybe I should share the joy after all.&lt;/p&gt;

&lt;p&gt;Far too often I find myself jumping through hoops building ActiveRecord &lt;code&gt;find&lt;/code&gt; conditions arrays dynamically depending on what arguments were passed in to the method. So I cooked up a simple little class to clean that up a bit:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# class to construct conditions for AR queries
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# cc = ConditionsConstructor.new(&apos;foobar &amp;amp;gt; ?&apos;, 7)
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# cc.add(&apos;blah is not null&apos;)
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# cc.add(&apos;baz in (?)&apos;, [1,2,3])
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# cc.conditions
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# # =&amp;gt; [&quot;foobar &amp;amp;gt; ? and blah is not null and baz in (?)&quot;, 7, [1, 2, 3]]
&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ConditionsConstructor&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@conditions_strs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@conditions_args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@conditions_strs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@conditions_args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;conditions&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@conditions_strs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos; and &apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@conditions_args&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

</content>
 </entry>

 
 
 <entry>
   <title>Tracking the 123 Meme</title>
   <link href="https://footle.org/2008/02/16/tracking-the-123-meme/"/>
   <updated>2008-02-16T04:06:24-08:00</updated>
   <id>https://footle.org/2008/02/16/tracking-the-123-meme</id>
   <content type="html">&lt;p&gt;I&apos;m pretty late to the party, but I just ran across this on &lt;a href=&quot;http://nothinghappens.net/?p=269&quot;&gt;Chuck Hoffman&apos;s blog&lt;/a&gt;: &quot;Grab the nearest book, open to page 123, go down to the 5th sentence, and type up the 3 following sentences.&quot;
&lt;/p&gt;

&lt;p&gt;Before I do that, I thought it would be interesting to try to track this meme back as far as possible. For the sake of my sanity, I&apos;m not following multiple paths from posts that link to more than one source--I&apos;ll just pick the link that seems to be the primary source. So here goes:
&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://nothinghappens.net/?p=269&quot;&gt;nothing happens&lt;/a&gt; linked to &lt;a href=&quot;http://www.cs.uni.edu/~wallingf/blog/archives/monthly/2008-02.html#e2008-02-15T16_48_28.htm&quot;&gt;Knowing and Doing&lt;/a&gt; linked to &lt;a href=&quot;http://www.exampler.com/blog/2008/02/12/a-tagging-meme-reveals-i-short-change-design/&quot;&gt;Exploration Through Example&lt;/a&gt; linked to &lt;a href=&quot;http://alex.halavais.net/the-bibliomancy-meme-redux/&quot;&gt;a thaumaturgical compendium&lt;/a&gt; linked to &lt;a href=&quot;123 Meme: Libraries, National Security, Freedom of Information Laws and Social Responsibilities&quot;&gt;michaelzimmer.org&lt;/a&gt; linked to &lt;a href=&quot;http://www.pogowasright.org/blogs/dissent/?p=821&quot;&gt;Chronicles of Dissent&lt;/a&gt; linked to &lt;a href=&quot;http://fergdawg.blogspot.com/2008/02/distraction-fergies-tech-blog-1-2-3.html&quot;&gt;Fergie&apos;s Tech Blog&lt;/a&gt; linked to &lt;a href=&quot;http://blog.wired.com/27bstroke6/2008/02/threat-level-1.html&quot;&gt;Threat Level&lt;/a&gt; linked to &lt;a href=&quot;http://blog.wired.com/defense/2008/02/danger-1-2-3.html&quot;&gt;Danger Room&lt;/a&gt; linked to &lt;a href=&quot;http://abumuqawama.blogspot.com/2008/02/1-2-3-meme-tag-were-it.html&quot;&gt;Abu Muqawama&lt;/a&gt; linked to &lt;a href=&quot;http://afghanistanica.com/2008/02/06/mountain-tourism-in-afghanistan-plus-123-meme/&quot;&gt;Afganistanica: Mountain Tourism in Afghanistan&lt;/a&gt; linked to &lt;a href=&quot;http://statefailure.blogspot.com/2008/02/123-meme.html&quot;&gt;[My] State Failure Blog&lt;/a&gt; linked to &lt;a href=&quot;http://kingsofwar.wordpress.com/2008/02/05/123-meme-via-mountain-runner/&quot;&gt;Kings of War&lt;/a&gt; linked to &lt;a href=&quot;http://mountainrunner.us/2008/02/123_meme_preemptive_version.html&quot;&gt;MountainRunner&lt;/a&gt; linked to &lt;a href=&quot;http://zenpundit.com/?p=2583&quot;&gt;zenpundit.com&lt;/a&gt; linked to &lt;a href=&quot;http://theglitteringeye.com/?p=3466&quot;&gt;the glittering eye&lt;/a&gt; who gave a bad link that I had to track down to &lt;a href=&quot;http://kevinsullivan.poligazette.com/?p=282&quot;&gt;Independent Liberal&lt;/a&gt; linked to &lt;a href=&quot;http://donklephant.com/2008/01/31/the-123-meme/&quot;&gt;Donklephant&lt;/a&gt; linked to &lt;a href=&quot;http://stubbornfacts.us/site_stuff/continuing_the_meme&quot;&gt;Stubborn Facts&lt;/a&gt; linked to &lt;a href=&quot;http://stubbornfacts.us/site_stuff/meme_time_1&quot;&gt;another post&lt;/a&gt; on the same blog, linked to &lt;a href=&quot;http://sidewaysmencken.blogspot.com/2008/01/meme-me.html&quot;&gt;Sideways Mencken&lt;/a&gt;, who did not link, but referenced &lt;a href=&quot;http://internetronin.blogspot.com/2008/01/im-it.html&quot;&gt;Internet Ronin&lt;/a&gt; linked to &lt;a href=&quot;http://ambivablog.typepad.com/ambivablog/2008/01/tagged-by-the-a.html&quot;&gt;AmbivaBlog&lt;/a&gt; [and now I&apos;m starting to tire of this game] linked to &lt;a href=&quot;http://theanchoressonline.com/2008/01/27/page-123-book-meme/&quot;&gt;The Anchoress&lt;/a&gt; linked [not directly, had to dig it up *sigh*] to &lt;a href=&quot;http://somehavehats.typepad.com/some_have_hats/2008/01/book-meme.html&quot;&gt;Some Have Hats&lt;/a&gt; linked to [again not directly...grr] &lt;a href=&quot;http://churchofthemasses.blogspot.com/2008/01/book-meme.html&quot;&gt;Church of the Masses&lt;/a&gt; linked [incorrectly] to &lt;a href=&quot;http://kathleenmiller.typepad.com/the_daily_grotto/2008/01/book-meme.html&quot;&gt;The Daily Grotto&lt;/a&gt; [warning! annoying chanting] linked to &lt;a href=&quot;http://aussiecoffeeshop.blogspot.com/2008/01/meme_24.html&quot;&gt;Aussie Coffee Shop&lt;/a&gt; linked to &lt;a href=&quot;http://michaelgabrielraphael.blogspot.com/2008/01/book-meme.html&quot;&gt;Where Angels Go&lt;/a&gt; which mentioned, but failed to link to the person who tagged them, so it&apos;s a dead end.&lt;/p&gt;

&lt;p&gt;Whew. This was getting a bit tedious. Not to mention that it seemed to have gotten firmly entrenched in religious/pro-life blogs, which were getting on my nerves.
&lt;/p&gt;

&lt;p&gt;Just as well. Turns out Google returns almost half a million hits for &lt;a href=&quot;http://www.google.com/search?hl=en&amp;amp;safe=off&amp;amp;q=%22page+123%22+sentence&quot;&gt;&quot;page 123&quot; sentence&lt;/a&gt;, and there doesn&apos;t seem to be a way to sort results by date (the daterange operator failed me completely). The oldest post I could find on &lt;a href=&quot;http://blogsearch.google.com/&quot;&gt;Google Blog search&lt;/a&gt; was &lt;a href=&quot;http://johnnycucumber.livejournal.com/2331.html&quot;&gt;this one&lt;/a&gt;, from November 24, 2004 (albeit for a slight variation on the meme--just the fifth sentence, not the three following it), but which clearly isn&apos;t the origin. Seems it was a meme floating around on LiveJournal around then. If anyone has better search-fu and can find an earlier post, let me know.
&lt;/p&gt;

&lt;p&gt;At this point, I&apos;ve made myself pretty sick of this meme. Often it appears to be a means by which people can brag about whatever erudite text they may or may not actually be reading. Even so, I can&apos;t have wasted this much time and not play along. I&apos;ve got two books nearly equidistant from my keyboard now. One is, at least in my field, too mundane to bother with: the &lt;a href=&quot;http://www.pragprog.com/titles/ruby&quot;&gt;Pickaxe book&lt;/a&gt;. The other sports the following 123/5/3 sentences:
&lt;/p&gt;

&lt;blockquote&gt;
The latissimus dorsi muscles have a major role in the deadlift: from the floor, the lat pulls back on the humerus to keep the arms from swinging forward away from the shins, and acts as an anchor on the upper part of the humerus to maintain the position of the bar directly under the shoulder blades until the bar crosses above the knees. The lats act in an essentially isometric way from the floor to the point where hip extension allows the arms to become vertical. At this point tension comes off the lats, and as the back becomes vertical, the arms drag the bar into the thighs as they assume an angle &lt;i&gt;behind&lt;/i&gt; the vertical, opposite the starting position.
&lt;/blockquote&gt;

&lt;p&gt;That&apos;s from &lt;a href=&quot;http://www.startingstrength.com/&quot;&gt;Starting Strength&lt;/a&gt; by Rippetoe and Kilgore, which is a great book for learning how to do basic barbell lifts correctly (something we do a fair bit of in &lt;a href=&quot;http://crossfitoakland.com/&quot;&gt;Crossfit&lt;/a&gt;). Coincidentally, that&apos;s just a couple pages past where I was actually reading about the deadlift. (Most interesting tidbit I&apos;ve learned so far from the book: the importance of a solid grip when doing the dealift. If your hands start slipping, &lt;a href=&quot;http://en.wikipedia.org/wiki/Proprioception&quot;&gt;proprioceptive&lt;/a&gt; (love that word) feedback tells the back that what you&apos;re trying to lift is too heavy, and it basically gives up.)
&lt;/p&gt;

&lt;p&gt;I&apos;m not going to inflict this on anyone else, but if you&apos;re reading this, feel free to prate on about whatever book you have near you.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Cheating for Fun</title>
   <link href="https://footle.org/2007/12/05/cheating-for-fun/"/>
   <updated>2007-12-05T01:16:58-08:00</updated>
   <id>https://footle.org/2007/12/05/cheating-for-fun</id>
   <content type="html">&lt;p&gt;I recently checked out the &lt;a href=&quot;http://www.facebook.com/applications/Scramble/6494671374&quot;&gt;Scramble&lt;/a&gt; application on Facebook, which is a knock-off of &lt;a href=&quot;http://en.wikipedia.org/wiki/Boggle&quot;&gt;Boggle&lt;/a&gt;. It’s a fun diversion, even though I usually get my ass kicked. There’s an annoying chat window there, too, and invariably someone will accuse someone else of cheating, at which point a number of people will pipe up with “how would you cheat?”&lt;/p&gt;

&lt;p&gt;This got me thinking…how &lt;em&gt;would&lt;/em&gt; you cheat? You’d just have to write a Scramble puzzle solver that spit out all the words in on the board. That sounded like a fun problem. I hadn’t done anything with &lt;a href=&quot;http://en.wikipedia.org/wiki/Recursion&quot;&gt;recursion&lt;/a&gt; in a while, so I gave it a go. Below is what I came up with. You’ll need a word list to run it. I originally used /usr/share/dict/words, but it was missing a lot of valid words (I think it only has base words, no plurals or tenses). So I stole the scrabble word list from the &lt;a href=&quot;http://packages.debian.org/unstable/games/scribble&quot;&gt;Debian scribble&lt;/a&gt; package, which worked much better.&lt;/p&gt;

&lt;p&gt;Anyway, here you go:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://gist.github.com/bgreenlee/8946388&quot;&gt;boggler.rb&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/files/words.gz&quot;&gt;words.gz&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I did try this out a couple times on Scramble and won handily. There’s really not much fun in that, though.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Note:&lt;/b&gt; This was really just an exercise in coming up with a fun algorithm, and is primarily intended for programmers. If you’re just looking to cheat at Boggle/Scramble, there are plenty of &lt;a href=&quot;http://www.l.google.com/search?q=cheat+boggle&quot;&gt;web sites that will help you with that&lt;/a&gt;, and with a lot less effort.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Lesser-Known MySQL Performance Tips</title>
   <link href="https://footle.org/2007/11/28/lesser-known-mysql-performance-tips/"/>
   <updated>2007-11-28T10:02:33-08:00</updated>
   <id>https://footle.org/2007/11/28/lesser-known-mysql-performance-tips</id>
   <content type="html">&lt;p&gt;&lt;div style=&quot;float:right;margin:0.5em 0.5em 0.5em 0.5em;&quot;&gt;&lt;a href=&quot;http://www.flickr.com/photos/talkrhubarb/223175100/&quot;&gt;&lt;img alt=&quot;dolphins by talkrhubarb&quot; src=&quot;http://farm1.static.flickr.com/80/223175100_a2e26fb461_m.jpg&quot; style=&quot;border:none !important&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;span style=&quot;font-size:75%;color:#999&quot;&gt;&quot;dolphins&quot; by &lt;a href=&quot;http://www.flickr.com/photos/talkrhubarb/&quot;&gt;talkrhubarb&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;
I thought I knew a fair bit about MySQL before I started working on &lt;a href=&quot;http://wesabe.com&quot;&gt;Wesabe&lt;/a&gt;, but I was wrong. Once your tables start to get really massive, all sorts of fun issues come out of the woodwork. There are a thousand articles out there on the basics of database optimization (use indices, &lt;a href=&quot;http://en.wikipedia.org/wiki/Denormalization&quot;&gt;denormalize&lt;/a&gt; when necessary, etc.), so I&apos;m not going to cover those again. Here are some tips--most specific to MySQL--that I&apos;ve learned on the job:&lt;/p&gt;

&lt;ul style=&quot;clear:right&quot;&gt;
	&lt;li&gt;MySQL only uses one index per table when doing a query, and the query optimizer doesn&apos;t always pick the best column, so indexing everything is not necessarily a great idea. If you&apos;re always selecting on a certain set of columns, create a single multi-column index&lt;/li&gt;

	&lt;li&gt;related to the above, don&apos;t put indices on columns with a low &lt;a href=&quot;http://en.wikipedia.org/wiki/Cardinality_(SQL_statements)&quot;&gt;cardinality&lt;/a&gt;. You can check the cardinality of a column by doing &lt;code&gt;SHOW INDEX FROM table_name&lt;/code&gt;&lt;/li&gt;

	&lt;li&gt;if any text or blob fields are part of your SELECT query, MySQL will write any temp tables to disk rather than memory. So where possible, use large VARCHAR fields (on 5.0.3 or higher) instead. See: &lt;a href=&quot;http://railspikes.com/2007/9/14/one-reason-why-MySQL-sucks&quot;&gt;http://railspikes.com/2007/9/14/one-reason-why-MySQL-sucks&lt;/a&gt;&lt;/li&gt;

	&lt;li&gt;if you need to do case-sensitive matching, declare your column as BINARY; don&apos;t use LIKE BINARY in your queries to cast a non-binary column. If you do, MySQL won&apos;t use any indexes on that column.&lt;/li&gt;

	&lt;li&gt;&lt;code&gt;SELECT ... LIMIT offset, limit&lt;/code&gt;, where offset is a large number == &lt;strong&gt;bad&lt;/strong&gt;, at least with InnoDB tables, as MySQL actually counts out every record until it gets to the offset. Ouch. Instead, assuming you have an auto-incremented id field, &lt;code&gt;SELECT * FROM foo WHERE id &amp;gt;= &lt;em&gt;offset&lt;/em&gt; AND id &amp;lt; &lt;em&gt;offset+limit&lt;/em&gt;&lt;/code&gt; (props to &lt;a href=&quot;http://blog.codahale.com/&quot;&gt;Coda&lt;/a&gt; for that one).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you have a query in which you&apos;re looking for the most recent &lt;i&gt;n&lt;/i&gt; items of something&amp;mdash;e.g. &lt;code&gt;SELECT * FROM foo WHERE bar = ? ORDER BY created_at DESC LIMIT 10&lt;/code&gt;)&amp;mdash;your query will be significantly faster if you create a multi-column index on whichever field(s) you&apos;re selecting on plus the timestamp field that you&apos;re ordering by (in this case, &lt;code&gt;CREATE INDEX idx_foo_bar_created_at ON foo (bar,created_at)&lt;/code&gt;). This allows MySQL to look up the records directly from the index, instead of pulling all the records where &lt;code&gt;bar = ?&lt;/code&gt;, sorting them (probably first writing them to a tempfile), and then taking the last 10. &lt;code&gt;EXPLAIN&lt;/code&gt; is your friend. If you&apos;re seeing &quot;Using temporary table, Using filesort&quot; in the &quot;extra&quot; section of EXPLAIN, that&apos;s bad.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I’ll add more as we come across them. If you have any other non-obvious tips, leave them in the comments or email me (brad@ this domain) and I’ll add them too.&lt;/p&gt;

&lt;p&gt;By the way, an invaluable book for learning how to squeeze the most out of MySQL is &lt;a href=&quot;http://www.amazon.com/High-Performance-MySQL-Jeremy-Zawodny/dp/0596003064/&quot;&gt;High Performance MySQL&lt;/a&gt;, by &lt;a href=&quot;http://jeremy.zawodny.com/blog/&quot;&gt;Jeremy Zawodny&lt;/a&gt; and &lt;a href=&quot;http://blog.megacity.org/&quot;&gt;Derek Balling&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Tumblr</title>
   <link href="https://footle.org/2007/11/05/tumblr/"/>
   <updated>2007-11-05T01:02:32-08:00</updated>
   <id>https://footle.org/2007/11/05/tumblr</id>
   <content type="html">&lt;p&gt;I decided to give &lt;a href=&quot;http://en.wikipedia.org/wiki/Tumblog&quot;&gt;tumblogging&lt;/a&gt; a &lt;a href=&quot;http://tumblr.footle.org&quot;&gt;try&lt;/a&gt;. I’m hoping that ease of use and lowered expectations will get me to post more often, and I’m liking it so far. It covers the large middle ground between blogging and &lt;a href=&quot;http://twitter.com/bgreenlee&quot;&gt;twittering&lt;/a&gt;. I can put up something interesting without feeling like I need to construct a coherent post around it, and I don’t feel like I’m pestering people with twitters (not to mention that it allows for richer media types).&lt;/p&gt;

&lt;p&gt;I realize I could just do the same thing on this blog if I wanted to, but there’s something about the minimalist formatting and ease-of-use that just seems to work. So I’ll continue to post longer pieces here (I’ve got a number that I need to just sit down and write), and I’ll keep posting inane comments to Twitter, but I imagine that the majority of interesting things I find will end up on my &lt;a href=&quot;http://tumblr.footle.org&quot;&gt;tumblelog&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Social Graphs Must Die</title>
   <link href="https://footle.org/2007/09/22/social-graphs-must-die/"/>
   <updated>2007-09-22T16:24:15-07:00</updated>
   <id>https://footle.org/2007/09/22/social-graphs-must-die</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;http://errtheblog.com/&quot;&gt;Chris Wanstrath&lt;/a&gt; made &lt;a href=&quot;http://twitter.com/defunkt/statuses/286921322&quot;&gt;a perfectly reasonable request&lt;/a&gt; earlier today, so I came up with the following &lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/748&quot;&gt;Greasemonkey&lt;/a&gt; script:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// ==UserScript==
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// @name           Social Graphs Must Die
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// @namespace      Footle
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// @description    Redact all mentions of &quot;social graphs&quot;;
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// ==/UserScript==
&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;innerHTML&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;innerHTML&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;social&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\s&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;+graph&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;?))&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/ig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;span style=&apos;background:#000;color:#000&apos;&amp;gt;$1&amp;lt;/span&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Actually closing a tab (that wasn’t opened by Javascript) in Firefox 2 isn’t possible AFAICT, but this is more fun anyway.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>I Get No Spam</title>
   <link href="https://footle.org/2007/08/14/i-get-no-spam/"/>
   <updated>2007-08-14T11:26:00-07:00</updated>
   <id>https://footle.org/2007/08/14/i-get-no-spam</id>
   <content type="html">&lt;p&gt;After hearing a &lt;a href=&quot;http://twitter.com/indirect/statuses/206360792&quot;&gt;couple&lt;/a&gt; &lt;a href=&quot;http://twitter.com/coda/statuses/206365502&quot;&gt;complaints&lt;/a&gt; from friends about the amount of spam they’re getting, I decided to take a quick look to see where I stood. At the risk of setting myself up, I should say that I get no spam (channeling &lt;a href=&quot;http://www.dvorak.org/blog/?p=2595&quot;&gt;John C. Dvorak&lt;/a&gt;). Or at least very little–maybe one every other day gets through to my inbox.&lt;/p&gt;

&lt;p&gt;I think the trick is just to have multiple levels of filtering. I use a Gmail address for most online transactions (for online transactions that I really don’t care about–if I’m doing a one-time registration just to get a trial key, for example–I use my Yahoo address, which is nothing but a spam bucket). My Gmail address gets forwarded to my personal email address (@footle.org), which has &lt;a href=&quot;http://spamassassin.apache.org/&quot;&gt;SpamAssassin&lt;/a&gt; running on the server. If it makes it past SA to Mail.app, it gets inspected by &lt;a href=&quot;http://c-command.com/spamsieve/&quot;&gt;SpamSieve&lt;/a&gt;, an awesome Bayesian spam filter for OS X mail clients.&lt;/p&gt;

&lt;p&gt;Anyway, my stats for the last 24 hours:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Server-level filters (spam caught):
    &lt;ul&gt;
      &lt;li&gt;SpamAssassin: 281&lt;/li&gt;
      &lt;li&gt;Gmail: 32&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Client-level filter (spam caught):
    &lt;ul&gt;
      &lt;li&gt;SpamSieve: 17&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Spam getting to my inbox: 0&lt;/li&gt;
  &lt;li&gt;Non-spam messages: 52&lt;/li&gt;
  &lt;li&gt;False positives: 1 (just &lt;a href=&quot;a href=&amp;quot;http://flavorpill.net/&quot;&gt;Flavorpill&lt;/a&gt;, so not a big deal)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(Wow…330 pieces of spam in a single day. That seems way worse than when I last checked.)&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Idea-That-I-Don't-Have-Time-To-Work-On of the Week</title>
   <link href="https://footle.org/2007/08/09/idea-that-i-dont-have-time-to-work-on-of-the-week/"/>
   <updated>2007-08-09T01:47:48-07:00</updated>
   <id>https://footle.org/2007/08/09/idea-that-i-dont-have-time-to-work-on-of-the-week</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;http://www.apple.com/macosx/features/bonjour/&quot;&gt;Bonjour&lt;/a&gt;-enabled &lt;a href=&quot;http://git.or.cz/&quot;&gt;Git&lt;/a&gt;. (Although &lt;a href=&quot;http://blog.codahale.com&quot;&gt;Coda&lt;/a&gt; tells me that Dave F. at &lt;a href=&quot;http://powerset.com&quot;&gt;Powerset&lt;/a&gt; already approached him with this idea. Neither of us have time to work on it.)&lt;/p&gt;

&lt;p&gt;I started using Git recently and although it’s a bit confounding at times, I love how cheap and easy branching is, and that you can commit incremental changes to your local repository, then later commit them in batch to subversion. Git allows for distributed development, but unless you’re on the same server as other developers, or you go through the trouble of mounting their repository over the network, you can’t check out their repository. Seems like it shouldn’t be too difficult to give Git Bonjour powers.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Update:&lt;/b&gt; Chad Fowler &lt;a href=&quot;http://github.com/chad/gitjour/tree/master&quot;&gt;has started such a project&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Binary multipart POSTs in Javascript</title>
   <link href="https://footle.org/2007/07/31/binary-multipart-posts-in-javascript/"/>
   <updated>2007-07-31T15:32:57-07:00</updated>
   <id>https://footle.org/2007/07/31/binary-multipart-posts-in-javascript</id>
   <content type="html">&lt;p&gt;We recently released a very slick &lt;a href=&quot;http://blog.wesabe.com/index.php/2007/07/25/the-wesabe-firefox-uploader/&quot;&gt;Firefox extension&lt;/a&gt; at &lt;a href=&quot;https://www.wesabe.com&quot;&gt;Wesabe&lt;/a&gt;. It was written by my colleague Tim Mason, but I helped figure out one small piece of it—namely, how to do binary multipart POSTs in Javascript—and since it involved many hours of hair-pulling for both of us, I thought I’d share the knowledge. (Tim says I should note that “this probably only works in Firefox version 2.0 and greater &lt;em&gt;and&lt;/em&gt; that it uses Mozilla specific calls that are only allowed for privileged javascript—basically only for extensions.”)&lt;/p&gt;

&lt;p&gt;One of the cool features of the plugin is the ability to take a &lt;a href=&quot;http://blog.wesabe.com/index.php/2007/07/25/one-more-thing-browser-snapshot-and-file-attachments/&quot;&gt;snapshot&lt;/a&gt; of a full browser page and either save the snapshot to disk or upload it to Wesabe (so you can, for example, save the receipt for a web purchase along with that transaction in your account). The snapshot is uploaded to Wesabe via a standard multipart POST, the same way that a file is uploaded via a web form.&lt;/p&gt;

&lt;p&gt;Tim was having trouble getting the POST to work with binary data at first, and he had other things to finish, so he wanted to just base-64-encode it and be done with it. I was reluctant to do that, as the size of the upload would be significantly larger (about &lt;a href=&quot;http://en.wikipedia.org/wiki/Base64&quot;&gt;137%&lt;/a&gt; of the original). Also, Rails didn’t automatically decode base-64-encoded file attachments. But Tim had other bugs to fix, so I submitted a &lt;a href=&quot;http://dev.rubyonrails.org/ticket/9016&quot;&gt;patch&lt;/a&gt; to Rails to do the base-64 decoding. I was pretty proud of this patch until it was pointed out to me that &lt;a href=&quot;http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.4.5&quot;&gt;RFC 2616&lt;/a&gt; specifically disallows the use of Content-Transfer-Encoding in HTTP. Doh. They also realized that it is a colossal waste of bandwidth.&lt;/p&gt;

&lt;p&gt;Since Tim was cramming to meet a hard(-ish) deadline set for the release of the plugin, I offered to lend my eyeballs to the binary post problem. This could be a very long story, but I’ll just get to the point: you can read binary data in to a Javascript string and dump it right out to a file just fine, but if you try to do any concatenation with that string, Javascript ends up munging it mercilessly. I’m not sure whether it is trying to interpret it as UTF8 or if it terminates it as soon as it hits a null byte (which is what seemed to be happening), but regardless, doing &lt;code&gt;&quot;some string&quot; + binaryData + &quot;another string&quot;&lt;/code&gt;, as is necessary when putting together a mutipart post, just does not work.&lt;/p&gt;

&lt;p&gt;The answer required employing Rube Goldbergian system of input and output streams. The seed of the solution was found on &lt;a href=&quot;http://developer.taboca.com/cases/en/XMLHTTPRequest_post_utf-8/&quot;&gt;this post&lt;/a&gt;, although that didn’t explain how to mix in all of the strings needed for the post and MIME envelope. So here it is, in all it’s goriness:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1223431.js&quot;&gt; &lt;/script&gt;

&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; Spaces removed from multipart boundary per Gijsbert’s suggestion in the comments (thanks!).&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Reloading Ruby Classes in Rails</title>
   <link href="https://footle.org/2007/05/13/reloading-ruby-classes-in-rails/"/>
   <updated>2007-05-13T12:58:54-07:00</updated>
   <id>https://footle.org/2007/05/13/reloading-ruby-classes-in-rails</id>
   <content type="html">&lt;p&gt;I ran across a bug in Date::Format today, and after spending a few hours hacking away at a fix (the date/format.rb code is &lt;em&gt;uuuuugly&lt;/em&gt; and &lt;em&gt;sloooow&lt;/em&gt;…someone should really rewrite that. Better yet, rewrite it in C), I thought I’d submit a patch. So I grabbed the &lt;a href=&quot;http://www.ruby-lang.org/en/community/ruby-core/&quot;&gt;ruby_1_8 branch&lt;/a&gt; and lo and behold, my issue had already been fixed!&lt;/p&gt;

&lt;p&gt;So the question now was how to monkeypatch the entire Date::Format module? Simply &lt;code&gt;require&lt;/code&gt;-ing it as a plugin doesn’t work, since Date::Format is already loaded at that point. The trick then is to use &lt;code&gt;load&lt;/code&gt; instead of require.&lt;/p&gt;

&lt;p&gt;First, I tried this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;load&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;date/format.rb&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;(note: load needs the actual filename; it doesn’t have the magic that require does) but that gave me an error:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-irb&quot; data-lang=&quot;irb&quot;&gt;&lt;span class=&quot;go&quot;&gt;in `load&apos;: wrong number of arguments (1 for 0) (ArgumentError)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Turns out Rails::Plugin::Loader defines its own &lt;code&gt;load&lt;/code&gt;, so:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;Kernel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;load&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;date/format.rb&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;et voila!&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Stop iPhoto from Launching when you Connect your Camera</title>
   <link href="https://footle.org/2007/05/13/stop-iphoto-from-launching-when-you-connect-your-camera/"/>
   <updated>2007-05-13T03:19:53-07:00</updated>
   <id>https://footle.org/2007/05/13/stop-iphoto-from-launching-when-you-connect-your-camera</id>
   <content type="html">&lt;p&gt;It took me a bit of digging to find this, so I thought I may as well spread the word here. I’ve started using Adobe Lightroom for managing my photos, but every time I connect my camera or card reader to import photos, iPhoto would launch, and I couldn’t figure out where I could change that. I finally discovered that the setting is in the Image Capture application. Run that, then go to Preferences and you’ll find it there. Why they wouldn’t also put it in iPhoto, Lightroom, or even on a preferences panel is beyond me.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Web 2.0 and Coming Soon...</title>
   <link href="https://footle.org/2007/04/17/web-20-and-coming-soon/"/>
   <updated>2007-04-17T23:49:02-07:00</updated>
   <id>https://footle.org/2007/04/17/web-20-and-coming-soon</id>
   <content type="html">&lt;p&gt;Marc and I presented our &lt;a href=&quot;http://www.web2expo.com/cs/webex2007/view/e_sess/11865&quot;&gt;Super Ninja Privacy Techniques for Web App Developers&lt;/a&gt; talk again yesterday at &lt;a href=&quot;http://www.web2expo.com/&quot;&gt;Web 2.0&lt;/a&gt; (we also did it at &lt;a href=&quot;http://conferences.oreillynet.com/etech/&quot;&gt;ETech&lt;/a&gt; last month), and it seemed well received. I still need to work on my presentation skills; I’m not an old hand at this like Marc is.&lt;/p&gt;

&lt;p&gt;I’m working on a follow-up to my &lt;a href=&quot;http://blog.footle.org/2007/02/22/protecting-your-users-data-with-a-privacy-wall/&quot;&gt;privacy wall&lt;/a&gt; post which will describe a much better way to go about keeping a user’s private data private, using an encrypted “Locker”. I’ll also go into detail about how we deal with password recovery.&lt;/p&gt;

&lt;p&gt;Hopefully by preannouncing this, I’ll force myself to get off my duff and finish the post. So stay tuned, and bug me if I don’t have it up soon.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Google Takes Steps Towards Greater Privacy</title>
   <link href="https://footle.org/2007/03/14/google-takes-steps-towards-greater-privacy/"/>
   <updated>2007-03-14T10:09:49-07:00</updated>
   <id>https://footle.org/2007/03/14/google-takes-steps-towards-greater-privacy</id>
   <content type="html">&lt;p&gt;Google &lt;a href=&quot;http://googleblog.blogspot.com/2007/03/taking-steps-to-further-improve-our.html&quot;&gt;recently announced&lt;/a&gt; that it will soon start anonymizing search logs older than 18-24 months. Full details can be found in their &lt;a href=&quot;http://216.239.57.110/blog_resources/google_log_retention_policy_faq.pdf&quot;&gt;Log Retention Policy FAQ (PDF)&lt;/a&gt;. This is a heartening step back towards their &lt;a href=&quot;http://en.wikipedia.org/wiki/Don&apos;t_Be_Evil&quot;&gt;“Don’t Be Evil”&lt;/a&gt; corporate philosophy, which some think has been largely &lt;a href=&quot;http://breitbart.com/article.php?id=D8FBCF686&amp;amp;show_article=1&quot;&gt;abandoned&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I’ve just recently started using &lt;a href=&quot;http://www.scroogle.org/&quot;&gt;Scroogle&lt;/a&gt; as a way of defeating their tracking of my every search (their site is awful; &lt;a href=&quot;http://en.wikipedia.org/wiki/Scroogle&quot;&gt;Wikipedia&lt;/a&gt; has more readable information about the project), although the motives of the man behind it, Daniel Brandt, who also runs the &lt;a href=&quot;http://www.google-watch.org/&quot;&gt;Google Watch&lt;/a&gt; site, &lt;a href=&quot;http://www.google-watch-watch.org/&quot;&gt;may be questionable&lt;/a&gt;. Still, he doesn’t have much incentive for keeping a log of queries and IP addresses, and if he did, since he’s not giving me a cookie, he can’t tie all my searches together.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Do Passwords Right With bcrypt-ruby</title>
   <link href="https://footle.org/2007/02/28/do-passwords-right-with-bcrypt-ruby/"/>
   <updated>2007-02-28T10:25:53-08:00</updated>
   <id>https://footle.org/2007/02/28/do-passwords-right-with-bcrypt-ruby</id>
   <content type="html">&lt;p&gt;My colleague Coda Hale just released a sweet &lt;a href=&quot;http://blog.codahale.com/2007/02/28/bcrypt-ruby-secure-password-hashing/&quot;&gt;bcrypt-ruby gem&lt;/a&gt; that does password hashing right. It also provides for future-proofing by enabling you to assign a computational cost for generating a password hash and letting you version your password hashes. You have no more excuses.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Protecting Your Users' Data with a Privacy Wall</title>
   <link href="https://footle.org/2007/02/22/protecting-your-users-data-with-a-privacy-wall/"/>
   <updated>2007-02-22T02:40:08-08:00</updated>
   <id>https://footle.org/2007/02/22/protecting-your-users-data-with-a-privacy-wall</id>
   <content type="html">&lt;p&gt;&lt;div style=&quot;float:right;margin:0.5em 0.5em 0.5em 0.5em;&quot;&gt;&lt;img alt=&quot;Just Another Brick In The Wall? by Iain Cuthbertson&quot; src=&quot;http://farm1.static.flickr.com/32/64441215_1e52c533a5_m.jpg&quot; /&gt;&lt;br /&gt;
&lt;span style=&quot;font-size:75%;color:#999&quot;&gt;Just Another Brick In The Wall?&lt;br /&gt;by &lt;a href=&quot;http://www.flickr.com/photos/bigcuthy/&quot;&gt;Iain Cuthbertson&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;

We deal with a lot of very private data at &lt;a href=&quot;http://www.wesabe.com&quot;&gt;Wesabe&lt;/a&gt;, so security and privacy are our top concerns. In this post I will describe one of our primary means for assuring privacy, a technique that is general enough that any site can use it.  Our creative name for this technique is the &lt;strong&gt;privacy wall&lt;/strong&gt;. Later, I&apos;ll go on to tell you ways to hack the wall, just so you don&apos;t get too comfortable.&lt;/p&gt;

&lt;h3&gt;The Privacy Wall&lt;/h3&gt;

&lt;p&gt;The idea is simple: don&apos;t have any direct links in your database between your users&apos; &quot;public&quot; data and their private data. Instead of linking tables directly via a foreign key, use a cryptographic hash &lt;a href=&quot;#footnote_1&quot;&gt;[1]&lt;/a&gt; that is based on at least one piece of data that only the user knows&amp;mdash;such as their password. The user&apos;s private data can be looked up when the user logs in, but otherwise it is completely anonymous. Let&apos;s go through a simple example.&lt;/p&gt;

&lt;p&gt;Let&apos;s say we&apos;re designing an application that lets members keep a list of their deepest, darkest secrets. We need a database with at least two tables: &apos;users&apos; and &apos;secrets&apos;. The first pass database model looks like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/images/standard-model.png&quot; alt=&quot;Standard Model&quot; height=&quot;111&quot; width=&quot;348&quot; /&gt;&lt;/p&gt;

&lt;p style=&quot;clear:both&quot;&gt;The problem with this schema is that anyone with access to the database can easily find out all the secrets of a given user. With one small change, however, we can make this extremely difficult, if not impossible:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/images/privacy-wall2.png&quot; alt=&quot;Privacy Wall&quot; height=&quot;111&quot; width=&quot;348&quot; /&gt;&lt;/p&gt;

&lt;p style=&quot;clear:both&quot;&gt;The special sauce is the &apos;secret_key&apos;, which is nothing more than a cryptographic hash of the user&apos;s username and their password &lt;a href=&quot;#footnote_2&quot;&gt;[2]&lt;/a&gt;. When the user logs in, we can generate the hash and store it in the session &lt;a href=&quot;#footnote_3&quot;&gt;[3]&lt;/a&gt;. Whenever we need to query the user&apos;s secrets, we use that key to look them up instead of the user id. Now, if some baddie gets ahold of the database, they will still be able to read everyone&apos;s secrets, but they won&apos;t know which secret belongs to which user, and there&apos;s no way to look up the secrets of a given user.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; A commenter on the Wesabe blog brought up the important point of what you do if the user forgets their password. The recovery method we came up with was to store a copy of their secret key, encrypted with the answers to their security questions (which aren&apos;t stored anywhere in our database, of course). Assuming that the user hasn&apos;t forgotten those as well, you can easily find their account data and &quot;move it over&quot; when they reset their password (don&apos;t forget to update the encrypted secret key); if they do forget them, well, there&apos;s a problem.&lt;/p&gt;

&lt;h3&gt;Attacking the Wall&lt;/h3&gt;

&lt;p&gt;I mentioned earlier that you store the secret key in the user&apos;s session. If you&apos;re storing your session data in the database and your db is hacked, any users that are logged in (or whose sessions haven&apos;t yet be deleted) can be compromised. The same is true if sessions are stored on the filesystem. Keeping session data in memory is better, although it is still hackable (the swapfile is one obvious target). However you&apos;re storing your session data, keeping your sessions reasonably short and deleting them when they expire is wise. You could also store the secret key separately in a cookie on the user&apos;s computer, although then you&apos;d better make damn sure you don&apos;t have any &lt;a href=&quot;http://en.wikipedia.org/wiki/XSS&quot;&gt;cross-site scripting (XSS)&lt;/a&gt; vulnerabilities that would allow a hacker to harvest your user&apos;s cookies.&lt;/p&gt;

&lt;p&gt;Other holes can be found if your system is sufficiently complex and an attacker can find a path from User to Secret through other tables in the database, so it&apos;s important to trace out those paths and make sure that the secret key is used somewhere in each chain.&lt;/p&gt;

&lt;p&gt;A harder problem to solve is when the secrets themselves may contain enough information to identify the user, and with the above scheme, if one secret is traced back to a user, all of that user&apos;s secrets are compromised. It might not be possible or practical to scrub or encrypt the data, but you can limit the damage of a secret being compromised. My colleague and security guru &lt;a href=&quot;http://www.emerose.com&quot;&gt;Sam Quiqley&lt;/a&gt; suggests the following as an extra layer of security: add a counter to the data being hashed to generate the secret key:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;secret key 1 = Hash(salt + password + &apos;1&apos;)
secret key 2 = Hash(salt + password + &apos;2&apos;)
...
secret key n = Hash(salt + password + &apos;&amp;amp;lt;n&amp;amp;gt;&apos;)&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Getting a list of all the secrets for a given user when they log in is going to be a lot less efficient, of course; you have to keep generating hashes and doing queries until no secret with that hash is found, and deleting secrets may require special handling. But it may be a small price to pay for the extra privacy.&lt;/p&gt;

&lt;p&gt;Finally, log files can be a gold mine for attackers. There&apos;s a very good chance you&apos;re logging queries, debug statements, or exception reports that link users to their keys or directly to their secrets. You should scrub any identifying information before it gets written to the log file.&lt;/p&gt;

&lt;h3&gt;So That&apos;s It, Right?&lt;/h3&gt;

&lt;p&gt;The privacy wall is far from a silver bullet. Privacy and security are hard&amp;mdash;really hard&amp;mdash;particularly so if your app is taking private data and extracting information out of it for public consumption, like we are at Wesabe. The privacy wall is one of a number of methods we&apos;re using to insure that our users&apos; private data stays that way. If you&apos;re lucky enough to be going to ETech next month, definitely check out &lt;a href=&quot;https://www.wesabe.com/page/founders#marc&quot;&gt;Marc&apos;s&lt;/a&gt; session on &lt;a href=&quot;http://conferences.oreillynet.com/cs/et2007/view/e_sess/10492&quot;&gt;Super Ninja Privacy Techniques for Web App Developers&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I hope you found this helpful. Let me know what you think; I appreciate any and all feedback. And if you&apos;ve got any cool privacy techniques up your sleeve, share the knowledge!&lt;/p&gt;

&lt;hr style=&quot;width:25%; margin-top: 2em&quot; /&gt;

&lt;p&gt;&lt;a name=&quot;footnote_1&quot;&gt;&lt;/a&gt;&amp;lt;p&amp;gt;[1] A cryptographic hash is way of mapping any amount of plain text to a fixed-length “fingerprint” such that the same text always maps to the same hash, and given a hash, it is impossible to generate the text from which it was derived. Hashes are wonderful things with many uses. If you’re a developer, and you didn’t already know this, stop reading now and go &lt;a href=&quot;http://en.wikipedia.org/wiki/Cryptographic_hash&quot;&gt;here&lt;/a&gt; or &lt;a href=&quot;http://www-128.ibm.com/developerworks/java/library/s-hashing/index.html&quot;&gt;here&lt;/a&gt;, and learn how to generate a SHA1/2 hash in your programming language of choice. Come back when you’re ready. I’ll wait.&amp;lt;/p&amp;gt;&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;footnote_2&quot;&gt;&lt;/a&gt;&amp;lt;p&amp;gt;[2] You can throw in a &lt;a href=&quot;http://en.wikipedia.org/wiki/Salt_%28cryptography%29&quot;&gt;salt&lt;/a&gt; too, to be safe; just make sure that you’re not using the same hash that you’re using for checking the user’s password. You &lt;em&gt;are&lt;/em&gt; smart enough not to &lt;a href=&quot;http://blog.moertel.com/articles/2006/12/15/never-store-passwords-in-a-database&quot;&gt;store passwords in plaintext in the database&lt;/a&gt;, aren’t you?&amp;lt;/p&amp;gt;&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;footnote_3&quot;&gt;&lt;/a&gt;&amp;lt;p&amp;gt;[3] Danger, Will Robinson! Keep reading.&amp;lt;/p&amp;gt;&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Campfire Hacks: Uploading Screenshots with Quicksilver and Pyro</title>
   <link href="https://footle.org/2007/02/04/campfire-hacks-uploading-screenshots-with-quicksilver-and-pyro/"/>
   <updated>2007-02-04T06:39:02-08:00</updated>
   <id>https://footle.org/2007/02/04/campfire-hacks-uploading-screenshots-with-quicksilver-and-pyro</id>
   <content type="html">&lt;p&gt;We live in &lt;a href=&quot;http://campfirenow.com/&quot;&gt;Campfire&lt;/a&gt; at &lt;a href=&quot;http://www.wesabe.com&quot;&gt;Wesabe&lt;/a&gt;, so naturally we&apos;ve developed a number of tools and hacks around it. One of these days I&apos;ll get around to writing about the Campfire bot framework we&apos;ve developed, but right now I&apos;ll start with something simpler: a way to upload screenshots to Campfire with only a few keystrokes (riffing of my colleague &lt;a href=&quot;http://blog.codahale.com&quot;&gt;Coda Hale&lt;/a&gt;&apos;s &lt;a href=&quot;http://blog.codahale.com/2007/01/22/send-as-im-adium-quicksilver/&quot;&gt;desire to eliminate&lt;/a&gt; &lt;a href=&quot;http://blog.codahale.com/2007/01/15/tweet-twitter-quicksilver/&quot;&gt;the need for a mouse&lt;/a&gt;). Note that this is for Mac users only, so if you&apos;re one of the poor souls who hasn&apos;t seen the light yet, you can stop reading now.&lt;/p&gt;

&lt;p&gt;Two prerequisites (other than a Mac): &lt;a href=&quot;http://quicksilver.blacktree.com/&quot;&gt;Quicksilver&lt;/a&gt; and &lt;a href=&quot;http://www.karppinen.fi/pyro/&quot;&gt;Pyro&lt;/a&gt;. Quicksilver should be familiar to most Mac users already. It is an incredibly powerful application that can be quite obtuse but can save you gobs of time if you learn how to use it. Pyro is a client for Campfire. Why do you need a client for a browser-based chat app? Getting message notifications in your dock is one reason, but the biggest reason is that there seems to be a memory leak in Firefox that causes it to grind to a halt if you&apos;ve had Campfire up for too long. But I digress.&lt;/p&gt;

&lt;p&gt;You first need to enable the Screen Capture Actions plugin in Quicksilver (go to Plugins -&amp;gt; Recommended, and check Screen Capture Actions). Then to go Catalog -&amp;gt; Quicksilver and make sure that Internal Commands is checked). This should give you Capture Region, Window, and Screen commands.&lt;/p&gt;

&lt;p&gt;Next, the secret sauce: a bit of AppleScript that uploads a file to Campfire via Pyro:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-applescript&quot; data-lang=&quot;applescript&quot;&gt;&lt;span class=&quot;k&quot;&gt;on&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;theFile&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;tell&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;application&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Pyro&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;upload&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;theFile&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;room&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;[your campfire room name]&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;campfire&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;[your campfire].campfirenow.com&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;tell&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;Paste that into Script Editor and save it as &lt;code&gt;PyroUpload&lt;/code&gt; in &lt;code&gt;~/Library/Application Support/Quicksilver/Actions&lt;/code&gt; (if this folder doesn&apos;t exist, create it), and restart Quicksilver.&lt;br /&gt;&lt;br /&gt;Now you can upload a screenshot with just Cmd - Space - [Capture Window|Region|Screen] - Return - [take your screenshot] - PY - Return.&lt;/p&gt;

&lt;p&gt;Have fun!&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Must...stop...looking at...stats...</title>
   <link href="https://footle.org/2006/11/17/muststoplooking-atstats/"/>
   <updated>2006-11-17T15:19:12-08:00</updated>
   <id>https://footle.org/2006/11/17/muststoplooking-atstats</id>
   <content type="html">&lt;p&gt;I’ve been too tired today to do any actual work, so I’ve spent much of the day camping out on the &lt;a href=&quot;http://www.wesabe.com&quot;&gt;Wesabe&lt;/a&gt; site stats. It’s terribly exciting having so many people hitting your site and so many signing up (almost 1/3 of our unique visitors have created accounts). The site has been humming along beautifully, too–major props goes out my colleague &lt;a href=&quot;http://blog.codahale.com/&quot;&gt;Coda Hale&lt;/a&gt; for his Apache/Mongrel/Pen prowess.&lt;/p&gt;

&lt;p&gt;Anyway, I just wanted to share one of the more interesting stats from our analytics (&lt;a href=&quot;http://www.haveamint.com/&quot;&gt;Mint&lt;/a&gt;–very tasty):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/images/go_firefox.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;That’s a lovely thing to see. Granted, these are largely very tech-savvy, early-adopter people at this stage, but it’s heartening to see IE getting the beatdown.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Wesabe Launches</title>
   <link href="https://footle.org/2006/11/16/wesabe-launches/"/>
   <updated>2006-11-16T17:41:09-08:00</updated>
   <id>https://footle.org/2006/11/16/wesabe-launches</id>
   <content type="html">&lt;p&gt;The reason I’ve had my head in the sand for the last six months is that I’ve been working on a new startup, and we’ve finally launched publicly. &lt;a href=&quot;http://www.wesabe.com&quot;&gt;Check us out.&lt;/a&gt; Here’s a screencast demo of the service:&lt;/p&gt;
&lt;div&gt;
&lt;object width=&quot;425&quot; height=&quot;350&quot;&gt; &lt;param name=&quot;movie&quot; value=&quot;http://www.youtube.com/v/UK_Kv_-GvVc&quot; /&gt; &amp;lt;/param&amp;gt; &lt;embed src=&quot;http://www.youtube.com/v/UK_Kv_-GvVc&quot; type=&quot;application/x-shockwave-flash&quot; width=&quot;425&quot; height=&quot;350&quot; /&gt; &amp;lt;/embed&amp;gt; &lt;/object&gt;
&lt;/div&gt;

&lt;p&gt;Let me know what you think. (Or better yet, send your thoughts to &lt;a href=&quot;support@wesabe.com&quot;&gt;support@wesabe.com&lt;/a&gt;.)&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Still here</title>
   <link href="https://footle.org/2006/07/22/still-here/"/>
   <updated>2006-07-22T17:25:50-07:00</updated>
   <id>https://footle.org/2006/07/22/still-here</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/bgreenlee/sets/72157594149140755/&quot;&gt;&lt;img src=&quot;http://static.flickr.com/68/155965360_8f8d710dc5_m.jpg&quot; style=&quot;border: 1px solid #333; float: right&quot; /&gt;&lt;/a&gt; &amp;lt;p&amp;gt;No, I haven’t abandoned this site. I’ve just been working my butt off at a new startup. I’ll try to get some content up soon, but in the meantime, enjoy some pictures of the &lt;a href=&quot;http://www.flickr.com/photos/bgreenlee/sets/72157594149140755/&quot;&gt;newest member of our family&lt;/a&gt;. &amp;lt;/p&amp;gt;
&lt;br clear=&quot;both&quot; /&gt;&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Productivity in Java vs. Rails</title>
   <link href="https://footle.org/2006/05/31/productivity-in-java-vs-rails/"/>
   <updated>2006-05-31T03:57:35-07:00</updated>
   <id>https://footle.org/2006/05/31/productivity-in-java-vs-rails</id>
   <content type="html">&lt;p&gt;I am far more productive when writing Rails code than when writing Java. I just realized that one of the reasons for my lower productivity in Java is the need to recompile every time a make a change to a page on the site. In the 15 seconds or so it takes to recompile and redeploy to Tomcat, I get bored and am apt to go check my new favorite news site, &lt;a href=&quot;http://popurls.com&quot;&gt;popurls&lt;/a&gt;, or my RSS feeds, or (less likely) post to my blog. Suddenly those 15 seconds have become 5 minutes. And this happens many times throughout the day.&lt;br /&gt;&lt;br /&gt;With Rails, I make a change, refresh my browser, and there it is. On to the next step.&lt;br /&gt;&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>HTTP Authorization with Apache/FastCGI</title>
   <link href="https://footle.org/2006/05/24/http-authorization-with-apachefastcgi/"/>
   <updated>2006-05-24T10:56:12-07:00</updated>
   <id>https://footle.org/2006/05/24/http-authorization-with-apachefastcgi</id>
   <content type="html">&lt;p&gt;It took me forever to figure this one out, but if you want HTTP Authentication to work with Apache 2 and mod_fastcgi, you need this in your apache conf file:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;FastCgiConfig -pass-header Authorization
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;FastCGI doesn’t pass the Authorization header by default for some reason.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Processes, Threads, and Ruby</title>
   <link href="https://footle.org/2006/05/23/processes-threads-and-ruby/"/>
   <updated>2006-05-23T06:50:40-07:00</updated>
   <id>https://footle.org/2006/05/23/processes-threads-and-ruby</id>
   <content type="html">&lt;p&gt;While researching the best way to handle calling an external program from Ruby (and capturing stdout &amp;amp; stderr), I came across this post, which is a good review of how processes and threads work:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.ruby-forum.com/topic/65155#75363&quot;&gt;http://www.ruby-forum.com/topic/65155#75363&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I still haven’t figured out exactly how I’m going to do this, but I’ll post it here when I figure it out. Ruby has a few different ways of opening and communicating with processes, but all seem to be lacking in some way or another. IO.popen lets you write to the process’ stdin, and read from its stdout, but you can’t get stderr without jumping through serious hoops (like redirecting stderr to a file and then reading the file…ugh). Open3.popen3 (brilliant naming) gives you stdin, stdout, and stderr, but the subprocess runs as a grandchild, so there seems to be no way to wait for it to finish.&lt;/p&gt;

</content>
 </entry>

 
 
 <entry>
   <title>Database War Stories</title>
   <link href="https://footle.org/2006/04/30/database-war-stories/"/>
   <updated>2006-04-30T01:46:58-07:00</updated>
   <id>https://footle.org/2006/04/30/database-war-stories</id>
   <content type="html">&lt;p&gt;There’s an interesting series of posts over at &lt;a href=&quot;http://radar.oreilly.com/&quot;&gt;O’Reilly Radar&lt;/a&gt;. Tim O’Reilly asked people how they were using databases in their “Web 2.0” applications (although I think the Web 2.0 part of it is for the most part irrelevant). The responses so far have made for interesting reading. So far we’ve heard from &lt;a href=&quot;http://radar.oreilly.com/archives/2006/04/web_20_and_databases_part_1_se.html&quot;&gt;Second Life&lt;/a&gt;, &lt;a href=&quot;http://radar.oreilly.com/archives/2006/04/database_war_stories_2_bloglin.html&quot;&gt;Bloglines and Memeorandum&lt;/a&gt;, &lt;a href=&quot;http://radar.oreilly.com/archives/2006/04/database_war_stories_3_flickr.html&quot;&gt;Flickr&lt;/a&gt;, &lt;a href=&quot;http://radar.oreilly.com/archives/2006/04/database_war_stories_4_nasa_wo.html&quot;&gt;NASA World Wind&lt;/a&gt;, and &lt;a href=&quot;http://radar.oreilly.com/archives/2006/04/database_war_stories_5_craigsl.html&quot;&gt;craigslist&lt;/a&gt;. One of the lessons learned is that with a high-traffic site, at some point you have to break your database up so that the “hot” data is spread across a number of boxes. This got me thinking. It should be possible to build a tool that analyzes your database usage and, given a number of slave boxes to configure as it sees fit, automatically configures masters and slaves and distributes your data across those boxes as necessary. This would not be a one-time only process either; it would continue to monitor usage and performance and adjust accordingly. Certainly not an easy task, but should be doable.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Bad UI in iTunes</title>
   <link href="https://footle.org/2006/04/25/bad-ui-in-itunes/"/>
   <updated>2006-04-25T08:58:27-07:00</updated>
   <id>https://footle.org/2006/04/25/bad-ui-in-itunes</id>
   <content type="html">&lt;p&gt;I use iTunes both on a Mac and Windows. In OS X, Command-H hides an app, something I do so often I just do it without thinking. However, in iTunes on Windows, Control-H (aka backspace) deletes whatever object you’re on, with no undo. I just deleted a playlist I had spent a long time working on and I see no way to get it back.&lt;/p&gt;

&lt;p&gt;Why don’t I at least have the option to undo? Terrible UI.  Surprising that Apple of all companies made such a basic mistake.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Amazon's new S3 Storage Service</title>
   <link href="https://footle.org/2006/03/15/amazons-new-s3-storage-service/"/>
   <updated>2006-03-15T03:10:05-08:00</updated>
   <id>https://footle.org/2006/03/15/amazons-new-s3-storage-service</id>
   <content type="html">&lt;p&gt;Amazon just launched a new service, &lt;a href=&quot;http://www.amazon.com/gp/browse.html/104-8936730-9867911?node=16427261&quot;&gt;S3 - Simple Storage Service&lt;/a&gt;. It is a web service that allows you to store as much data as you like, with file sizes up to 5GB, and you just pay for the storage you use and the data transferred. Rates are very reasonable, too – $0.15/GB/month of storage, and $0.20/GB in data transferred.&lt;br /&gt;&lt;br /&gt;This is pretty interesting. It gives developers the ability to create applications requiring significant storage space without having to make a huge upfront investment in equipment and expertise. Want to write your own Flickr? Go for it. Granted, it’s risky relying on a third party for a core part of your business, but you only need them until you get your million users and can get enough funding to build your own storage backend.&lt;br /&gt;&lt;br /&gt;Google is apparently working on their own storage backend, Google Drive. It will be interesting to see how this plays out. Nothing but good news for aspiring entrepreneurs, though.&lt;br /&gt;&lt;br /&gt;via &lt;a href=&quot;http://www.techcrunch.com/2006/03/14/amazon-grid-storage-web-service-launches/&quot;&gt;TechCrunch&lt;/a&gt;&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Multi-Touch Touch Screen</title>
   <link href="https://footle.org/2006/02/27/multi-touch-interaction-research/"/>
   <updated>2006-02-27T02:45:23-08:00</updated>
   <id>https://footle.org/2006/02/27/multi-touch-interaction-research</id>
   <content type="html">&lt;p&gt;One of the most exciting new technologies I’ve seen in a long time: a &lt;a href=&quot;http://mrl.nyu.edu/%7Ejhan/ftirtouch/index.html&quot;&gt;multi-touch touch screen&lt;/a&gt;. The video says it all.&lt;/p&gt;

&lt;div&gt;
&lt;object height=&quot;350&quot; width=&quot;425&quot;&gt;
&lt;param name=&quot;movie&quot; value=&quot;http://www.youtube.com/v/zp-y3ZNaCqs&quot; /&gt;&lt;embed src=&quot;http://www.youtube.com/v/zp-y3ZNaCqs&quot; type=&quot;application/x-shockwave-flash&quot; height=&quot;350&quot; width=&quot;425&quot; /&gt;&amp;lt;/embed&amp;gt;&amp;lt;/param&amp;gt;&lt;/object&gt;
&lt;/div&gt;
</content>
 </entry>

 
 
 <entry>
   <title>            Your next ISP: Google</title>
   <link href="https://footle.org/2006/02/08/your-next-isp-google/"/>
   <updated>2006-02-08T10:13:10-08:00</updated>
   <id>https://footle.org/2006/02/08/your-next-isp-google</id>
   <content type="html">&lt;p&gt;John C. Dvorak has a &lt;a href=&quot;http://www.pcmag.com/article2/0,1895,1916760,00.asp&quot;&gt;good piece&lt;/a&gt; at pcmag.com about speculations that Google is going to be creating their own network (see the “Google is the Internet” scenario from the &lt;a href=&quot;http://money.cnn.com/magazines/business2/business2_archive/2006/01/01/8368125/index.htm&quot;&gt;article linked in my previous post&lt;/a&gt;). I certainly hope they do, as telcos have been &lt;a href=&quot;http://muniwireless.com/community/1023&quot;&gt;dragging their feet&lt;/a&gt; on broadband for a long time, and &lt;a href=&quot;http://www.usatoday.com/tech/news/2005-01-03-fiber-cover_x.htm&quot;&gt;acting like the Mafia&lt;/a&gt; whenever someone encroaches on “their” territory.&lt;/p&gt;

&lt;p&gt;More articles on the subject:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href=&quot;http://business.timesonline.co.uk/article/0,,9075-2023600,00.html&quot;&gt;Rumours mount over Google&apos;s internet plan&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&quot;http://www.networkingpipeline.com/blog/archives/2006/02/google_to_telco.html&quot;&gt;Google to Telcos: Who Needs You?&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>

 
 
 <entry>
   <title>            Imagining the Google Future</title>
   <link href="https://footle.org/2006/02/02/imagining-the-google-future/"/>
   <updated>2006-02-02T03:54:11-08:00</updated>
   <id>https://footle.org/2006/02/02/imagining-the-google-future</id>
   <content type="html">&lt;p&gt;Great article from Business 2.0 describing four future scenarios for Google:&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://money.cnn.com/magazines/business2/business2_archive/2006/01/01/8368125/index.htm&quot;&gt;Imagining the Google Future&lt;/a&gt;&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>RIP IM Smarter</title>
   <link href="https://footle.org/2006/01/30/rip-im-smarter/"/>
   <updated>2006-01-30T02:16:55-08:00</updated>
   <id>https://footle.org/2006/01/30/rip-im-smarter</id>
   <content type="html">&lt;p&gt;My &lt;a href=&quot;http://www.imsmarter.com&quot;&gt;imsmarter&lt;/a&gt; proxy stopped working last week, and I just got around to going to their site to see what was up. Looks like they’ve shut down. A bit of a pity; I thought it was a useful service. I use IM on four different machines and it made finding something from a past conversation a lot easier. Actually, though, what I used most often was its reminder feature. I could send it an IM saying “Remind me in 2 hours to check the car” and it would do just that, saving me many parking tickets. I imagine there are other services like that out there; I should check around. Actually, that would be a pretty trival thing to implement myself. Hmmm.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>            Your Dwindling Privacy</title>
   <link href="https://footle.org/2006/01/09/your-dwindling-privacy/"/>
   <updated>2006-01-09T04:47:50-08:00</updated>
   <id>https://footle.org/2006/01/09/your-dwindling-privacy</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;http://www.suntimes.com/output/news/cst-nws-privacy05.html&quot;&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;Your phone records are for sale&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;“The Chicago Police Department is warning officers their cell phone records are available to anyone – for a price. Dozens of online services are selling lists of cell phone calls, raising security concerns among law enforcement and privacy experts.”&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.applefritter.com/bannedbooks&quot;&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;Data Mining 101: Finding Subversives with Amazon Wishlists&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;Although this raises some serious privacy concerns, what I found more interesting about this article was how relatively easy it is now to take data from all kinds of publicly available sources and use them to produce something like a map showing the locations of all the readers (or in this case, desire-ers) of a particular book.&lt;br /&gt;&lt;br /&gt;(Both of these links via &lt;a href=&quot;http://www.schneier.com/blog/&quot;&gt;Bruce Schneier’s Blog&lt;/a&gt;.)&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Business Blogging</title>
   <link href="https://footle.org/2006/01/01/business-blogging/"/>
   <updated>2006-01-01T01:53:37-08:00</updated>
   <id>https://footle.org/2006/01/01/business-blogging</id>
   <content type="html">&lt;p&gt;Chris Anderson of &lt;a href=&quot;http://www.wired.com&quot;&gt;Wired&lt;/a&gt; / &lt;a href=&quot;http://www.thelongtail.com&quot;&gt;The Long Tail&lt;/a&gt; has started a wiki page to track &lt;a href=&quot;http://www.thelongtail.com/the_long_tail/2005/12/announcing_the_.html&quot;&gt;public blogs by Fortune 500 companies&lt;/a&gt;. The list isn’t terribly long yet, but I’m sure it will be growing, both as more people discover existing company blogs and as more companies jump on the bandwagon.&lt;/p&gt;

&lt;p&gt;Speaking of which, we’ve jumped on the bandwagon ourselves at &lt;a href=&quot;http://www.triporama.com&quot;&gt;Triporama&lt;/a&gt;. The &lt;a href=&quot;http://www.triporama.com/blog&quot;&gt;Triporama Blog&lt;/a&gt; isn’t yet linked in from the main site (it will be soon), but Wendell has already posted a great piece about the origins of Triporama.&lt;/p&gt;

&lt;p&gt;Happy New Year!&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>New Photos</title>
   <link href="https://footle.org/2005/12/17/new-photos/"/>
   <updated>2005-12-17T11:19:08-08:00</updated>
   <id>https://footle.org/2005/12/17/new-photos</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;http://flickr.com/photos/bgreenlee&quot;&gt;&lt;img src=&quot;http://static.flickr.com/9/69696604_deeae41fa2_m.jpg&quot; style=&quot;float: left; margin: 0 10px 10px 0; border: 1px solid black;&quot; /&gt;&lt;/a&gt;Bunch of new photos on up on &lt;a href=&quot;http://flickr.com/photos/bgreenlee&quot;&gt;Flickr&lt;/a&gt;, btw.&lt;/p&gt;
&lt;p&gt;&lt;br style=&quot;clear: both&quot; /&gt;&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Triporama Launches</title>
   <link href="https://footle.org/2005/12/15/triporama-launches/"/>
   <updated>2005-12-15T04:02:29-08:00</updated>
   <id>https://footle.org/2005/12/15/triporama-launches</id>
   <content type="html">&lt;p&gt;I’ve been pretty busy lately, if the infrequency of my posts is any indicator, but it’s paid off: &lt;a href=&quot;http://www.triporama.com&quot;&gt;Triporama&lt;/a&gt; officially launched yesterday. We sent out some 300 emails and then immediately left to go to the bar. Fortunately, the site held up, with only one serious bug so far, which I fixed last night.&lt;/p&gt;

&lt;p&gt;Not that I can slack off now…we’ve got a mile-long list of features we’d like to implement. It’s great to finally get it out there, though.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Interesting Links</title>
   <link href="https://footle.org/2005/12/15/interesting-links/"/>
   <updated>2005-12-15T02:40:42-08:00</updated>
   <id>https://footle.org/2005/12/15/interesting-links</id>
   <content type="html">&lt;p&gt;This:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.articledashboard.com/Article/Top-10-Innovative-Web-2-0-Applications-of-2005/10891&quot;&gt;Top 10 Innovative Web 2.0 Applications of 2005&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;led me to this:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.tagcloud.com/&quot;&gt;TagCloud&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;which let me to this:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://developer.yahoo.net/search/content/V1/termExtraction.html&quot;&gt;Term Extraction Documentation for Yahoo! Search Web Services&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now to just figure out some cool things to do with it.&lt;/p&gt;

</content>
 </entry>

 
 
 <entry>
   <title>Good Reading</title>
   <link href="https://footle.org/2005/11/23/good-reading/"/>
   <updated>2005-11-23T01:59:01-08:00</updated>
   <id>https://footle.org/2005/11/23/good-reading</id>
   <content type="html">&lt;p&gt;Clay Shirky has a great piece about ontologies, categorization, and how they don’t really make sense for most of the Web today: &lt;strong&gt;&lt;a href=&quot;http://www.shirky.com/writings/ontology_overrated.html&quot;&gt;Ontology is Overrated&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Paul Graham’s new essay tries to make some sense of everyone’s favorite buzzword: &lt;strong&gt;&lt;a href=&quot;http://paulgraham.com/web20.html&quot;&gt;Web 2.0&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Happy Thanksgiving!&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Utter Insanity</title>
   <link href="https://footle.org/2005/11/02/utter-insanity/"/>
   <updated>2005-11-02T04:02:40-08:00</updated>
   <id>https://footle.org/2005/11/02/utter-insanity</id>
   <content type="html">&lt;p&gt;Video of Dan Osman speed-soloing up Bear’s Reach at Lover’s Leap (near South Lake Tahoe, CA). Need I say don’t try this at home? &lt;a href=&quot;http://www.ebaumsworld.com/video/watch/1220/&quot;&gt;http://www.ebaumsworld.com/video/watch/1220/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/images/dano_leap_sm.jpg&quot; width=&quot;220&quot; height=&quot;165&quot; alt=&quot;Dan Osman dyno on Bear&amp;#39;s Reach&quot; style=&quot;float: left; margin: 0px 10px 10px 0px; border: 1px solid black;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;(I’ve done this route, but it took me more like 2 hours–not 4 minutes and 25 seconds.)&lt;/p&gt;

&lt;p&gt;I’m not sure when this video was shot, but I think it was not long before his death on November 23, 1998. He was always a huge risk-taker, and one of his hobbies was taking very long falls on climbing ropes. He died attempting a 925-foot fall on rigging that he had left up in Yosemite in the rain and snow for over a month. Pretty stupid.&lt;/p&gt;

&lt;p&gt;Here’s a good article about Dan: &lt;a href=&quot;http://www.outsideonline.com/outdoor-adventure/Terminal-Velocity.html&quot;&gt;
http://www.outsideonline.com/outdoor-adventure/Terminal-Velocity.html&lt;/a&gt;&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Flock</title>
   <link href="https://footle.org/2005/10/20/flock/"/>
   <updated>2005-10-20T16:11:00-07:00</updated>
   <id>https://footle.org/2005/10/20/flock</id>
   <content type="html">&lt;p&gt;I&apos;m posting this entry from within &lt;a href=&quot;http://www.flock.com/&quot;&gt;Flock&lt;/a&gt;, a new browser based on Mozilla, the codebase which underlies Firefox. You might think the world needs a new browser like it needs a hole in the head, and I more or less agree with you, but Flock has some really cool features:&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;You can link your bookmarks to your &lt;a href=&quot;http://del.icio.us&quot;&gt;del.icio.us&lt;/a&gt; account so that they&apos;re always available when you move between computers.&lt;/li&gt;&lt;/ul&gt;
&lt;ul&gt;&lt;li&gt;It integrates with a number of blogging services and software to let you blog directly from the browser. You can even highlight a chunk of text on the page, right-click on it and select &quot;Blog This&quot;, and it opens up a blog post window with the text inserted and quoted, and the site name linked. (I&apos;m finding that its blogging editor is incredibly annoying when you&apos;re trying to do bulleted lists)&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://flickr.com&quot;&gt;flickr&lt;/a&gt; integration, which seems to me to be a bit gratuitous, but it is kind of cool to get access to your photos in a toolbar (sorry, &quot;topbar&quot;).&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;ul&gt;&lt;li&gt;Integrated RSS feed reader, which right now has a really clunky interface. But this is just a developer preview release, so I&apos;m sure that will improve.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;ul&gt;&lt;li&gt;&quot;The Shelf&quot;...kind of a clipboard for web content. You can drag-and-drop links, chunks of text, or pictures on to it and later drag-and-drop them into your blog posts (it seems to be made pretty specifically for blogging; you can&apos;t double-click on items in your Shelf to open them up, and although you can drop them onto any application that accepts clipboard data, what you get is an HTML-wrapped version of your content).&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;All in all, very impressive. I hope that some of these features (especially the social bookmarking integration) make their way over to Firefox, but I&apos;ll be keeping an eye on Flock&apos;s progress.&lt;br /&gt;&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>The Future of Video</title>
   <link href="https://footle.org/2005/10/12/the-future-of-video/"/>
   <updated>2005-10-12T07:16:40-07:00</updated>
   <id>https://footle.org/2005/10/12/the-future-of-video</id>
   <content type="html">&lt;p&gt;Apple just released a new video-capable iPod, as was expected. You can also download music videos from the iTunes Music Store, at $1.99 a shot. That&apos;s cool. Yawn.&lt;/p&gt;

&lt;p&gt;But wait...what&apos;s really interesting is that you can also download episodes from some TV shows, like Lost or Desperate Housewives--also for $1.99. This is the start of a major paradigm shift. I&apos;m not a huge TV watcher, but there are a few good shows out there that we&apos;ve gotten hooked on (Lost, Smallville, Arrested Development, Battlestar Galactica). Not having cable and Tivo, though, I can&apos;t always catch my shows. I&apos;ve always said I&apos;d be happy to pay a small fee ($1.99 is about right) to be able to download an episode legally (it&apos;s not hard to find and download them &quot;illegally&quot; online). Now I can do that. Go Apple. The networks certainly weren&apos;t going to get their shit together to do it themselves.&lt;/p&gt;

&lt;p&gt;It&apos;s still got a long way to go. Only a few shows are apparently available. Actually, I don&apos;t know exactly what&apos;s available because the only links to videos on their &quot;Music&quot; store home page are for &quot;Music Videos&quot; and a big &quot;Lost&quot; graphic. Is it so hard to just have a separate video section in your store? I&apos;m guessing that Apple tried to push this out the door quickly, before properly redesigning their store interface to support the videos. Or maybe not. It&apos;s not that hard to do. Regardless, I&apos;m sure they&apos;ll sort it out soon enough.&lt;/p&gt;

&lt;p&gt;They&apos;re going to have to rename the Music Store, though. Media Store? Actually, my guess is that once they pad out their offerings a bit, they&apos;ll have a separate Video Store.&lt;/p&gt;

&lt;p&gt;An Apple Video Store will be huge for everyone involved. The networks will be able to squeeze new money out of shows that have long since been written off. You&apos;ll be able to relive your youth by downloading some Miami Vice episodes or &quot;owning&quot; your own copy (as much as Apple&apos;s DRM lets you own) of the classic &quot;Master of my Domain&quot; Seinfeld episode, not to mention getting access to all kinds of old shows that will never make it to DVD. And of course Apple get its cut.&lt;/p&gt;

&lt;p&gt;Go Apple.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Shot of the Week</title>
   <link href="https://footle.org/2005/10/11/ford/"/>
   <updated>2005-10-11T15:45:05-07:00</updated>
   <id>https://footle.org/2005/10/11/ford</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/bgreenlee/51785879/&quot;&gt;&lt;img src=&quot;http://static.flickr.com/28/51785879_e345edcb47_m.jpg&quot; style=&quot;border: 1px solid black&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Link Roundup</title>
   <link href="https://footle.org/2005/10/11/link-roundup-2/"/>
   <updated>2005-10-11T02:17:20-07:00</updated>
   <id>https://footle.org/2005/10/11/link-roundup-2</id>
   <content type="html">&lt;p&gt;In lieu of anything else interesting to post, I&apos;ll clear out some of the links I&apos;ve been saving:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;http://writeboard.com/&quot;&gt;Writeboard&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;
I haven&apos;t had the opportunity to really use this yet, but it looks like a pretty cool collaboration tool. No more sending Word docs back and forth. It&apos;s also packaged with their equally cool &lt;a href=&quot;http://backpackit.com&quot;&gt;Backpack&lt;/a&gt; app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;http://aurgasm.us/&quot;&gt;Aurgasm&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;
I&apos;m a bit late in the game here, but I&apos;ve just started discovering the wonderful world of MP3 blogs. All sorts of great, eclectic music, for free. There are more MP3 blogs out there than you can shake your booty at, but this is one of my favorites.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;http://www.alistapart.com/articles/improvingprint&quot;&gt;Improving Link Display for Print&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;
Absolutely ingenious. Using CSS &amp;amp; Javascript, you can automatically list all links on the print version of your web page as footnotes. I&apos;m going to have to give it a shot on this site.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://www.copilot.com/&quot;&gt;Fog Creek Copilot&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;
For anyone who is, like I am, the person family and friends turn to when they have computer problems, this looks like a godsend for those trickier issues. Yes, computer remote control software is nothing new, but the really ingenious thing here is how easy it is to get someone set up. You just sign up with the site and give the person you&apos;re helping a code. They go to the site, enter the code, download the necessary software, and you&apos;re connected.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>CSS Layouts: I Give Up</title>
   <link href="https://footle.org/2005/09/27/css-layouts-i-give-up/"/>
   <updated>2005-09-27T09:57:00-07:00</updated>
   <id>https://footle.org/2005/09/27/css-layouts-i-give-up</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/public/images/thescream_crop.jpg&quot; width=&quot;165&quot; height=&quot;202&quot; alt=&quot;The Scream&quot; style=&quot;float: left; padding: 0px 10px 10px 0px;&quot; /&gt;We&apos;re in the middle of a fairly major site redesign at &lt;a href=&quot;http://triporama.com&quot;&gt;Triporama&lt;/a&gt;, and I was doing my best to have the layout be as purely CSS as possible, replacing the previous table-heavy layout. It&apos;s turned out to be a major headache, and I&apos;m taking a step back now and reimplementing parts of the layout with tables.&lt;/p&gt;

&lt;p&gt;One problem with CSS today is that every different browser has different levels of support for the different versions of CSS, whereas tables have been around for so long that most browsers in use today handle them fairly similarly. The really big problem with CSS, though, is IE. Internet Explorer is a &lt;a href=&quot;http://www.positioniseverything.net/explorer.html&quot;&gt;CSS bug fest&lt;/a&gt;. It would be great to say &quot;fuck IE,&quot; (actually, I say that almost every day) but it is unfortunately still the most widely used browser.&lt;/p&gt;

&lt;p&gt;Yes, I know--tables aren&apos;t meant to be used for layout; they&apos;re not &quot;semantic&quot;, they&apos;re slower (not sure about that one--maybe if you have many levels of nested tables). And yes, clever designers have come up with all sorts of tricks to get CSS layouts to work across different browsers. But you end up spending hours or days getting your layout to work on various browsers and what you have in the end is a confusing morass of fragile code. It&apos;s just not worth it. I&apos;ll wait for IE 7 plus a few years (although my parents will probably still be using AOL 8.0 on a dialup line) before attempting a pure-CSS site again.&lt;/p&gt;

&lt;p&gt;So, to summarize my new web design philosophy: use CSS for various individual elements/components on the site, but if you&apos;re doing a multi-column layout, use a table for the main layout (actually, I still have my header and footer positioned with CSS, as I spent far too long figuring out how to get the footer to stay glued to the bottom of the page if you have less than a page worth of content, but to flow after the main content if you have more...and the solution I found seems to work on all modern browsers). The layout for the whole site is in a single file, so making site-wide changes (another argument for using CSS) is still easy.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Slowlight</title>
   <link href="https://footle.org/2005/09/19/slowlight/"/>
   <updated>2005-09-19T16:16:11-07:00</updated>
   <id>https://footle.org/2005/09/19/slowlight</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;http://www.apple.com/macosx/features/spotlight/&quot;&gt;Spotlight&lt;/a&gt; was a great addition to OS X, and it works great for finding things buried in your filesystem. But for anyone used to &lt;a href=&quot;http://quicksilver.blacktree.com/&quot;&gt;Quicksilver&lt;/a&gt; or &lt;a href=&quot;http://www.obdev.at/products/launchbar/&quot;&gt;LaunchBar&lt;/a&gt;, it is painfully slow as an application launcher, which is really all I need most of the time. I recently reinstalled Quicksilver and I don&apos;t think I&apos;ve touched Spotlight since then.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Link Roundup</title>
   <link href="https://footle.org/2005/09/19/link-roundup/"/>
   <updated>2005-09-19T02:08:09-07:00</updated>
   <id>https://footle.org/2005/09/19/link-roundup</id>
   <content type="html">&lt;p&gt;Some random interesting stories/links I’ve run across in the last week or so:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.lennyjones.net/burn2005/comicbook2005.htm&quot;&gt;Photos from this year&apos;s Burning Man&lt;/a&gt; in the form of a graphic novel. Very nicely done.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.freedom-to-tinker.com/?p=893&quot;&gt;With an audio recording of you typing away at your computer for 10 minutes, it&apos;s possible to figure out everything you typed.&lt;/a&gt; (via &lt;a href=&quot;http://www.counterpane.com/crypto-gram.html&quot;&gt;Crypto-Gram&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://news.bbc.co.uk/cbbcnews/hi/newsid_4200000/newsid_4209000/4209004.stm&quot;&gt;Tongue-eating bug found in fish.&lt;/a&gt; So gross, but so cool. (via &lt;a href=&quot;http://boingboing.net/&quot;&gt;Boing-Boing&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.hotflashgames.com/wordpads.htm&quot;&gt;Word Pads&lt;/a&gt;, a very addictive word game. My high score so far is &lt;strike&gt;only around 5000&lt;/strike&gt; 18575.&lt;/p&gt;

&lt;p&gt;I didn&apos;t really discover this in the last week, but it&apos;s too cool not to get a mention: the &lt;a href=&quot;http://www.sueandpaul.com/gmapPedometer/?centerX=-122.35782623291016&amp;amp;centerY=37.7916084854395&amp;amp;zl=5&amp;amp;fl=m-e-h-0-1&amp;amp;polyline=&quot;&gt;Gmaps  Pedometer&lt;/a&gt; (the link centers on a more interesting location than the default of Hoboken, NJ). It&apos;s a testament to the brilliance of the Google folks that people have been able to come up with great hacks like this.&lt;/p&gt;

&lt;p&gt;Finally, I&apos;m going to try to play in the upcoming Ultimate Frisbee regionals, despite not having played since last winter, mostly due to my crappy back. I think I can hold it together for a weekend. Or at least a day. But this has inspired me: &lt;a href=&quot;http://www.aftenposten.no/english/sports/article1115952.ece&quot;&gt;a 67-year old man comes out of retirement to play for his soccer team in their time of need.&lt;/a&gt; (via &lt;a href=&quot;http://www.fark.com&quot;&gt;Fark&lt;/a&gt;)&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>LINQ</title>
   <link href="https://footle.org/2005/09/17/linq/"/>
   <updated>2005-09-17T02:49:05-07:00</updated>
   <id>https://footle.org/2005/09/17/linq</id>
   <content type="html">&lt;p&gt;I&apos;m not a C#/.Net programmer, but &lt;a href=&quot;http://msdn.microsoft.com/netframework/future/linq/default.aspx&quot;&gt;LINQ&lt;/a&gt; is too cool. You can basically use SQL-like querying on just about any collection, whether it be an array in memory, a database, and XML structure. This is one of those &quot;why didn&apos;t anyone think of this before?&quot; things. Yes, there have been similar tools for querying objects for a long time, but nothing this elegant. &lt;a href=&quot;http://channel9.msdn.com/Showpost.aspx?postid=114680&quot;&gt;Watch the video&lt;/a&gt; for a quick (well, 30 minute) intro, or, if you prefer text, read the &lt;a href=&quot;http://msdn.microsoft.com/netframework/future/linq/default.aspx?pull=/library/en-us/dndotnet/html/linqprojectovw.asp&quot;&gt;overview document&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>New Pics</title>
   <link href="https://footle.org/2005/09/01/new-pics-2/"/>
   <updated>2005-09-01T04:38:22-07:00</updated>
   <id>https://footle.org/2005/09/01/new-pics-2</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;http://flickr.com/photos/bgreenlee&quot;&gt;&lt;img src=&quot;http://static.flickr.com/23/38261653_30bd841392_m.jpg&quot; style=&quot;float: left; margin: 0 10px 10px 0; border: 1px solid black;&quot; /&gt;&lt;/a&gt;Finally got off my butt and posted some more pics to &lt;a href=&quot;http://flickr.com/photos/bgreenlee&quot;&gt;Flickr&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;br style=&quot;clear: both&quot; /&gt;&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Spam Filtering Idea</title>
   <link href="https://footle.org/2005/08/30/spam-filtering-idea/"/>
   <updated>2005-08-30T03:13:36-07:00</updated>
   <id>https://footle.org/2005/08/30/spam-filtering-idea</id>
   <content type="html">&lt;p&gt;I share a hosted server with a few friends. We host a number of sites (including this one) and our own email. We have SpamAssassin set up and tuned pretty nicely (thanks, Jelo). Unfortunately, it&apos;s killing our server. SpamAssassin can suck up a lot of resources. Ideally we&apos;d have a server dedicated to processing mail, but we can&apos;t afford that.&lt;/p&gt;

&lt;p&gt;So here&apos;s my idea: a spam filtering cluster. Have a bunch of [trusted] home-based servers set up with SpamAssassin and dynamic DNS. A mail comes into the main mailserver and if it isn&apos;t on a whitelist, it gets shipped out to one of the filter machines. The filter machine runs SA on it and lets the main server know the result (it doesn&apos;t need to sent the mail back, so no worries about low upload speeds). Emails over a certain size would probably just be processed on the main server to avoid the bandwidth and time required to send it out (large emails are rarely spam anyway). Finally, in order for the Bayesian filtering to function correctly, you&apos;d have to periodically sync the data from the Bayesian learner out to the filter machines.&lt;/p&gt;

&lt;p&gt;I&apos;ve looked at SpamAssassin a bit and I think it wouldn&apos;t be too hard. SA comes with a client and a server, spamc and spamd. Incoming mail gets piped through spamc, which takes care of shipping it off to spamd for processing. Spamd can live on any other host. It can also just report back whether the email was spam or not, rather than returning the entire email. So the only two things left to do are:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Write a small client (spamb?) that maintains a list of hosts running spamd. When a message comes in, pick the next hostname in the list, and pass it on to spamc. Spamc sends it to the appropriate spamd host, and receives the response--either yes/no or in our case, the full SA report, which gets attached to the message headers. If we get the full message back, that means that spamc timed out trying to contact that spamd host. In this case, mark that host as being down, along with a timestamp, and take it out of the rotation for a certain period of time.&lt;/li&gt;
&lt;li&gt;A way to distribute the users&apos; bayesian data files and prefs to the remote systems. Apparently spamd can read user from a SQL database, although I haven&apos;t looked into it to see if the bayesian learner data can be stored in a database. If so, that&apos;s an easy solution to the problem. Otherwise, you could just write a script that checks for changes in any of the user files and if it sees them, rsyncs them to each of the hosts.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I&apos;ll let you know what happens if I get around to trying this out.&lt;/p&gt;

</content>
 </entry>

 
 
 <entry>
   <title>Ruby on Rails Problem with OS X</title>
   <link href="https://footle.org/2005/08/28/ruby-on-rails-problem-with-os-x/"/>
   <updated>2005-08-28T04:41:22-07:00</updated>
   <id>https://footle.org/2005/08/28/ruby-on-rails-problem-with-os-x</id>
   <content type="html">&lt;p&gt;I&apos;ve been playing around with &lt;a href=&quot;http://www.rubycentral.com/&quot;&gt;Ruby&lt;/a&gt; and &lt;a href=&quot;http://rubyonrails.org/&quot;&gt;Ruby on Rails&lt;/a&gt; lately. I&apos;m not that far into it yet, but they both look interesting. I&apos;ll write more about my experiences later.&lt;/p&gt;

&lt;p&gt;In the meantime, if you&apos;re setting this up on a Mac (running Tiger) like I am, do yourself a favor and before you start getting into any of the Rails tutorials (like &lt;a href=&quot;http://www.onlamp.com/pub/a/onlamp/2005/01/20/rails.html?page=1&quot;&gt;Rolling With Ruby on Rails&lt;/a&gt;), go here first:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.juju.org/archives/2005/08/06/ruby-on-rails-mysql-and-osx-tiger-woes&quot;&gt;Ruby On Rails, Mysql, and OSX Tiger Woes&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Do what it says (including &lt;a href=&quot;http://tech.rufy.com/entry/46&quot;&gt;the fix&lt;/a&gt; it mentions), and you&apos;ll save yourself a lot of grief. Note that as one of the commentors mentions, it works just fine with &lt;a href=&quot;http://tmtm.org/downloads/mysql/ruby/mysql-ruby-2.7.tar.gz&quot;&gt;mysql-ruby-2.7&lt;/a&gt; also.&lt;/p&gt;

&lt;p&gt;Back to my tutorial...&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>What do ants smell like?</title>
   <link href="https://footle.org/2005/08/26/what-do-ants-smell-like/"/>
   <updated>2005-08-26T11:08:37-07:00</updated>
   <id>https://footle.org/2005/08/26/what-do-ants-smell-like</id>
   <content type="html">&lt;p&gt;Just got an appointment reminder from Kaiser. Must remember not to put on my Parfum de la Fourmi.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/public/images/kaiser_sm.jpg&quot; width=&quot;400&quot; height=&quot;264&quot; alt=&quot;kaiser sm&quot; /&gt;&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Sage Advice of the Day</title>
   <link href="https://footle.org/2005/08/24/sage-advice-of-the-day/"/>
   <updated>2005-08-24T03:02:53-07:00</updated>
   <id>https://footle.org/2005/08/24/sage-advice-of-the-day</id>
   <content type="html">&lt;p&gt;Some insight to be gleaned here:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.thisisgoingtobebig.com/2005/08/10_steps_to_a_h.html&quot;&gt;10 Steps to a Hugely Successful Web 2.0 Company&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I don&apos;t completely agree with all of his &quot;steps&quot;, particularly the examples he provides. Take #7--Get people hooked on free--for example. Yes, free will always win you fans, and a large user base has intrinsic value, but if you&apos;re providing a service that people are willing to pay for, by all means let them pay.  (Regarding his Thefacebook vs. Match.com example--which one is actually making money?)  Still, there are some good ones. My favorite: &lt;b&gt;6.  Be mindnumbingly simple.&lt;/b&gt; Then again, this is a pretty &lt;a href=&quot;http://en.wikipedia.org/wiki/KISS_principle&quot;&gt;age-old design mantra.&lt;/a&gt;&lt;/p&gt;

</content>
 </entry>

 
 
 <entry>
   <title>Useful Sites of the Week</title>
   <link href="https://footle.org/2005/08/15/useful-sites-of-the-week/"/>
   <updated>2005-08-15T03:56:11-07:00</updated>
   <id>https://footle.org/2005/08/15/useful-sites-of-the-week</id>
   <content type="html">&lt;p&gt;I&apos;ve had my web designer hat on lately. I&apos;ve always been a much better judge of good design than a creator of good design, so I need all the help I can get. One thing that can make a huge difference in the quality of your site is color selection. Here are some sites I&apos;ve been going to lately for chromatic inspiration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;http://www.returnofdesign.com/colors/&quot;&gt;The Return of Design - Web Color Schemes&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;
A slew of pre-packaged palettes, all using web-safe colors (i.e. 256-color palette), each with a number of variations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;http://www.colorblender.com/&quot;&gt;ColorBlender&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;
Pick your starting color and ColorBlender will show you a 6-color palette for that color, and allow you to easily play with variations or customize them. You can also save them [to a cookie] so you have your personal blends available to you whenever you visit the site. You can also email direct links to your blend. Very cool.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;http://wellstyled.com/tools/colorscheme2/index-en.html&quot;&gt;Color Scheme Generator 2&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;
The ultimate color-generating tool. If you can&apos;t come up with a color scheme you like with this tool, you really are a lost cause. You can even see how your scheme looks to people with any one of eight different types of colorblindness.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>CSS Not Working? Don't Forget Your Doctype</title>
   <link href="https://footle.org/2005/08/08/css-not-working-dont-forget-your-doctype/"/>
   <updated>2005-08-08T11:54:22-07:00</updated>
   <id>https://footle.org/2005/08/08/css-not-working-dont-forget-your-doctype</id>
   <content type="html">&lt;p&gt;I just spend *hours* trying to get some CSS working only to discover that the reason it wasn&apos;t working was because I didn&apos;t have the DOCTYPE declared at the top of my html:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Strict//EN&quot;
         &quot;DTD/xhtml1-strict.dtd&quot;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

</content>
 </entry>

 
 
 <entry>
   <title>The Butler in the Pantry with the Candlestick</title>
   <link href="https://footle.org/2005/08/04/the-butler-in-the-pantry-with-the-candlestick/"/>
   <updated>2005-08-04T08:32:26-07:00</updated>
   <id>https://footle.org/2005/08/04/the-butler-in-the-pantry-with-the-candlestick</id>
   <content type="html">&lt;p&gt;Today&apos;s diversion: &lt;a href=&quot;http://www.coudal.com/thefish.php&quot;&gt;Whose Fish?&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Took me about 45-50 minutes, the first 30 minutes of which were spent on a false start. After starting over with a better system for keeping track of everything, it wasn&apos;t that bad.&lt;/p&gt;

&lt;p&gt;I really doubt that this was Einstein&apos;s puzzle, and certainly the 2% figure is pulled out of someone&apos;s ass, but it&apos;s still good for some brain calisthenics.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Secret to cheaper flights?</title>
   <link href="https://footle.org/2005/08/04/secret-to-cheaper-flights/"/>
   <updated>2005-08-04T06:33:26-07:00</updated>
   <id>https://footle.org/2005/08/04/secret-to-cheaper-flights</id>
   <content type="html">&lt;p&gt;Last night Jacqueline was looking around online for flights to Seattle. She ended up falling asleep before she could book anything, but when she went to check again in the morning, she found that the same flights were about $30 cheaper.&lt;/p&gt;
&lt;p&gt;Perhaps it was just a coincidence, but my theory is that people/agents put holds on flights throughout the day, and those holds are released at the end of the day (assumedly midnight, although I don&apos;t know which timezone), freeing up seats and thus reducing prices. Has anyone else seen this? Or is this common knowledge and I&apos;ve just been clueless?&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Netflix</title>
   <link href="https://footle.org/2005/08/02/netflix/"/>
   <updated>2005-08-02T17:05:18-07:00</updated>
   <id>https://footle.org/2005/08/02/netflix</id>
   <content type="html">&lt;p&gt;I finally caved in and signed up for Netflix, as you&apos;ll see if you look on the bottom of the sidebar. I&apos;ve been a bit of Luddite, preferring to get my movies from one of the great local video stores. But we recently moved and now our closest video store is about a mile away--as opposed to about 200 feet away--so our movie-watching has dropped dramatically (while our watching of mind-numbing reality shows has increased accordingly).&lt;/p&gt;
&lt;p&gt;It seems to me that the queue is the key feature of Netflix. I can&apos;t count the number of times we&apos;ve seen a preview for a movie and thought &quot;We should rent that.&quot; Then you get to the video store and you spend half an hour walking up and down the Recent Releases trying to figure out what to get. Then again, sometimes you&apos;re in the mood for a particular kind of movie, and it might not be what&apos;s next in your queue.&lt;/p&gt;
&lt;p&gt;Hmmm...here&apos;s a business idea to help out all those struggling video stores in the new Netflix world: make an online service (let&apos;s call it FooFlix) where people can browse movies, get recommendations, and add movies to a queue, much like Netflix. But then install terminals in video stores and tie member&apos;s FooFlix accounts to their video store account. Then they scan/swipe/enter their store card/code in the terminal and it brings up the movies in their queue and highlights the ones that the video store has available. The stores would also be able to see what their customers (or an aggregate of all FooFlix customers) have in their queues, so they know what they should be ordering.&lt;/p&gt;
&lt;p&gt;As for a revenue model, you probably couldn&apos;t get away with charging customers for the service, but you could charge video stores to rent the terminal, and perhaps for customer queue data. You could probably do some pretty targeted advertising on the site, too.&lt;/p&gt;
&lt;p&gt;Probably not going to make me a billionare. If anyone steals the idea, at least send me a postcard or something.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Thank God I wasn't OS/2 Warp</title>
   <link href="https://footle.org/2005/07/29/which-os-are-you/"/>
   <updated>2005-07-29T17:03:16-07:00</updated>
   <id>https://footle.org/2005/07/29/which-os-are-you</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;http://bbspot.com/News/2003/01/os_quiz.php&quot;&gt;&lt;img src=&quot;http://www.bbspot.com/public/images/News_Features/2003/01/os_quiz/slackware.jpg&quot; width=&quot;300&quot; height=&quot;90&quot; border=&quot;0&quot; alt=&quot;You are Slackware Linux. You are the brightest among your peers, but are often mistaken as insane.  Your elegant solutions to problems often take a little longer, but require much less effort to complete.&quot; /&gt;
&lt;br /&gt;
Which OS are You?&lt;/a&gt;&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>ISO Good-enough Idea</title>
   <link href="https://footle.org/2005/07/27/so-good-enough-idea/"/>
   <updated>2005-07-27T17:13:43-07:00</updated>
   <id>https://footle.org/2005/07/27/so-good-enough-idea</id>
   <content type="html">&lt;p&gt;Joel Spolsky&apos;s &lt;a href=&quot;http://www.joelonsoftware.com/articles/HighNotes.html&quot;&gt;latest article&lt;/a&gt; is largely a rehash of &lt;a href=&quot;http://www.joelonsoftware.com/articles/fog0000000074.html&quot;&gt;one of his earliest articles&lt;/a&gt;, whereby he expounds on his belief (which I share) that there&apos;s no substitute for top-notch programmers. The thing that got me thinking was his  &quot;shaky claim that most people are wrong in thinking you need an idea to make a successful software company,&quot; and this chart:&lt;/p&gt;

&lt;table style=&quot;FONT: 12px Helvetica,Arial,sans-serif; TEXT-ALIGN: center&quot; align=&quot;center&quot; border=&quot;0&quot;&gt;
			&lt;tbody&gt;
&lt;tr&gt;
				&lt;td style=&quot;BORDER-RIGHT: black 1px solid; BORDER-TOP: black 1px solid; BORDER-LEFT: black 1px solid; WIDTH: 65px; BORDER-BOTTOM: black 1px solid&quot;&gt;Best Working Conditions&lt;/td&gt;
				&lt;td style=&quot;FONT-SIZE: 200%&quot;&gt;=&amp;gt;&lt;/td&gt;

				&lt;td style=&quot;BORDER-RIGHT: black 1px solid; BORDER-TOP: black 1px solid; BORDER-LEFT: black 1px solid; WIDTH: 65px; BORDER-BOTTOM: black 1px solid&quot;&gt;Best Programmers&lt;/td&gt;
				&lt;td style=&quot;FONT-SIZE: 200%&quot;&gt;=&amp;gt;&lt;/td&gt;
				&lt;td style=&quot;BORDER-RIGHT: black 1px solid; BORDER-TOP: black 1px solid; BORDER-LEFT: black 1px solid; WIDTH: 65px; BORDER-BOTTOM: black 1px solid&quot;&gt;Best Software&lt;/td&gt;
				&lt;td style=&quot;FONT-SIZE: 200%&quot;&gt;=&amp;gt;&lt;/td&gt;
				&lt;td style=&quot;BORDER-RIGHT: black 1px solid; BORDER-TOP: black 1px solid; BORDER-LEFT: black 1px solid; WIDTH: 65px; BORDER-BOTTOM: black 1px solid&quot;&gt;Profit!&lt;/td&gt;
			&lt;/tr&gt;

		&lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;The problem I have with this is that you still need a pretty good idea to start with, or you&apos;re never going to get the best programmers in the first place. Great programmers aren&apos;t in it for the money; they want to work on stuff that interests them. Cool stuff. Sexy stuff. Having a great working environment with lots of other great programmers around is a big draw too, but how are you going to achieve that without the great idea in the first place?&lt;/p&gt;

&lt;p&gt;This hits a chord with me because I know a lot of great programmers with whom I would love to start a company, but I&apos;ve been waiting for the perfect idea to come along and it hasn&apos;t. But perhaps the trick is to just come up with a good-enough idea -- good enough to get one or two other great programmers to dive into it with you -- and just take it from there. &lt;/p&gt;

&lt;p&gt;So...who&apos;s got a good-enough idea?&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>There's Sex In My Violence!</title>
   <link href="https://footle.org/2005/07/22/theres-sex-in-my-violence/"/>
   <updated>2005-07-22T03:22:22-07:00</updated>
   <id>https://footle.org/2005/07/22/theres-sex-in-my-violence</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;http://sfgate.com/cgi-bin/article.cgi?f=/gate/archive/2005/07/22/notes072205.DTL&amp;amp;nl=fix&quot; target=&quot;_blank&quot;&gt;Another great column&lt;/a&gt; by Mark Morford. Complaining about a bit of hidden sex in a game that glorifies sex, drugs, and violence does seem a bit misguided. Yeah, Puritan roots!&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Falling</title>
   <link href="https://footle.org/2005/07/13/falling/"/>
   <updated>2005-07-13T16:16:52-07:00</updated>
   <id>https://footle.org/2005/07/13/falling</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;http://www.izpitera.ru/lj/tetka.swf&quot;&gt;Cool and a bit disturbing, and strangely addictive.&lt;/a&gt; Use your mouse to move her around. Pretty nice bit of programming.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Embrace Your Geekness</title>
   <link href="https://footle.org/2005/07/13/embrace-your-geekness/"/>
   <updated>2005-07-13T02:29:38-07:00</updated>
   <id>https://footle.org/2005/07/13/embrace-your-geekness</id>
   <content type="html">&lt;p&gt;Somebody has deemed today Embrace Your Geekness Day. So what better way to celebrate than post to my blog.&lt;/p&gt;

&lt;p&gt;I searched around for information about the origins of this holiday, but found nothing other than lists of other obscure days (July 15th is Respect Canada Day!). How does one get a day proclaimed anyway? There are some openings left; one calendar I looked at had the 29th and 31st of this month still open. How about a Wear Flip-Flops to Work Day? (Googling for that came up with a &lt;a href=&quot;http://ubersite.com/m/38413&quot;&gt;single hit&lt;/a&gt;.)&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Belated Happy Birthday</title>
   <link href="https://footle.org/2005/07/11/belated-happy-birthday/"/>
   <updated>2005-07-11T07:33:11-07:00</updated>
   <id>https://footle.org/2005/07/11/belated-happy-birthday</id>
   <content type="html">&lt;p&gt;The July 4th New Yorker cover was classic:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/public/images/New_Yorker___July_4_2005__Small_.jpg&quot; title=&quot;New Yorker   July 4 2005  Small &quot;&gt;
&lt;img src=&quot;/public/images/thumb_New_Yorker___July_4_2005__Small_.jpg&quot; width=&quot;146&quot; height=&quot;200&quot; alt=&quot;New Yorker   July 4 2005  Small &quot; /&gt;
&lt;/a&gt;&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Scrumptions Muffins</title>
   <link href="https://footle.org/2005/07/09/scrumptions-muffins/"/>
   <updated>2005-07-09T19:39:57-07:00</updated>
   <id>https://footle.org/2005/07/09/scrumptions-muffins</id>
   <content type="html">&lt;p&gt;From a cookbook by the Ladies Auxillary of some hospital in Rhode Island:&lt;/p&gt;

&lt;p&gt;Scrumptions Muffins&lt;/p&gt;

&lt;p&gt;1 cup softened vanilla ice cream
1 cup sifted self-rising flour&lt;/p&gt;

&lt;p&gt;Mix well. Pour into a muffin tin lined with paper cups, about 3/4 full. Bake at 350 F for 20 min.&lt;/p&gt;

&lt;p&gt;You know you want to make them. I know I will.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Update:&lt;/b&gt; Made them. I had to improvise a bit, as I didn’t have self-rising flour. I added about 1/2 tsp. of baking powder instead. They were pretty bad. Very dense. Must have been the flour.&lt;/p&gt;
</content>
 </entry>

 
 
 <entry>
   <title>Always check your logs</title>
   <link href="https://footle.org/2005/07/08/always-check-your-logs/"/>
   <updated>2005-07-08T13:30:50-07:00</updated>
   <id>https://footle.org/2005/07/08/always-check-your-logs</id>
   <content type="html">&lt;p&gt;Brad’s #1 rule of debugging web apps: always check your log files. All of them.&lt;/p&gt;

&lt;p&gt;A friend of mine just ran into a problem where a php file upload script that had been working fine for months suddenly started barfing on large files. He was getting a “partial upload” error. I told him to check his web server error logs and his system message log. He did the former, and after hours of pounding his head against the wall, I finally went in and poked around myself. I actually found the problem before looking in the log files, but there it was in &lt;code&gt;/var/log/messages&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;Jul 7 15:27:42 xxxx /kernel: pid 46891 (httpd), uid 80 on /var: file system full
Jul 7 15:30:02 xxxx /kernel: pid 46875 (httpd), uid 80 on /var: file system full
Jul 7 15:49:07 xxxx /kernel: pid 46872 (httpd), uid 80 on /var: file system full&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The temp directory that php was using for file uploads was &lt;code&gt;/var/tmp&lt;/code&gt;, and &lt;code&gt;/var&lt;/code&gt; only had 216K left. This is why small file uploads were working, but larger ones weren’t. (As an aside, be careful of what you’re storing in &lt;code&gt;/var&lt;/code&gt;. On some systems, log files are kept in &lt;code&gt;/var/log&lt;/code&gt;, and /var is often set up as a separate partition, and often relatively small at that. In his case, the whole partition was only 252M, and &lt;code&gt;/var/log&lt;/code&gt; was eating up 195M of that…and growing. We moved &lt;code&gt;/var/log&lt;/code&gt; to &lt;code&gt;/usr/var/log&lt;/code&gt; and created a symlink.)&lt;/p&gt;
</content>
 </entry>

 

</feed>
