private Member[] pickTargets(Collection<Member> members, int startingIndex, int maxTargets) {
        final Member[] viableTargetArray = members.toArray(new Member[0]);
        final Member[] pickedTargets = new Member[Math.min(maxTargets, viableTargetArray.length)];

        for (int i = 0; i < pickedTargets.length; i++) {
            startingIndex = (startingIndex + 1) % viableTargetArray.length;
            pickedTargets[i] = viableTargetArray[startingIndex];
        }
        return pickedTargets;
    }
private Member [ ] pickTargets ( Collection < Member > members , int startingIndex , int maxTargets ) { final Member [ ] viableTargetArray = members . toArray ( new Member [ 0 ] ) ; final Member [ ] pickedTargets = new Member [ Math . min ( maxTargets , viableTargetArray . length ) ] ; for ( int i = 0 ; i < pickedTargets . length ; i ++ ) { startingIndex = ( startingIndex + 1 ) % viableTargetArray . length ; pickedTargets [ i ] = viableTargetArray [ startingIndex ] ; } return pickedTargets ; }
Picks up to {@code maxTargets} from the provided {@code members}
collection. The {@code startingIndex} parameter determines which
subset of members can be returned. By increasing the parameter by the
size of the returned array you can imitate a "sliding window", meaning
that each time it is invoked it will rotate through a list of viable
targets and return a sub-collection based on the previous method call.
A member may be skipped if the collection of viable targets changes
between two invocations but if the collection does not change,
eventually all targets should be returned by this method.

@param members       a collection of members to choose from
@param startingIndex the index of the first returned member
@param maxTargets    the maximum number of members to return
@return the chosen targets
@see CRDTReplicationConfig#getMaxConcurrentReplicationTargets()