class MultiNodeExecution {

    public static <T> T execute(Callable<T> function) {
        try {
            return function.call();
        } catch (Exception e) {
            throw Exceptions.bubble(e);
        }
    }

    /**
     * Aggregate (sum) results of the {@link RedisFuture}s.
     *
     * @param executions mapping of a key to the future
     * @return future producing an aggregation result
     */
    public static RedisFuture<Long> aggregateAsync(Map<?, ? extends CompletionStage<Long>> executions) {

        return new PipelinedRedisFuture<>(executions, objectPipelinedRedisFuture -> {
            AtomicLong result = new AtomicLong();
            for (CompletionStage<Long> future : executions.values()) {
                Long value = execute(() -> future.toCompletableFuture().get());
                if (value != null) {
                    result.getAndAdd(value);
                }
            }

            return result.get();
        });
    }

    /**
     * Returns the result of the first {@link RedisFuture} and guarantee that all futures are finished.
     *
     * @param executions mapping of a key to the future
     * @param <T> result type
     * @return future returning the first result.
     */
    public static <T> RedisFuture<T> firstOfAsync(Map<?, ? extends CompletionStage<T>> executions) {<FILL_FUNCTION_BODY>}

    /**
     * Returns the result of the last {@link RedisFuture} and guarantee that all futures are finished.
     *
     * @param executions mapping of a key to the future
     * @param <T> result type
     * @return future returning the first result.
     */
    public static <T> RedisFuture<T> lastOfAsync(Map<?, ? extends CompletionStage<T>> executions) {

        return new PipelinedRedisFuture<>(executions, objectPipelinedRedisFuture -> {
            // make sure, that all futures are executed before returning the result.
            T result = null;
            for (CompletionStage<T> future : executions.values()) {
                result = execute(() -> future.toCompletableFuture().get());
            }
            return result;
        });
    }

    /**
     * Returns always {@literal OK} and guarantee that all futures are finished.
     *
     * @param executions mapping of a key to the future
     * @return future returning the first result.
     */
    public static RedisFuture<String> alwaysOkOfAsync(Map<?, ? extends CompletionStage<String>> executions) {

        return new PipelinedRedisFuture<>(executions, objectPipelinedRedisFuture -> {

            synchronize(executions);

            return "OK";
        });
    }

    private static void synchronize(Map<?, ? extends CompletionStage<String>> executions) {

        // make sure, that all futures are executed before returning the result.
        for (CompletionStage<String> future : executions.values()) {
            try {
                future.toCompletableFuture().get();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new RedisCommandInterruptedException(e);
            } catch (ExecutionException e) {
                // swallow exceptions
            }
        }
    }

}


        return new PipelinedRedisFuture<>(executions, objectPipelinedRedisFuture -> {
            // make sure, that all futures are executed before returning the result.
            for (CompletionStage<T> future : executions.values()) {
                execute(() -> future.toCompletableFuture().get());
            }
            for (CompletionStage<T> future : executions.values()) {
                return execute(() -> future.toCompletableFuture().get());
            }
            return null;
        });
    
<no_super_class>