docs: def _get_read_names(self, search_result, max_range):
          '''
          _get_read_names - loops through hmm hits and their alignment spans to
          determine if they are potentially linked (for example, if one gene in a 
          contig hits a hmm more than once, in two different conserved regions
          of that gene) and combines them into one 'hit' because they are
          technically the same. The total span of the hits deemed to be linked is
          returned.
  
          Parameters
          ----------
          search_result : obj
              SequenceSearchResult object with all paramaters defined. Used here
              to create rows containing information on alignment direction and
              alignment span.
          max_range : int
              Maximum range that a gene can extend within a contig. Any hits
              that extend beyond this length cannot be linked. max_range is
              set as 1.5 X the average length of all full length genes used
              in the search database. This is defined in the CONTENTS.json file
              within a gpkg.
          Returns
          -------
              Dictionary where keys are the contig/read name. The value for each
              entry is an array lists, one per hit in each contig, each with the
              span (min and max) of the alignment.
          '''
  
          splits = {}  # Define an output dictionary to be filled
          spans = []
          for result in search_result:  # Create a table (list of rows contain span, and complement information
              spans += list(
                           result.each(
                                      [SequenceSearchResult.QUERY_ID_FIELD,
                                          SequenceSearchResult.ALIGNMENT_DIRECTION,
                                          SequenceSearchResult.HIT_FROM_FIELD,
                                          SequenceSearchResult.HIT_TO_FIELD,
                                          SequenceSearchResult.QUERY_FROM_FIELD,
                                          SequenceSearchResult.QUERY_TO_FIELD]
                                         )
                           )
  
          for hit in spans:  # For each of these rows (i.e. hits)
              i = hit[0]  # set id to i
              c = hit[1]  # set complement to c
              ft = [min(hit[2:4]), max(hit[2:4])]  # set span as ft (i.e. from - to) - This is the amount covering the query
              qs = [min(hit[4:6]), max(hit[4:6])]  # seq the query span to qs - This is the amount covering the HMM
  
              if ft[0] == ft[1]: continue  # if the span covers none of the query, skip that entry (seen this before)
  
              if i not in splits:  # If the hit hasnt been seen yet
                  splits[i] = {'span'       : [ft],
                               'strand'     : [c],
                               'query_span' : [qs]}  # add the span and complement as new entry
  
              else:  # otherwise (if it has been seen)
                  for idx, entry in enumerate(splits[i]['span']):  # for each previously added entry
                      if splits[i]['strand'][idx] != c:  # If the hit is on the same complement strand
                          splits[i]['span'].append(ft)  # Add the new range to be split out in the future
                          splits[i]['strand'].append(c)  # Add the complement strand as well
                          splits[i]['query_span'].append(qs)
                          break
  
                      previous_qs      = splits[i]['query_span'][idx] # Get the query span of the previous hit
  
                      previous_q_range = set(range(previous_qs[0], previous_qs[1])) # Get the range of each
                      current_q_range  = set(range(qs[0], qs[1]))
                      query_overlap    = set(previous_q_range).intersection(current_q_range) # Find the intersection between the two ranges
  
                      previous_ft_span = set(range(entry[0], entry[1]))
                      current_ft_span  = set(range(ft[0], ft[1]))
                      if any(query_overlap): # If there is an overlap
                          ####################################################
                          # if the span over the actual read that hit the HMM
                          # for each hit overlap by > 25%, they are considered
                          # the same hit, and ignored
                          ####################################################
                          intersection_fraction = float(len(previous_ft_span.intersection(current_ft_span)))
  
                          if intersection_fraction / float(len(previous_ft_span)) >= PREVIOUS_SPAN_CUTOFF:
                              break
                          elif intersection_fraction / float(len(current_ft_span)) >= PREVIOUS_SPAN_CUTOFF:
                              break
                          else: # else (i.e. if the hit covers less that 25% of the sequence of the previous hit)
                              ####################################################
                              # If they made it this far, it means that the hits do not overlap.
                              # But one last check must be made to ensure they do not cover the same
                              # region in the HMM.
                              ####################################################
                              if len(query_overlap) > (len(current_q_range)*PREVIOUS_SPAN_CUTOFF): # if the overlap on the query HMM does not span over 25%
                                  if (idx+1) == len(splits[i]['span']):
                                      splits[i]['span'].append(ft) # Add from-to as another entry, this is another hit.
                                      splits[i]['strand'].append(c) # Add strand info as well
                                      splits[i]['query_span'].append(qs)
                                      break # And break
  
                      if min(entry) < min(ft):  # if/else to determine which entry comes first (e.g. 1-5, 6-10 not 6-10, 1-5)
                          if max(ft) - min(entry) < max_range:  # Check if they lie within range of eachother
                              entry[1] = max(ft)  # ammend the entry if they are
                              break  # And break the loop
                      else:
                          if max(entry) - min(ft) < max_range:  # Check if they lie within range of eachother
                              entry[0] = min(ft)  # ammend the entry if they are
                              break  # And break the loop
  
                  else:  # if no break occured (no overlap)
                      splits[i]['span'].append(ft)  # Add the new range to be split out in the future
                      splits[i]['strand'].append(c)  # Add the complement strand as well
                      splits[i]['query_span'].append(qs)
          return {key: {"entry":entry['span'], 'strand': entry['strand']} for key, entry in splits.iteritems()}