This is getting long enough that it would be worth extracting into a template file.