docs: function parseList(body) {
    const $ = cheerio.load(body)
  
    // currying of a function that parses a <td> with an icelandic number as a JS Number
    // used for the fieldsParser below
    const numberField = function (i) {
      return function ($children) {
        return +$children.eq(i).text().replace(',', '.')
      }
    }
  
    // for each row, all of this object's functions will be called to popoulate each
    // key in the generated object - they are all passed in the full array of
    // children (which are the cheerioed <td>s)
    const fieldsParser = {
      timestamp: ($children) => {
        // the fields are in this format: <td><a href>2015-12-30</a></td><td>21:31:24,0</td>
        const date = `${$children.eq(0).text()} ${$children.eq(1).text()}`
        return new Date(date.split(',')[0])
      },
      latitude: numberField(2),
      longitude: numberField(3),
      depth: numberField(4),
      size: numberField(5),
      quality: numberField(6),
      humanReadableLocation: ($children) => {
        // these are three <td> elements' text values combined.. there migth be a
        // cleaner way to do this, but I don't know how.
        const strObj = $children.slice(7, 10).map(function () {
          return $(this).text()
        })
        return Array.prototype.join.call(strObj, ' ').replace(/^\s*|\s*$/g, '')
      },
    }
  
    // This finds all the table rows in the list, except the first row, which
    // is a header row.
    const data = []
  
    $('table').eq(2).find('tr').slice(1)
      .map(function () {
        const $children = $(this).children()
        const obj = {}
        for (const key in fieldsParser) {
          if (fieldsParser.hasOwnProperty(key)) {
            obj[key] = fieldsParser[key]($children)
          }
        }
        data.push(obj)
        return obj
      })
  
    return data
  }