Wood stove for heating a home: Lessons learned from three months in the redwoods

I moved to Guerneville in September, from San Francisco. Guerneville is a tiny town on the Russian River, nestled in the redwoods, about 12 miles from the coast and two hours north of San Francisco.

It's cold here, compared to the other places in California that I've lived. (It's not cold compared to Connecticut, Rhode Island, Tahoe, or Seattle.)

I'm learning how to use a wood stove to heat my home. With starting a fire every day, sometimes multiple times a day, and then watching it thrive or subside all day, I have learned a lot about woodstoves, rather quickly. I've also been quite motivated to learn -- if I don't get a nice fire going, then either I'm cold, or I risk a creosote chimney fire.

This is a great set-up for learning!

  • frequent practice
  • low risk of disaster
  • intrinsic motivation
  • inexpensive practice
  • rapid feedback
  • friendly experts and advice.

Most of the things that I learned now seem like I should have known them instinctively -- I took physics in college! -- but I didn't.

Here's what I learned:

  • wood has to be both hot and dry enough in order to burn.
  • walnut wood that’s lived its life in a tree in a watered orchard and then in a pile (not a careful stack) is not very dry.
  • Wood that is not very dry needs to be a lot hotter than dry wood in order to ignite and stay lit.
  • Kindling is not just defined by diameter; it’s also needs a lower temperature to catch flame.
  • Therefore, kindling should be either especially dry (kiln-dried) or especially oily (fatwood).
  • A match won’t light a piece of cold damp wood.
  • To get cold damp wood to become flaming, make it hotter and dryer.
  • The way to get cold damp wood to be hotter and drier, and then to catch fire, is to light a fire with kindling near it.
  • It is easier for a piece of cold damp wood to catch fire when it’s in a hot woodstove than a cold woodstove, because the heat of the woodstove raises the temperature of the wood, and dries it a bit.
  • firelighters that will ignite dry kindling may not ignite cold damp wood.
  • cold damp wood can’t really be started by a fire lighter; it doesn’t create enough heat to warm cold damp wood enough to catch fire.
  • the fire has to heat up the stove itself, before the stove will start heating the room. once the stove is hot, it will radiate heat, and it will make it easier to light the next log.

VSCode performance fix for Mac OS X Sierra

I recently started using VSCode for my Ember development, and I like a lot about it... except, it was slow! I'd been using JetBrains IDEs for years, first RubyMine and then WebStorm, and I wanted to try something new & shiny. (I like shiny things.)

When I ran Ember, Chrome, and VSCode together, horrible things happened. My CPU spiked and my computer crawled. From experience with Sublime and WebStorm, I suspected it was watching too many files. I found a setting that should have helped, but didn't help enough, and then another setting that fixed the problem entirely!

The new special setting is files.watcherExclude. Apparently just files.exclude isn't a strong enough signal that VSCode should really, truly ignore those files.

"files.watcherExclude": {
        "**/.git/objects/**": true,
        "**/.git/subtree-cache/**": true,
        "**/node_modules/*/**": true,
        "**/dist/**": true,
        "**/tmp/**": true
      },
  "files.exclude": {
        "**/.git/objects/**": true,
        "**/.git/subtree-cache/**": true,
        "**/node_modules/*/**": true,
        "**/dist/**": true,
        "**/tmp/**": true
      },

All of the IDEs I've used have required some tuning of this sort. With the JetBrains IDEs, we just have to configure the JVM properties, and the internet knows that pretty well... but I haven't found this fix for vscode mentioned anywhere yet. I hope it helps.

Resources for Beginning Japanese

I have started learning Japanese! Partly to prepare for a trip in October, but also because I want to stretch my brain in different ways. It turns out that I really enjoy it. 

I'm taking a face-to-face class at the Japan Society of California, but that's mostly just to get some experience with actual conversation with a native speaker. I'm actually mostly crafting my education myself. So, without further ado, here are some of my favorite resources:

 

  • Start with learning hiragana. The Tofugu Guide to Learning Hiragana is the best out there. 
  • RealKana is a good app and website for drilling hiragana and katakana. Unlike many other tools, it shows the characters in multiple fonts, and lets you choose which characters to drill. 
  • I use the Genki textbook as my main text. The class I'm taking uses Japanese for Busy People; I like its focus on business people rather than college students, but the explanations are better in Genki. 
  • WaniKani is a fantastic spaced-repetiton system for learning kanji and some vocabulary. It has a whole coherent system of mnemonics that are hilarious and fun. 
  • Fluent Forever is a book with a general approach to learning languages. The author suggests that I will get much more out of a deck that I build; so far I have found that to be true.  
  • Anki! Anki is a general spaced-repetition system -- aka flashcards, but better. There are many, many decks to download, but the act of making my own cards seems to help with retention. 
  • Pimsleur Japanese.  These audio lessons focus on conversation and seem to be obsessed with drinking alcohol. "Now ask the woman if she'd like to have a drink with you. Suggest that you meet at the hotel, or at Miss Suzuki's place." The rest of my materials don't ever prompt me to produce speech, and in the end I want to be able to talk to people, so this is a great resource. 
  • JapanesePod101.com. This is fun supplement to everything else, good for conversation and culture, but not enough to actually learn Japanese. The dialog is almost all with native speakers, and it features an american guy who lives in Japan and talks about his experiences there. 

And then, I've tried out a few resources and decided they're not for me:

 

  • Rosetta Stone. I get access to this for free because I'm a Brown University alum -- nice perk. The problem is that Rosetta Stone is so focused on audio and way too devoted to their own method. It doesn't mix well with other resources. Once I'm in a lesson, it's very hard to skip forward. I'm usually frustrated with the pace when I'm in Rosetta Stone. 
  • Rocket Japanese. My main problem with this is that half of the dialog is by the founder, who is a non-native speaker. Bah, I don't want to spend my time listening to an Englishman speak japanese.

More to come as I discover more great stuff. What do you like? What have I missed? 

 

 

"Could not find watchman" doesn't actually mean it can't find watchman!

I've been doing an ember-cli upgrade, and I started seeing this error message when I start the server:

$ ember serve
Could not find watchman, falling back to NodeWatcher for file system events.
Visit http://www.ember-cli.com/user-guide/#watchman for more info.

This was frustrating because I knew I had watchman installed just fine!

$ which watchman
/usr/local/bin/watchman

This issue on the watchman repo was helpful in figuring this out. Running watchman watch . gave a much more interesting error message:

$ watchman watch .
/Users/benji/Library/LaunchAgents/com.github.facebook.watchman.plist: Operation already in progress ^C ```

The solution for me was to tell launchtl to forget about watchman:

$ launchctl unload ~/Library/LaunchAgents/com.github.facebook.watchman.plist 

After that, ember-cli ran watchman just fine.

There's an issue for this; I'm going to post a fix to clarify the language of the error.

What makes a good pull request description?

When you issue a pull request, you're saying, "I changed some code in this repository -- Please pull my change into the project." You should provide a PR description that tells reviewers what they need to know to evaluate your contribution. Better descriptions give better reviews, which end up with a higher-quality codebase.

Most PRs for a front-end web application should include all of these:

  • Purpose: what is this change trying to accomplish? Linking to specifications or tickets is fine, but you must include a one-sentence explanation in the PR description itself.
  • Approach: how does this change accomplish its goal? Explain your approach's architecture at a high level.
  • Worries: Is there anything weird here? Do you have any areas you want help?
  • Before & after screenshots, if the change is visual
  • How to use the feature or exercise the change. Just linking to a ticket with a bug description is not enough; tell the reviewer how they can verify for themselves that the feature is working as planned.

Larger PRs should also include:

  • Did you consider alternative approaches? Why did you go with the approach you chose?
  • How does this relate to other work? Link to other PRs or describe future plans.

Mapping RGB colors to Philips Hue colors

Converting to Philips Hue color descriptors from colors picked in a web UI can be a bit tricky. Here's what I've come up with, which gets pretty close. The color descriptor is described in the Hue API docs (free account required). There are several other js libraries that work with Hue, but I wanted to build my own.

I'm using the jQuery Color plugin to convert RGB to HSV. Tinycolor will work too, but I went with jQuery Color because it allows CSS transitions with $.anmiate.

Here's the code:

var HueService = {
  colorToHueHsv: function (color) {
    var jqc = $.Color(color);
     return {
       "hue" : Math.floor(65535 * jqc.hue() / 360),
       "sat": Math.floor(jqc.saturation() * 255),
       "bri": Math.floor(jqc.lightness() * 255)
     }
  }
}

The input to the function can be anything that jQuery Color can interpret as a color. For instance, there's a lilac color I like, #676de8.

So I can do HueService.colorToHueHsv('#676de8') and get back {hue: 43143, sat: 187, bri: 167}.

I then turn on one of my lights to that color with a PUT to http://10.0.1.3/api/myusername/lights/3/state with form data {"on":true,"hue":43143,"sat":187,"bri":167}

Assuming I've authenticated to the Hue bridge, the light turns on with pretty much that color. I don't think I have the brightness and saturation mapped quite correctly; it's tricky because the Hue 0-1 space for brightness has 0 at "the lowest brightness possible with the bulb still on". I'll keep tuning this -- check the source for updates.

I'm using this code in my Sunrise Hues project, which lets me build custom sunrises as a gentle alarm clock.

franzen does dfw

One thing I enjoyed in Jonathan Franzen's new novel, Freedom, was his use of David Foster Wallace-style intrafamily dialog. [spoiler alert] This scene, where Patty's father discourages her to involve the police in her rape, echoes the scene in Infinite Jest where Hal identifies his father as the "professional conversationalist", or the late night phone calls between Hal and Orin:  

"Coach Nagel says I should go to the police."

"Coach Nagel should stick to her dribbling," her dad said.

"Softball," Patty said. "It's softball season now."

"Unless you want to spend your entire senior year being publicly humiliated."

"Basketball is in the winter. Softball is in the spring, when the weather's warmer?"

"I'm asking you: is that really how you want to spend your senior year?"

"Coach Carver is basketball," Patty said. "Coach Nagel is softball. Are you getting this?"

Her dad started the engine. 

I enjoy this pattern, but not quite enough to justify reading the whole book. 

Another DFW-esque trick is the foreshadowing that never amounts to much, as in Freedom's opening sentence: 

The news about Walter Berglund wasn't picked up locally. [...] Walter had made quite a mess of his professional life out there in the nation's capital... [He is] in trouble now for conniving the with the coal industry and mistreating country people. 

When I read this, I was hoping that the rest of the book would emerge as the story of Walter's descent from environmentalist to corrupt crony, but Franzen pulls his punches. What could have been the climax of the plot, when precociously independent Joey calls his father for help in the middle of an arms-trading fiasco, is instead handled almost off-screen. The difference here is that DFW's foreshadowing -- of Hal and Don Gately digging up Incandenza père's head -- actually is the climax of multiple plots finally intertwining. Walter's scandal, however, sounds as a disappointing minor note in what could have been the unifying story line. Franzen could have used the scandal to show how all of this freedom led the main characters to betray their deepest beliefs, but he made it just another episode in a long novel that ultimately lacks a climax. 

Java foreach loops on empty collections

I've been worrying about whether I need to check for null when invoking a foreach loop on a collection that might be empty. The answer is, nope, I don't need to check for an empty list; java just Does The Right Thing.

List<Object> list = new ArrayList<Object>();
logger.info("here's a list that was always empty: " + list.toString());
for (Object o: list) {
logger.info("here's an object: " + o.toString());
}
logger.info("done");

...yields this output:
INFO: here's a list that was always empty: []
INFO: done

These alternate ways of expressing the same loop also all execute without a problem, even for an empty list:

for (int i = 0; i < list.size(); i++) {
Object o = list.get(i);
logger.info("here's an object: " + o.toString());
}
for (int i = 0; i < list.size(); i++) {
Object o = list.get(i);
logger.info("here's an object: " + o.toString());
}

That's just a detail that's been bugging me, and now I understand the behavior. For what it's worth, I couldn't find this issue addressed in the JSR.

graphical diff for git on mac os x

I just configured git to use FileMerge for diffs. FileMerge is a pretty graphical diff tool. I couldn't find quite the right invocation via google, so here's what I did:


  1. Create ~/bin/git-diff-driver.sh with these contents:
    #!/bin/sh
    /usr/bin/opendiff "$2" "$5"

  2. Make it executable
    chmod ugo+x ~/bin/git-diff-driver.sh


  3. Make git use this little script for diffs. Edit ~/.gitconfig to include these lines:
    [diff] 
    external = "/Users/ben/bin/git-diff-driver.sh"


Now the next time that you call git diff HEAD FileMerge will open. GUI sweetness.

missing out on flex?

Last week I finally started using an AIR application, TweetDeck, because my brother said it was cool. Now I'm reading about Flex and AIR, and I have to say, I might have been missing out on a good thing. It looks to me like Flex and AIR are together a powerful front-end platform for building nice applications... where by nice I mean the things that Ben Shine traditionally loves: smooth, swoopy, delicate, rounded, subtle, surprising, shiny.
This bears investigation.

what's running on port 8080?

I learned an important new unix command today: lsof. The name seems to stand for "list open files." The purpose of the command is to list information about the process who has opened a file. In unix-y OS's, sockets are file-ish, so lsof -i :8080 lists the process who opened the file named port 8080 on localhost, where ":8080" is interpreted as the address of a network file.
In my case, I traced the rogue 8080 to an instance of tomcat being started up by ~/Library/Caches/IntelliJIDEA70/tomcat_Unnamed_adomainahexid. I could tell from the domain name that this was a tomcat that I was developing with four months ago. Ouch.
I don't know why it was starting at system startup, but I'm not in the mood to dork around (anymore than I have already), so I rm -rf'd the cache directory and moved the tomcat install to apache-tomcat-6.0.18-hideme. It's gone now.

something else to hate about outlook 2003

When I reply to an email in Outlook 2003, the display of the original email in my inbox updates with the helpful annotation, "You replied on 2/6/2009 at 2:41 PM." That's fine.
What sucks, though, is that Outlook applies that annotation before I've actually sent the reply. There's a time period when I'm composing the reply during which Outlook claims that I've sent a reply to a message, but I I haven't actually replied yet.
Ways in which this might be disastrous are left as an exercise to the reader.

o glorious patterns (of enterprise application architecture)

Two years ago, I started reading Martin Fowler's book, Patterns of Enterprise Application Architecture, on the recommendation of Adam Wolff, whose technical acumen I respect deeply. My first few times attempting the the book, the pages seemed to be made of a soporific variety of lead. I understood the words and the sentences and the paragraphs, but couldn't summon any interest in them.
Today at work, I somehow signed up to give an introductory talk on design patterns, so I went looking for my copy of the Gang of Four. I couldn't find it, but I did find PEAA. I opened the cover and found a list of The Most Amazing Things Ever. Four patterns describing ways to represent complex class hierarchies in databases! Two different patterns for storing session state! Query objects! Remote facade! Value object! Service stub! Finally, here was a vocabulary for the architectural problems that have challenged and puzzled me for the last two years! O glorious book! Just reading the inside front cover has crystallized hours of design discussions and a comparative analysis of a dozen web application frameworks. This is beautiful stuff!
Now I see why Adam was so excited about PEAA two years ago, and why I wasn't, and why I am now. If you're not building enterprise applications, there's no reason to care about the patterns. Studying them is dry and, joyless. If you are building enterprise applications, you spend your best moments thinking about the issues addressed by these patterns. If you're lucky enough to work with other people -- and really, who builds an enterprise app alone? -- then you spend hours each day talking about these issues. Beautiful, beautiful, glorious book!

SOLUTION for "Rails requires RubyGems >= 1.3.1" problem

If you don't care about running Rails 2.2, you can safely ignore this post. If you ran into the same problem I did, this post will help you solve it.
I'm running Aptana Studio 1.2.1 with RadRails 1.0.0, and I'm creating a new Rails project using Rails 2.2.2. The wizard for a new RadRails project seemed to basically work, but it failed on starting the rails server with this error message: "Rails requires RubyGems >= 1.3.1 (you have 1.2.0). Please `gem update --system` and try again." I tried that several times and it didn't work. Some googling revealed a solution, but the solution isn't quite spelled out in n00b-friendly language. (cwilliams on the aptana support site does the best job yet, though) So here we go.
Prologue: A lecture from your friendly sysadmin. Never run commands that start with "su" if you don't know what they mean.
Body: (much cribbed from cwilliams again)

[ben@pro ~]$ sudo gem update rails   # get the latest version of rails
[ben@pro ~]$ sudo gem update --system # update the RubyGems system software
[ben@pro ~]$ gem install linecache # install the "linecache" gem

linecache is a requirement of RadRails that isn't listed in the requirements.
[ben@pro ~]$ ruby -S gem --version
1.2.0

That tells me that I've got version 1.2.0 of gem installed. Gem is ruby's package manager. So let's install a gem whose purpose is to update the gem system. This is a little complicated, but it works:
[ben@pro ~]$ sudo ruby -S gem install rubygems-update 
Password:
Successfully installed rubygems-update-1.3.1
1 gem installed

Good. Now run the script that updates rubygems...

[ben@pro ~]$ sudo ruby -S update_rubygems
Installing RubyGems 1.3.1
mkdir -p /Library/Ruby/Site/1.8
mkdir -p /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin
...

At the end of the output of the update_rubygems command, you'll see a long message from the RubyGems team. I'm pretty sure you can safely ignore it. Make sure you have the right version of gem installed now:
[ben@pro ~]$ ruby -S gem --version
1.3.1

Good. Now go back to Aptana and start your Rails server again: Window -> Show Views -> Servers. Right-click on the server named <project>Server. Select "Start server in debug mode" from the context menu. The status of the server should switch to "Starting." Right click on the server name again; select "Open Console/Shell." This should show a lovely shell whose output ends with
** Mongrel 1.1.4 available at 127.0.0.1:3001
** Use CTRL-C to stop.

Don't be frightened that all that text is in red. You're good, you're golden; rails is up and running.

two firsts

One, I wrote code with GOTOs. I'm setting up a highly constrained dev environment for my current contract. It has to be Windows XP, and it can't use cygwin. There are at least two different builds I have to run: one uses ant 1.6.5 and a vendor-specific implementation of jdk 1.4.2; the other uses Sun's jdk 1.4.2 and ant 1.7.0. In bash land, I'd just write a setup-foo.sh script and be done with it. In pure-windows windows, that's not going to fly. (Even if I could use cygwin or mingw, ant command-line parameters in cmd.exe get really messy when invoked from bash. You can only do backtick cygpath -w so many times before going insane.) So, finally, a generation after it was released, I had to learn a little bit of dos scripting. I started with a book called "Microsoft Windows Shell Script Programming for the Absolute Beginner" and I felt like an absolute beginner. How do I express conditional logic? [if cond ( ... ) else ( ... ) actually kind of easier than bash] How do I accept command-line parameters? [%1%, %2%, not unlike bash]. How do I call procedures? OMFG. CALL :SetupFoo. How do I return from procedures? Aiee! GOTO. I got to experience the joy of debugging code with GOTOs without an interactive debugger. Thanks, but no. Props to all of you who lived through that (hi, Pop) but I'm way happier with structured programming. Object-oriented programming, now, that's for the young kids... (Just kidding -- people my age can handle OOP; aspect-oriented programming is for the young kids.)
Two, I spontaneously generated a really nice roast chicken recipe. Occasional post-workout brunches at Boulette's Larder have encouraged me to experiment with embarassing amounts of butter and carmelized onions. Spud has been delivering a frozen organic bone-in chicken breast each week, and they were stacking up in my freezer; plus Trader Joe's had some really cute multicolor pearl onions. And there are insane cranberry sauces everywhere these days; I went with one from Bi-Rite that included apples and ginger. Combine that with my housemate's well-seasoned cast iron pan and a gas oven... Mmm. Yummies.

aptana studio upgrades the IDE paradigm

Aptana Studio is a sweet little IDE, but it gets even sweeter now that they've added in Jaxer and Cloud.
My development life has been veering away from Java and towards JavaScript lately. I'd been coding in IntelliJ IDEA 7.04. It's got intense suites of features for java web development. IntelliJ IDEA 7 is pretty darn nice for javascript, css, and html; until Wednesday, it was my editor of choice. (Version 8 has added some promising javascript support, but I haven't upgraded yet.)

But Aptana Studio has delivered a game-changer: the IDE provides integrated deployment to cloud servers. This is sick, sick, sick. Usually, in order to make a web site available publicly, a developer has to sign up with a hosting provider, register a domain, point DNS to the right name servers, configure Apache, and upload files to the right place, configure Apache some more, etc. That's not rocket science, but it's not what I want to spend my time doing. I want to sit down in the morning and have a proof-of-concept site running by midnight. (Registering a domain and provisioning a site usually takes at least 24 hours.)

Aptana Studio delivered my one-day web 2.0 proof-of-concept deployment goal. Here's how!

  1. Aptana provides a virtual hosting service, Aptana Cloud.
  2. I can sign up for and provision a cloud server from within Aptana Studio; they've got a brilliant 21-day-free-trial for a cloud server.
  3. Standard stuff I'd expect from a virtual hosting provider: Aptana gives me a subdomain, name of my choice, and handles routing. At install time, I can choose which servers I wan to install.
  4. I write some javascript and html code -- pretty standard stuff.
  5. In one operation, inside the IDE, I deploy my site to the cloud. Boom. There it is.
  6. I edit the code. Another cloud sync, and my modified code is running on the remote site.
  7. I can monitor my cloud's logs within the IDE.
Really, that's more like ten minutes -- so I got to spend the rest of the day actually writing code. Which is what I'm going to do now -- my review of Jaxer will have to wait.

a lovely error message

I'm playing with hudson, an extensible continuous integration engine. One of its optional tasks is to archive build artifacts. Using the ant syntax, I told it to archive everything named *.war in the dist directory. When I entered that string into its lovely ajax configuration page, Hudson immediately informed me of a problem:
'dist/**/*.war' doesn't match anything: even 'dist' doesn't exist
The best part of this error message is "even 'dist' doesn't exist."
I could explain what's so cool about this, but if you don't know now, you'll never care, even if I do explain it. If you do see what's cool about it, go check out hudson.

give them what they (say they) want

I feel guilty about walking past a hungry person and not helping them get some food, but I find it hard to believe that everyone claiming to be hungry in downtown San Francisco is only craving nutritional sustenance. An easy solution: when approached by a "hungry" person, I hand them some actual food! I usually carry a snack with a long shelf life in my backpack: a baggie of nuts, a chocolate bar, some dried fruit. So when I'm approached by someone who says they're hungry, I offer them an actual treat looking just as yummy and nutritious as it was on the shelves of Whole Foods.
The reaction I get to such offers is illuminating. An aggressive beggar in the big Westfield mall downtown literally recoiled at the offer of a bag of grape Clif Blox.. Sorry, buddy, but you need detox, not glucose. And yeah: the homeless community knows exactly where to go for free detox services, and they talk about it with more respect and dread than prison. (How do I know? Because I've talked to people who got sober for good after their 15th or 20th time through Ozanam.)
I'm not saying that I can cure poverty or drug addiction or homelessness with a 300 calorie snack. I'm just saying, here's an ethical way to cope with pleas from which our society should not ignore. Give them what they say they want.

"unsubscribe"

One of the best developments in the web this year: one-click unsubscribe links in promotional emails I must have signed up for at some point. Here's the scenario: I get some email from Random Business. I gave Random Business my email two years ago when I was interested in their random thing; I am no longer interested. I want to unsubscribe.
The old way: I'd follow a link in their email to a login screen. If I didn't remember my username and password, which I probably don't since it's been a while, I have to go through the forgot-my-password link, wait for email to arrive, then at least log in again, go to my preferences, edit my preferences, then click save and verify that I really want to unsubscribe.
The new way: At the bottom of the promotional email, there's a link that says "Click here to unsubscribe." In the very best implementation, I click on that link and get a page which says, "myemail@mysite.com has been unsubscribed from all Random Business mailings."
This was a very simple technology to put together, and could have been done a decade ago. By focusing on an everyday annoyance felt by most email users, someone was able to vastly improve the user experience. I won't quite say this builds brand loyalty (I am, after all, unsubscribing) but it does decrease lingering annoyance.
Companies with one-click unsubscribe, I salute you!