The American tropics

The New York Times provides a visualization of the steady Northern march of extreme heat due to global warming. By 2060, much of the country will experience 20+ days a year above 100º F.

By the end of the century, that will expand to include almost the entire country except for Northern coastal areas, the West coast and the high Rockies.

It's easy to see this as a map of where not to live. It must also be a call to action. Unfortunately, it feels like we are slipping past the point of no return. The feedback cycles are already in motion. Even with massive cuts in carbon emissions, radical geoengineering may be our only option to preserve the climate our species has prospered in for the last 50,000 years.

— August 23, 2016

Adding a command to list recently changed git branches (three ways)

I wanted to add a command to make it easy for me to see what branches I'd worked on recently. Between different projects, bugfixes, and code reviews, I end up switching branches a lot, and it can be hard to remember the names of the branches I need to polish up for submitting as a pull request and merging. It's also useful to find branches that can be deleted.

This is a git command to show all the branches sorted by date descending (branch names may be changed to protect the innocent):

git for-each-ref --sort -committerdate refs/heads/

1b46ebacca9d6a4f49698b59577e21254471f6ac commit refs/heads/look/fp-email-on-first-completion
875686cd2b9db4fe45b24a96299f71933f6599fa commit refs/heads/master
9ef1d512fcc6e05dc5b80121e1e3768c011bb167 commit refs/heads/look/document-position-metadata
ed6df9b73e2c38d74ee3419c71ee488703c8cb27 commit refs/heads/look/fix-dp-500
7b130aceaeafe31077265b6a1b7cdabd1f8329d4 commit refs/heads/look/improve-document-position-caching
fcb726b5372255a3b1c50eac1c04cf5eda4587d4 commit refs/heads/look/remove-rails-4-caching-hacks
bd1f3df97cfd3dcbe9803770fd24944bed01f236 commit refs/heads/look/remove-rails-3-code
9b6bc693e5273cf3a7ddea1062462ae333c1bb6a commit refs/heads/look/fix-selenium-rails-4
c231b29f083b14d7cdb698e8f4d2be105bc32e45 commit refs/heads/look/fix-account-router
8d16a3868f8a12961ee8dbcaa383fae7a10ebcd8 commit refs/heads/look/handle-invalid-content-hash
fe50ecee84e6017dfa444bb426c4ac7c9929fa50 commit refs/heads/look/unknown-format-rails-4
3bfe056947a351151d0e3cf18a61f30e9e03209b commit refs/heads/look/pluck
e903be6d8f2a2a170d913b5e77801600ec49023d commit refs/heads/look/match-array
bb07270a5045c737f60530ca1d3b8b17e2cdf7bb commit refs/heads/look/fix-change-column
bca2a817b32395576fe2c10be53b02022689ba75 commit refs/heads/look/rails-4-fixes
70c6e053c89e066f1eed0038faa1834ca255b4d4 commit refs/heads/look/GET_LOCK-sucks
07176fb95a802a3ca5dfcce5d3757d9831ef7d52 commit refs/heads/look/refactor-query-execution
5cb599fc57c7729ea8ed76f62ccd930b774a4d9c commit refs/heads/engine_index_refactor
(... dozens of branches omitted ...)

Adding a bit of formatting makes and piping to head makes the output easier to read:

git for-each-ref --format='%(committerdate:iso8601) %(committerdate:relative) %(refname)' --sort -committerdate refs/heads/ | head -15    

2016-08-04 17:59:50 -0700 4 days ago refs/heads/look/fp-email-on-first-completion
2016-08-04 17:24:34 -0700 4 days ago refs/heads/master
2016-08-04 15:02:23 -0700 4 days ago refs/heads/look/document-position-metadata
2016-08-02 13:27:42 -0700 6 days ago refs/heads/look/fix-dp-500
2016-07-28 12:24:30 -0700 11 days ago refs/heads/look/improve-document-position-caching
2016-07-19 19:55:07 -0700 3 weeks ago refs/heads/look/remove-rails-4-caching-hacks
2016-07-19 18:45:06 -0700 3 weeks ago refs/heads/look/remove-rails-3-code
2016-07-19 18:07:56 -0700 3 weeks ago refs/heads/look/fix-selenium-rails-4
2016-07-19 15:03:15 -0700 3 weeks ago refs/heads/look/fix-account-router
2016-07-18 17:36:24 -0700 3 weeks ago refs/heads/look/handle-invalid-content-hash
2016-06-30 18:49:33 -0700 6 weeks ago refs/heads/look/unknown-format-rails-4
2016-06-29 19:18:17 -0700 6 weeks ago refs/heads/look/pluck
2016-06-29 19:17:18 -0700 6 weeks ago refs/heads/look/match-array
2016-06-29 11:17:49 -0700 6 weeks ago refs/heads/look/fix-change-column
2016-06-21 14:36:50 -0700 7 weeks ago refs/heads/look/rails-4-fixes

This is a lot of typing, though! The easiest way to shorten it is to create a Bash alias:

alias grecent="git for-each-ref --format='%(committerdate:iso8601) %(committerdate:relative) %(refname)' --sort -committerdate refs/heads/ | head -15"

However, I wanted to make this a new subcommand, because I have trouble remembering to use Bash aliases.

The first thing I looked into was using a Bash function:

function git() {
    if [[ $@ == 'recent' ]]; then
        command git for-each-ref --format='%(committerdate:iso8601) %(committerdate:relative) %(refname)' --sort -committerdate refs/heads/ | head -15
        command git "$@"

This intercepts invocation of the git command. If the argument is recent, it runs my command. Otherwise, it passes the arguments to the git command (the Bash command builtin is used so it can call the real git). One thing I learned writing this is that getting the quoting right is super important.

That's not the only way to do it, though!

You can also add a git alias. Since this version doesn't take an argument, that's fairly simple:

        recent = !git for-each-ref --format='%(committerdate:iso8601) %(committerdate:relative) %(refname)' --sort -committerdate refs/heads/ | head -15

Because I only want to show some of the recent items, I need to invoke the alias as a shell command using ! so I can use head. You can also add arguments to git aliases, but it is a bit more complicated.

Another way is to add a new executable named git-recent to your $PATH (Antonio Santos Velasco has a good tutorial about this.). This will enable you to type git recent to invoke it. I have a ~/bin directory that is on my path, so that is a pretty easy place to stash such a command. If you want to add argument parsing (for example, to change the default number of recent items), using a stand-alone script is probably the easiest way.

Here's the full git-recent script:



git for-each-ref --format='%(committerdate:iso8601) %(committerdate:relative) %(refname)' --sort -committerdate refs/heads/ | head -$ITEMS

You can invoke it like this to get the default number of recent branches:

git recent

Or specify the number of branches:

git recent 10

Now that I have an easy way of listing recently changed branches, I use it constantly. It's been super useful for me. Maybe it will be for you, too.

— August 15, 2016

Fighting the future

Growing government budget deficits of around the globe have resulted in no small part from insistent demands from top earners for tax cuts. Some have advocated such cuts as part of a "starve the beast strategy," in which depriving the government of revenue would supposedly help eliminate government waste. But government programs exist because important constituents want them and are therefore extremely difficult to cut. Cuts, when they do come, typically occur not where they would make the most sense, but where those who would suffer from them are least able to push back. An important result of deficits has thus been to reduce our investment in the future. The unborn citizens who will suffer as a result are simply unable to protest.

-- Robert H. Frank, Success and Luck

This is a simple explanation for many of the United States' problems, from disinvestment in infrastructure which squanders the inheritance that we received from our predecessors to closing off our most productive cities to new residents through restrictive housing policy. It's easy to fight the future, because future citizens can't vote.

— August 14, 2016

Ignoring files in git without cluttering up history

If you are like me, you have a couple scratch files lying around in your repository. They don't have anything to do with the project and aren't relevant to the other members of my team, so I don't want to add them to .gitignore.

The usual outcome of this is selectively committing and trying to avoid checking in these extraneous files. However, I recently learned that there is a git configuration file called .git/info/exclude you can modify to ignore files. It's like .gitignore, but not checked in.

Here's an example:

# git ls-files --others --exclude-from=.git/info/exclude
# Lines that start with '#' are comments.
# For a project mostly in C, the following would be a good set of
# exclude patterns (uncomment them if you want to use them):
# *.[oa]
# *~

This is mentioned in the gitignore documentation and with more context by GitHub.

— August 6, 2016

How “Silicon Valley” Nails Silicon Valley

If Washington, D.C. is Hollywood for ugly people then Silicon Valley must be Hollywood for nerds. This article shows how desperate many of those nerds are to be part of a cultural moment, and how frustrated they can be when their Valley-famous bubble is burst by actual fame.

“Some Valley big shots have no idea how to react to the show,” [T. J.] Miller told me. “They can’t decide whether to be offended or flattered. And they’re mystified by the fact that actors have a kind of celebrity that they will never have—there’s no rhyme or reason to it, but that’s the way it is, and it kills them.” Miller met Musk at the after-party in Redwood City. “I think he was thrown by the fact that I wasn’t being sycophantic—which I couldn’t be, because I didn’t realize who he was at the time. He said, ‘I have some advice for your show,’ and I went, ‘No thanks, we don’t need any advice,’ which threw him even more. And then, while we’re talking, some woman comes up and says ‘Can I have a picture?’ and he starts to pose—it was kinda sad, honestly—and instead she hands the camera to him and starts to pose with me. It was, like, Sorry, dude, I know you’re a big deal—and, in his case, he actually is a big deal—but I’m the guy from ‘Yogi Bear 3-D,’ and apparently that’s who she wants a picture with.”

— July 16, 2016

Take it from me: Your local library needs a cat

Yes, yes it does.

— July 14, 2016

Displaying Emoji in git log

tl;dr: Upgrade less to a more recent version to see emoji in git log.

If you've ever seen a git commit message that included emoji, you may have noticed it doesn't display correctly when you use git log:

$ git log
commit bad43bf2d75cc0c75f0d2731a9c9672adfa01160
Author: Luke Francl <>
Date:   Sun Jun 19 09:40:49 2016 -0700

    First commit! <U+1F389>

Recently, I decided to try to figure this out. The first thing I noticed is that if you set --no-pager the emoji is displayed correctly:

$ git --no-pager log
commit bad43bf2d75cc0c75f0d2731a9c9672adfa01160
Author: Luke Francl <>
Date:   Sun Jun 19 09:40:49 2016 -0700

    First commit! 🎉

Git's pager defaults to less. I tried displaying the same emoji with less:

$ echo "🎉" | less

I found a post on Stack Overflow that said to set the LESSCHARSET environment variable to "utf-8". However, that didn't fix the problem:

$ echo "🎉" | LESSCHARSET=utf-8 less

Other characters work, though, like the Euro symbol used on Stack Overflow:

$ echo "€" | less

I don't even need LESSCHARSET because it turns out my locale is set for UTF-8 already:

$ locale

This made me wonder if I could upgrade less (or in more desperate straits, fix the code). I found the source at the less home page and noticed that the version that came installed with OS X (er, macOS) was very out of date. I had version 458 and the current version is 481. I downloaded and compiled version 481 and it was able to display emoji!

The easiest way to get less version 481 on OS X is to use homebrew's dupes repository:

$ brew install homebrew/dupes/less

After installing, make sure you're actually using version 481:

$ less --version
less 481 (POSIX regular expressions)
Copyright (C) 1984-2015  Mark Nudelman

You can force Bash to re-hash the location of less by executing hash -r, or open a new terminal.

Now, you should be able to see your log messages in their full emoji glory!

— June 19, 2016

Faced With Today's NIMBYs, What Would Jane Jacobs Do?

Janette Sadik-Khan and Seth Solomonow argue that to complete Jane Jacobs's urban vision, we must overcome community objections to change:

We should honor Jacobs’s memory today by redesigning our cities as she might have. It’s not just a matter of livability or quality of life, but a long-term strategy for a denser urban future, one that is environmentally rational and economically vital....

But the process to fulfill Jacobs’s vision may require revolutionary action instead of a merely evolutionary course. As city leaders attempt to adapt their cities for the future, they must face down passionate resistance from residents who perversely invoke Jane Jacobs and cite environmentalism, safety, local economics, and community autonomy not merely to oppose out-of-scale mega-projects, but to defeat proposals that Jacobs herself may have supported. Known as NIMBYs (Not In My Back Yard), local residents at official city meetings reliably oppose dense new housing, new public space, bike lanes, or redesigned streets to combat dangerous driving. By using Jane-Jacobs-like language of neighborhood preservation as a decoy to oppose Jane-Jacobs-like projects, many communities are effectively fighting to keep streets exactly the way that Robert Moses left them....

The impact of this NIMBYism doesn’t end with a defeated apartment building or bike lane. Opposing dense, accessible neighborhoods pushes residential development into ever-expanding suburbs and shrinking greenbelts around cities. The fight to leave our streets as they are condemns our nation to a sprawling future, longer and more congested commutes, and escalating infrastructure costs that combine for a $1 trillion drag on the national economy.

Would Jacobs support this? Maybe, maybe not. She has been claimed both by pro-development urbanists and NIMBYs, and has been called out by some as a NIMBY herself. Her legacy lives on in community groups which have both stopped freeways and keep them up. She had some personal experience as a developer and the results were widely panned. Perhaps this taught her about the compromises necessary in development? She also helped create the zoning that infilled the King-Spadina and King-Parliament areas in Toronto:

The results have been breathtaking — and might surprise those for whom Jane is a hero for stopping bulldozers. Not only have the “Two Kings” not lost jobs, as many industrial lands taken out of production have, but the number of jobs has increased by 58%. Even more impressively, 46,000 dwelling units have been permitted in the Two Kings, many of them in very large new high-rises.

The truth is that sometimes stopping development is the right thing. Everyone is glad that the Golden Gate freeway was stopped and that Marincello never despoiled the Marin Headlands. But making our cities better will require repairing them, and that means new development, and it should follow the urban template that Jane Jacobs described so well.

— May 8, 2016

Frog and Toad are Co-Founders

Frog and Toad was one of my favorite books as a child. Now, they are "all grown up and working in San Francisco" as co-founders. The parody is really well done. It captures the current silliness of Silicon Valley in a pitch-perfect imitation of the original stories' style.

Speaking of Frog and Toad, I recently saw an exhibition of Arnold Lobel's work at the Contemporary Jewish Museum. It made me aware of some of the other things he worked on, including the cat-based Whiskers & Rhymes which seems right up my alley.

— April 10, 2016

My favorite books of 2015

We're a quarter of the way into the new year, so it's about par for the course to get my list of books read from the previous year up. Last year I didn't read as much as I have lately. There's one good reason for that, but it's not the only one. Besides chewing off some long books, also abandoned more books last year. I think I am getting pickier.

Here's a few books that stood out last year:

Book Cover

Unbroken: A World War II Story of Survival, Resilience, and Redemption, Laura Hillenbrand

Louis Zamperini story is almost unbelievable. After his Olympic dreams are ruined by the onset of World War II, he became a bomber crewman in the Pacific theater. He survived ditching the Pacific, then 47 days adrift without food or water. Rescued by the Japanese, he then survived the rest of the war in burtal conditions in Japanese POW camps. The book continues after the war, revealing Zamperini's struggle to come to terms with his experience.

Book Cover

The Adjacent, Christopher Priest

This interwoven story of love and war across "adjacent" timelines reminds me of Cloud Atlas by a better writer. This is the only book that has ever gotten me to make a spreadsheet to better appreciate it.

The Adjacent brings in many of Christopher Priest's interests including alternative history and magic as well as his Dream Archipelago setting, which I have not read. I enjoyed the book regardless, but it would probably be more rewarding if you're familiar with his work (I had only read two of his books previously.)

Book Cover

The Thrilling Adventures of Lovelace and Babbage: The (Mostly) True Story of the First Computer, Sydney Padua

Charles Babbage's Analytical Engine is one of the great what-ifs of history, and Ada Lovelace is known as the "first computer programmer". The reality is more complicated, and this wonderfully drawn graphic novel with loads of footnotes and selections from primary source documents lays out the evidence in a fun, entertaining way. You can get a taste of the book on the author's website.

Book Cover

Honorable mention: The Water Knife, Paolo Bacigalupi

Bacigalupi latest entry in the eco-dystopia genre feels brutally real as the states in the American Southwest squabble over the dwindling supply of the Colorado River and regular people are caught in the crossfire. I can't wholeheartedly recommend it because I thought the violence was completely gratuitous. The best part about this book is it led me to read Cadillac Desert.

And here's the complete list of books I read in 2015:

The Life-Changing Magic of Tidying Up: the Japanese Art of Decluttering and Organizing, Marie Kondo

Ancillary Sword, Ann Leckie

Unbroken: A World War II Story of Survival, Resilience, and Redemption, Laura Hillenbrand

A Place of Greater Safety, Hilary Mantel

The Rise and Fall of the Great Powers: Economic Change and Military Conflict from 1500 to 2000, Paul Kennedy

Our Man in Havanna, Graham Greene

Bringing Up Bébé: One American Mother Discovers the Wisdom of French Parenting, Pamela Bruckerman

The Door Into Summer, Robert A. Heinlein

Corporate Confidential: 50 Secrets Your Company Doesn't Want You to Know -- And What to Do About Them, Cynthia Shapiro

Revolt in 2100, Robert A. Heinlein

The Reluctant Father, Phillip Toledano

The Right Stuff, Tom Wolfe

Season of the Witch: Enchantment, Terror, and Deliverance in the City of Love, David Talbot

Democracy and Populism: Fear and Hatred, John Lukacs

The Martian, Andy Weir

The Alliance: Managing Talent in the Networked Age, Reid Hoffman, Ben Casnocha, and Chris Yeh

The Adjacent, Christopher Priest

The Absolutely True Diary of a Part-Time Indian, Sherman Alexie

The Water Knife, Paolo Bacigalupi

The Complete Persepolis, Marjane Strapi

Tuf Voyaging, George R. R. Martin

The Thrilling Adventures of Lovelace and Babbage: The (Mostly) True Story of the First Computer, Sydney Padua

Ancillary Mercy, Ann Leckie

The Song Machine: Inside the Hit Factory, John Seabrook

You can also check out lists from previous years: 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, and 2014.

— April 4, 2016