code: private BTreePage applyInsertsAndRemovals(ChangeInfo ci) {
          int newCount = getCount() + ci.insertCount - ci.deleteCount;
  
          // Allocate new buffer of the correct size and start copying from the old one.
          val newPage = new BTreePage(this.config, new ByteArraySegment(new byte[DATA_OFFSET + newCount * this.config.entryLength + FOOTER_LENGTH]), false);
          newPage.formatHeaderAndFooter(newCount, getHeaderId());
          int readIndex = 0;
          int writeIndex = 0;
          for (val e : ci.changes) {
              int entryIndex = e.getKey() * this.config.entryLength;
              if (entryIndex > readIndex) {
                  // Copy from source.
                  int length = entryIndex - readIndex;
                  assert length % this.config.entryLength == 0;
                  newPage.data.copyFrom(this.data, readIndex, writeIndex, length);
                  writeIndex += length;
              }
  
              // Write new Entry.
              PageEntry entryContents = e.getValue();
              readIndex = entryIndex;
              if (entryContents != null) {
                  // Insert new PageEntry.
                  newPage.setEntryAtIndex(writeIndex, entryContents);
                  writeIndex += this.config.entryLength;
              } else {
                  // This PageEntry has been deleted. Skip over it.
                  readIndex += this.config.getEntryLength();
              }
  
          }
  
          if (readIndex < this.data.getLength()) {
              // Copy the last part that we may have missed.
              int length = this.data.getLength() - readIndex;
              newPage.data.copyFrom(this.data, readIndex, writeIndex, length);
          }
  
          return newPage;
      }
docs: Inserts the new PageEntry instances at the given offsets.
  
  @param ci A {@link ChangeInfo} object containing information to change.
  @return A new BTreePage instance with the updated contents.