public void endGroup() {
      boolean includeEndChange = false;
      myLastChangeShift = 0;
      for (myChangeGroupEndIndex = myChangeGroupStartIndex + 1; myChangeGroupEndIndex < myChanges.size(); myChangeGroupEndIndex++) {
        assert myDiff != 0 : String.format(
          "Text: '%s', length: %d, changes: %s, change group indices: %d-%d",
          Arrays.toString(myData), myInputLength, myChanges, myChangeGroupStartIndex, myChangeGroupEndIndex);
        TextChangeImpl change = myChanges.get(myChangeGroupEndIndex);
        int newDiff = myDiff + change.getDiff();

        // Changes group results to the zero text length shift.
        if (newDiff == 0) {
          myDataEndOffset = change.getEnd();
          includeEndChange = true;
          break;
        }

        // Changes group is not constructed yet.
        if (myDiff > 0 == newDiff > 0) {
          myDiff = newDiff;
          continue;
        }

        // Current change finishes changes group.
        myDataEndOffset = change.getStart() + myDiff;
        myLastChangeShift = myDiff;
        break;
      }
      
      if (myChangeGroupEndIndex >= myChanges.size()) {
        if (myDiff > 0) {
          processLastPositiveGroup();
        }
        else {
          processLastNegativeGroup();
        }
        myChangeGroupStartIndex = myChangeGroupEndIndex = myChanges.size();
      }
      else if (myDiff > 0) {
        processPositiveGroup(includeEndChange);
      }
      else {
        processNegativeGroup(includeEndChange);
      }
      myDiff = 0;
      myChangeGroupStartIndex = myChangeGroupEndIndex;
      if (includeEndChange) {
        myChangeGroupStartIndex++;
      }
      myFirstChangeShift = myLastChangeShift;
    }
public void endGroup()