docs: def regionsIntersection(s1, s2, collapse=True):
    """
    given two lists of genomic regions with chromosome, start and end
    coordinates, return a new list of regions which is the intersection of those
    two sets. Lists must be sorted by chromosome and start index
  
    :return: new list that represents the intersection of the two input lists.
             output regions will all have name "X", be on strand "+" and have
             score 0
    :param s1: first list of genomic regions
    :param s2: second list of genomic regions
    :raise GenomicIntervalError: if the input regions are not sorted correctly
                                 (by chromosome and start index)
    :note: O(n) time, O(n) space; informally, might use up to 3x space of input
    """
    debug = False
  
    # we don't need to explicitly check for sorting because sorted order is
    # a post-condition of the collapsing function
    s1_c = collapseRegions(s1)
    s2_c = collapseRegions(s2)
  
    if len(s1_c) == 0 or len(s2_c) == 0:
      return []
  
    res = []
    j = 0
    for i in range(0, len(s1_c)):
      if debug:
        sys.stderr.write("processing from s1_c : " + str(s1_c[i]) + "\n")
  
      # find first thing in s2_c with end in or after s1_c[i]
      if debug:
        sys.stderr.write("i = " + str(i) + " and j = " + str(j) + "\n")
      while (j < len(s2_c) and
             (s2_c[j].chrom < s1_c[i].chrom or
             (s2_c[j].chrom == s1_c[i].chrom and s2_c[j].end <= s1_c[i].start))):
        j += 1
      # nothing intersects if we hit the end of s2, or the end of the chrom,
      # or we're still on the same chrom but start after the end of s2_c[i]
      if j >= len(s2_c) or s2_c[j].chrom > s1_c[i].chrom or \
         (s2_c[j].chrom == s1_c[i].chrom and s2_c[j].start >= s1_c[i].end):
        continue
  
      # now everything at or after j in s2_c that starts before
      # the end of s1_c must overlap with it
      while s2_c[j].start < s1_c[i].end:
        s = max(s1_c[i].start, s2_c[j].start)
        e = min(s1_c[i].end, s2_c[j].end)
        overlap = GenomicInterval(s1_c[i].chrom, s, e, "X", 0, "+")
        if debug:
          sys.stderr.write("\tadding to overlaps: " + str(overlap) + "\n")
        res.append(overlap)
        j += 1
        if j >= len(s2_c) or s2_c[j].chrom != s1_c[i].chrom:
          break
  
      # it's possible the last intersecting element runs on to the
      # next element from s1_c, so...
      j -= 1
      if debug:
        sys.stderr.write("\tmoving s2_c index back to " + str(s2_c[j]) + "\n")
  
    return res