     for ix in [0...12]
       pitch_number = (ix * 5 + 7) % 12
       root_fingering = pitch_fingers[pitch_number]
+      chord_name = "#{NoteNames[pitch_number]}#{chord.abbr}"
       cell ->
-        ctx.font = '20px Impact'
-        ctx.font = '5pt Times' if draw_diagrams
-        ctx.fillStyle = 'rgb(10,20,30)'
-        ctx.fillText "#{NoteNames[pitch_number]}#{chord.abbr}", h_gutter, -3
         fingerings = []
         for semitones, note_number in chord.offsets
           for {string, fret} in intervals_from(root_fingering, semitones)
             fingerings.push {string, fret, note_number}
         fingerings = best_fingering_for(chord, pitch_number) if best_fingering
-        for f in fingerings
-          f.color = colors[f.note_number]
+        f.color = colors[f.note_number] for f in fingerings
+        ctx.font = '20px Impact'
+        ctx.font = '5pt Times' if draw_diagrams
+        ctx.fillStyle = 'rgb(10,20,30)'
+        ctx.fillText chord_name, h_gutter, -3
         draw_fingerboard fingerings
 
 chord_book = (options) ->
   page_count = options.pages
-  book "Combined Fretboard Chords.pdf", (page) ->
+  book "Combined Fretboard Chords", (page) ->
     for chord, i in Chords
       page -> chord_page chord, options
       break if page_count and i + 1 >= page_count

  draw_book (draw_page) ->
    draw_page()
    ctx.addPage()
  fs.writeFile BuildDirectory + filename, canvas.toBuffer()


#

  closed_medial_strings = (fs) ->
    string_frets = (-1 for s in StringNumbers)
    string_frets[f.string - 1] = f.fret for f in fs
    p = ((if x >= 0 then x else 'x') for x in string_frets).join('')
    return p.match(/\dx+\d/)

  closed_treble_strings = (fs) ->
    string_frets = (-1 for s in StringNumbers)
    string_frets[f.string - 1] = f.fret for f in fs
    p = ((if x >= 0 then x else 'x') for x in string_frets).reverse().join('')
    return p.match(/x$/)

  finger_count = (fs) ->
    (f for f in fs when f.fret).length

  high_note_count = (fs) -> -fs.length

  is_first_position = (fs) ->
    _(fs).sortBy((f) -> -f.string)[0].note_number == 0

  cmp = (fn) -> (x...) -> !fn(x...)

  filters = [
    {name: 'has all chord notes', filter: has_all_notes},
    {name: 'no muted medial strings', filter: cmp(closed_medial_strings)},
    {name: 'no muted treble strings', filter: cmp(closed_treble_strings)}
  ]

  sorts = [
    finger_count,
    high_note_count,
    cmp(is_first_position)
  ]

  chord_name = "#{NoteNames[root_note % 12]}#{chord.abbr}"
  choices = compute_choices(frets_per_string)
  for {name, filter} in filters
    filtered = (choice for choice in choices when filter(choice))
    unless filtered.length
      console.error "#{chord_name}: fatal filter #{name}"
      filtered = choices
    choices = filtered
  for sort in sorts
    choices = _(choices).sortBy(sort)
  # for choice in choices
  #   console.info finger_count(choice)
  return choices

best_fingering_for = (chord, root_note) ->
