code: @SafeVarargs
      public static <T> Iterable<List<T>> cartesianProduct(final Iterable<T>... iterables) {
          if (iterables.length == 0) {
              return Collections.singletonList(Collections.emptyList());
          }
  
          return () -> new AllCombinationsIterator<>(iterables);
      }
docs: Returns an iterator that iterates over the cartesian product of its given source domains. Each intermediate
  combination of elements is computed lazily.
  <p>
  <b>Note:</b> Subsequent calls to the returned iterator's {@link Iterator#next() next()} method return a
  reference to the same list, and only update the contents of the list. If you plan to reuse intermediate results,
  you'll need to explicitly copy them.
  
  @param iterables
  the iterables for the source domains
  @param <T>
  type of elements
  
  @return an iterator that iterates over the cartesian product of its given source domains