code: public static List<Part> among(long offset, long totalLength, long chunkSize) {
          List<Part> parts = new ArrayList<Part>();
          int i = 0;
          long start = 0;
          long end = Math.min(start + chunkSize, totalLength) - 1;
          do {
              parts.add(new Part(start + offset, end + offset));
              start = ++i * chunkSize;
              end = Math.min(start + chunkSize, totalLength) - 1;
          } while (start < totalLength);
          return parts;
      }
docs: Return a list of {@link Part}'s with the given offset where the total
  length is split up into equal partitions up to the last chunk that may
  contain a range of length &lt;= the given chunk size.
  
  For instance, an offset of 23 and total length of 21 with a chunkSize of
  10 would result in the following list of returned parts:
  <pre>
  [23, 32], [33, 42], [43, 43]
  </pre>
  
  Notice that the final chunk contains the same start and end. This should
  be expected in cases where the last chunk would only contain one value.
  
  @param offset      add this offset to the start and end of the calculated {@link Part}'s
  @param totalLength the total length of the range to partition
  @param chunkSize   partition the range in chunks of this size, with the
  last chunk containing &lt;= this value
  @return a list of {@link Part}'s