def _compute_move_for_insert(self, itag, ii1, ii2, ij1, ij2, imeta):
        # Store some state on the range we'll be working with inside this
        # insert group.
        #
        # i_move_cur is the current location inside the insert group
        # (from ij1 through ij2).
        #
        # i_move_range is the current range of consecutive lines that
        # we'll use for a move. Each line in this range has a
        # corresponding consecutive delete line.
        #
        # r_move_ranges represents deleted move ranges. The key is a
        # string in the form of "{i1}-{i2}-{j1}-{j2}", with those
        # positions taken from the remove group for the line. The value
        # is an instance of MoveRange. The values in MoveRange are used to
        # quickly locate deleted lines we've found that match the inserted
        # lines, so we can assemble ranges later.
        i_move_cur = ij1
        i_move_range = MoveRange(i_move_cur, i_move_cur)
        r_move_ranges = {}  # key -> (start, end, group)
        move_key = None

        is_replace = (itag == 'replace')

        # Loop through every location from ij1 through ij2 - 1 until we've
        # reached the end.
        while i_move_cur < ij2:
            try:
                iline = self.differ.b[i_move_cur].strip()
            except __HOLE__:
                iline = None

            updated_range = False

            if iline and iline in self.removes:
                # The inserted line at this location has a corresponding
                # removed line.
                #
                # If there's already some information on removed line ranges
                # for this particular move block we're processing then we'll
                # update the range.
                #
                # The way we do that is to find each removed line that matches
                # this inserted line, and for each of those find out if there's
                # an existing move range that the found removed line
                # immediately follows. If there is, we update the existing
                # range.
                #
                # If there isn't any move information for this line, we'll
                # simply add it to the move ranges.
                for ri, rgroup, rgroup_index in self.removes.get(iline, []):
                    r_move_range = r_move_ranges.get(move_key)

                    if not r_move_range or ri != r_move_range.end + 1:
                        # We either didn't have a previous range, or this
                        # group didn't immediately follow it, so we need
                        # to start a new one.
                        move_key = '%s-%s-%s-%s' % rgroup[1:5]
                        r_move_range = r_move_ranges.get(move_key)

                    if r_move_range:
                        # If the remove information for the line is next in
                        # the sequence for this calculated move range...
                        if ri == r_move_range.end + 1:
                            # This is part of the current range, so update
                            # the end of the range to include it.
                            r_move_range.end = ri
                            r_move_range.add_group(rgroup, rgroup_index)
                            updated_range = True
                    else:
                        # Check that this isn't a replace line that's just
                        # "replacing" itself (which would happen if it's just
                        # changing whitespace).
                        if not is_replace or i_move_cur - ij1 != ri - ii1:
                            # We don't have any move ranges yet, or we're done
                            # with the existing range, so it's time to build
                            # one based on any removed lines we find that
                            # match the inserted line.
                            r_move_ranges[move_key] = \
                                MoveRange(ri, ri, [(rgroup, rgroup_index)])
                            updated_range = True

                if not updated_range and r_move_ranges:
                    # We didn't find a move range that this line is a part
                    # of, but we do have some existing move ranges stored.
                    #
                    # Given that updated_range is set, we'll be processing
                    # the known move ranges below. We'll actually want to
                    # re-check this line afterward, so that we can start a
                    # new move range after we've finished processing the
                    # current ones.
                    #
                    # To do that, just i_move_cur back by one. That negates
                    # the increment below.
                    i_move_cur -= 1
                    move_key = None
            elif iline == '' and move_key:
                # This is a blank or whitespace-only line, which would not
                # be in the list of removed lines above. We also have been
                # working on a move range.
                #
                # At this point, the plan is to just attach this blank
                # line onto the end of the last range being operated on.
                #
                # This blank line will help tie together adjacent move
                # ranges. If it turns out to be a trailing line, it'll be
                # stripped later in _determine_move_range.
                r_move_range = r_move_ranges.get(move_key)

                if r_move_range:
                    new_end_i = r_move_range.end + 1

                    if (new_end_i < len(self.differ.a) and
                        self.differ.a[new_end_i].strip() == ''):
                        # There was a matching blank line on the other end
                        # of the range, so we should feel more confident about
                        # adding the blank line here.
                        r_move_range.end = new_end_i

                        # It's possible that this blank line is actually an
                        # "equal" line. Though technically it didn't move,
                        # we're trying to create a logical, seamless move
                        # range, so we need to try to find that group and
                        # add it to the list of groups in the range, if it'
                        # not already there.
                        last_group, last_group_index = r_move_range.last_group

                        if new_end_i >= last_group[2]:
                            # This is in the next group, which hasn't been
                            # added yet. So add it.
                            cur_group_index = r_move_range.last_group[1] + 1
                            r_move_range.add_group(
                                self.groups[cur_group_index],
                                cur_group_index)

                        updated_range = True

            i_move_cur += 1

            if not updated_range or i_move_cur == ij2:
                # We've reached the very end of the insert group. See if
                # we have anything that looks like a move.
                if r_move_ranges:
                    r_move_range = self._find_longest_move_range(r_move_ranges)

                    # If we have a move range, see if it's one we want to
                    # include or filter out. Some moves are not impressive
                    # enough to display. For example, a small portion of a
                    # comment, or whitespace-only changes.
                    r_move_range = self._determine_move_range(r_move_range)

                    if r_move_range:
                        # Rebuild the insert and remove ranges based on where
                        # we are now and which range we won.
                        #
                        # The new ranges will be actual lists of positions,
                        # rather than a beginning and end. These will be
                        # provided to the renderer.
                        #
                        # The ranges expected by the renderers are 1-based,
                        # whereas our calculations for this algorithm are
                        # 0-based, so we add 1 to the numbers.
                        #
                        # The upper boundaries passed to the range() function
                        # must actually be one higher than the value we want.
                        # So, for r_move_range, we actually increment by 2.  We
                        # only increment i_move_cur by one, because i_move_cur
                        # already factored in the + 1 by being at the end of
                        # the while loop.
                        i_range = range(i_move_range.start + 1,
                                        i_move_cur + 1)
                        r_range = range(r_move_range.start + 1,
                                        r_move_range.end + 2)

                        moved_to_ranges = dict(zip(r_range, i_range))

                        for group, group_index in r_move_range.groups:
                            rmeta = group[-1]
                            rmeta.setdefault('moved-to', {}).update(
                                moved_to_ranges)

                        imeta.setdefault('moved-from', {}).update(
                            dict(zip(i_range, r_range)))

                # Reset the state for the next range.
                move_key = None
                i_move_range = MoveRange(i_move_cur, i_move_cur)
                r_move_ranges = {}
dataset/ETHPy150Open reviewboard/reviewboard/reviewboard/diffviewer/opcode_generator.py/DiffOpcodeGenerator._compute_move_for_insert