class RandomDiscreteTimestampGenerator extends UnixEpochTimestampGenerator {

  /** A hard limit on the size of the offsets array to a void using too much heap. */
  public static final int MAX_INTERVALS = 16777216;
  
  /** The total number of intervals for this generator. */
  private final int intervals;
  
  // can't be primitives due to the generic params on the sort function :(
  /** The array of generated offsets from the base time. */
  private final Integer[] offsets;
  
  /** The current index into the offsets array. */
  private int offsetIndex;
  
  /**
   * Ctor that uses the current system time as current.
   * @param interval The interval between timestamps.
   * @param timeUnits The time units of the returned Unix Epoch timestamp (as well
   * as the units for the interval).
   * @param intervals The total number of intervals for the generator.
   * @throws IllegalArgumentException if the intervals is larger than {@link #MAX_INTERVALS}
   */
  public RandomDiscreteTimestampGenerator(final long interval, final TimeUnit timeUnits, 
                                          final int intervals) {
    super(interval, timeUnits);
    this.intervals = intervals;
    offsets = new Integer[intervals];
    setup();
  }
  
  /**
   * Ctor for supplying a starting timestamp.
   * The interval between timestamps.
   * @param timeUnits The time units of the returned Unix Epoch timestamp (as well
   * as the units for the interval).
   * @param startTimestamp The start timestamp to use. 
   * NOTE that this must match the time units used for the interval. 
   * If the units are in nanoseconds, provide a nanosecond timestamp {@code System.nanoTime()}
   * or in microseconds, {@code System.nanoTime() / 1000}
   * or in millis, {@code System.currentTimeMillis()}
   * @param intervals The total number of intervals for the generator.
   * @throws IllegalArgumentException if the intervals is larger than {@link #MAX_INTERVALS}
   */
  public RandomDiscreteTimestampGenerator(final long interval, final TimeUnit timeUnits,
                                          final long startTimestamp, final int intervals) {
    super(interval, timeUnits, startTimestamp);
    this.intervals = intervals;
    offsets = new Integer[intervals];
    setup();
  }
  
  /**
   * Generates the offsets and shuffles the array.
   */
  private void setup() {<FILL_FUNCTION_BODY>}
  
  @Override
  public Long nextValue() {
    if (offsetIndex >= offsets.length) {
      throw new IllegalStateException("Reached the end of the random timestamp "
          + "intervals: " + offsetIndex);
    }
    lastTimestamp = currentTimestamp;
    currentTimestamp = startTimestamp + (offsets[offsetIndex++] * getOffset(1));
    return currentTimestamp;
  }
}

    if (intervals > MAX_INTERVALS) {
      throw new IllegalArgumentException("Too many intervals for the in-memory "
          + "array. The limit is " + MAX_INTERVALS + ".");
    }
    offsetIndex = 0;
    for (int i = 0; i < intervals; i++) {
      offsets[i] = i;
    }
    Utils.shuffleArray(offsets);
  
<methods>public void <init>() ,public void <init>(long, java.util.concurrent.TimeUnit) ,public void <init>(long, java.util.concurrent.TimeUnit, long) ,public long currentValue() ,public long getOffset(long) ,public void initalizeTimestamp(long) ,public java.lang.Long lastValue() ,public java.lang.Long nextValue() <variables>protected long currentTimestamp,protected long interval,protected long lastTimestamp,protected long startTimestamp,protected java.util.concurrent.TimeUnit timeUnits