text: from collections import defaultdict, Counter
  
  def create_index(sequence, k=10):
      """
      Returns index dictionary mapping kmers to a list of positions
      """
      result = defaultdict(list)
      for i in range(len(sequence) - k):
          substring = sequence[i:i + k]
          result[substring].append(i)
      return result
  
  def find_breakpoint(reference, insert, reads, k=10):
      """
      TODO: also look at the reverse complement of each read, since
      they're unlikely to be strand-specific sequences
      """
      reference_index = create_index(reference, k)
      insert_start = insert[:k]
      insert_end = insert[-k:]
      breakpoint_start_weights = Counter()
      breakpoint_end_weights = Counter()
      for read in reads:
          start_offset = read.find(insert_start)
          if start_offset > k:
              # if we had an exact splice then we could just look at the kmer
              # before the insert_start but since there might be random linker
              # segments then we should look at all preceding kmers in the read
              for i in range(start_offset - k + 1):
                  substring = read[i:i + k]
                  if substring in reference_index:
                      reference_positions = reference_index[substring]
                      weight = 1.0 / len(reference_positions)
                      for pos in reference_positions:
                          breakpoint_start_weights[pos] += weight
          end_offset = read.find(insert_end)
          if end_offset > -1 and end_offset + k < len(read):
              for i in range(end_offset + k, len(read)):
                  substring = read[i:i + k]
                  if substring in reference_index:
                      reference_positions = reference_index[substring]
                      weight = 1.0 / len(reference_positions)
                      for pos in reference_positions:
                          # want to be able to compare breakpoint
                          # position hypotheses generated by start
                          # and end of insert, so subtract one from the
                          # position *after* the insert
                          breakpoint_end_weights[pos - 1] += weight
      hypotheses = set(breakpoint_start_weights).intersection(breakpoint_end_weights)
      print(breakpoint_start_weights)
      print(breakpoint_end_weights)
      if len(hypotheses) == 0:
          raise ValueError("Breakpoint could not be detected!")
  
      def score(pos):
          total_start = sum(breakpoint_start_weights.values())
          total_end = sum(breakpoint_end_weights.values())
          normalized_start_score = breakpoint_start_weights[pos] / total_start
          normalized_end_score = breakpoint_end_weights[pos] / total_end
          return normalized_start_score + normalized_end_score
  
      return max(hypotheses, key=score)
  