private int merge(BufferedRandomAccessFile fin, DataOutputStream fout, long offset, long chunkSize, int[][] blocks) throws IOException {

        long size1 = fin.length();

        if (offset >= size1) {
            return -1;
        }

        int chunkCount = 1;

        while (offset + chunkCount * chunkSize < size1 && chunkCount < blocks.length) chunkCount++;

        long[] chunkEnds = new long[chunkCount];
        long[] chunkPointers = new long[chunkCount];

        for (int i = 0; i < chunkCount; i++) {
            chunkPointers[i] = offset + i * chunkSize;
            chunkEnds[i] = Math.min(offset + (i + 1) * chunkSize, size1);
        }

        int[] blockSizes = new int[chunkCount];
        int[] blockStarts = new int[chunkCount];

        PriorityQueue<ValueToIndex> heap = new PriorityQueue<ValueToIndex>(blocks.length);

        for (int i = 0; i < chunkCount; i++) {
            refillBlock(i, chunkPointers, chunkEnds, blocks, blockSizes, blockStarts, heap, fin);
        }

        while (!heap.isEmpty()) {
            ValueToIndex min = heap.poll();
            fout.writeInt(min.getValue());

            if (blockStarts[min.index] + 1 < blockSizes[min.index]) {
                blockStarts[min.index] = blockStarts[min.index] + 1;
                min.setValue(blocks[min.index][blockStarts[min.index]]);
                heap.add(min);
            } else {
                chunkPointers[min.index] = chunkPointers[min.index] + blockSizes[min.index] * 4;
                refillBlock(min.index, chunkPointers, chunkEnds, blocks, blockSizes, blockStarts, heap, fin);
            }
        }

        fout.flush();

        return chunkCount;
    }