static _getTasksInRange(knownTasks, options) {
    const {type, initialIndex, earliestPossibleTimestamp, latestPossibleTimestamp} = options;

    // We may have overshot a little from last time, so back up to find the real starting index.
    let startIndex = initialIndex;
    while (startIndex > 0) {
      const task = knownTasks[startIndex];
      if (task && task[type] < earliestPossibleTimestamp) break;
      startIndex--;
    }

    /** @type {Array<{startTime: number, endTime: number}>} */
    const matchingTasks = [];
    for (let i = startIndex; i < knownTasks.length; i++) {
      const task = knownTasks[i];
      // Task is before our range of interest, keep looping.
      if (task[type] < earliestPossibleTimestamp) continue;

      // Task is after our range of interest, we're done.
      if (task[type] > latestPossibleTimestamp) {
        return {tasks: matchingTasks, lastIndex: i};
      }

      // Task is in our range of interest, add it to our list.
      matchingTasks.push(task);
    }

    // We went through all tasks before reaching the end of our range.
    return {tasks: matchingTasks, lastIndex: knownTasks.length};
  }
Finds all the tasks that started or ended (depending on `type`) within the provided time range.
Uses a memory index to remember the place in the array the last invocation left off to avoid
re-traversing the entire array, but note that this index might still be slightly off from the
true start position.

@param {Array<{startTime: number, endTime: number}>} knownTasks
@param {{type: 'startTime'|'endTime', initialIndex: number, earliestPossibleTimestamp: number, latestPossibleTimestamp: number}} options