docs: public List<ChannelWithMeta> mergeChannelList(List<ChannelWithMeta> channelIDs) throws IOException {
  		// A channel list with length maxFanIn<sup>i</sup> can be merged to maxFanIn files in i-1 rounds where every merge
  		// is a full merge with maxFanIn input channels. A partial round includes merges with fewer than maxFanIn
  		// inputs. It is most efficient to perform the partial round first.
  		final double scale = Math.ceil(Math.log(channelIDs.size()) / Math.log(maxFanIn)) - 1;
  
  		final int numStart = channelIDs.size();
  		final int numEnd = (int) Math.pow(maxFanIn, scale);
  
  		final int numMerges = (int) Math.ceil((numStart - numEnd) / (double) (maxFanIn - 1));
  
  		final int numNotMerged = numEnd - numMerges;
  		final int numToMerge = numStart - numNotMerged;
  
  		// unmerged channel IDs are copied directly to the result list
  		final List<ChannelWithMeta> mergedChannelIDs = new ArrayList<>(numEnd);
  		mergedChannelIDs.addAll(channelIDs.subList(0, numNotMerged));
  
  		final int channelsToMergePerStep = (int) Math.ceil(numToMerge / (double) numMerges);
  
  		final List<ChannelWithMeta> channelsToMergeThisStep = new ArrayList<>(channelsToMergePerStep);
  		int channelNum = numNotMerged;
  		while (!closed && channelNum < channelIDs.size()) {
  			channelsToMergeThisStep.clear();
  
  			for (int i = 0; i < channelsToMergePerStep && channelNum < channelIDs.size(); i++, channelNum++) {
  				channelsToMergeThisStep.add(channelIDs.get(channelNum));
  			}
  
  			mergedChannelIDs.add(mergeChannels(channelsToMergeThisStep));
  		}
  
  		return mergedChannelIDs;
  	}