diff --git a/pom.xml b/pom.xml
index a8b76ebd..1a386553 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,25 +1,749 @@
- 4.0.0
-
- org.example
- cffu
- 1.0-SNAPSHOT
- jar
-
- cffu
- http://maven.apache.org
-
-
- UTF-8
-
-
-
-
- junit
- junit
- 3.8.1
- test
-
-
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ 4.0.0
+
+ io.foldright
+ cffu
+ 0.9.0-SNAPSHOT
+ CompletableFuture-Fu(cffu)
+ ${project.name}
+ https://github.com/foldright/cffu
+ 2023
+
+
+
+ Apache 2
+ https://www.apache.org/licenses/LICENSE-2.0.txt
+ repo
+ A business-friendly OSS license
+
+
+
+ scm:git:git@github.com:foldright/cffu.git
+ scm:git:git@github.com:foldright/cffu.git
+ https://github.com/foldright/cffu
+
+
+ https://github.com/foldright/cffu/issues
+ GitHub Issues
+
+
+
+ 1.8
+ ${maven.compiler.source}
+ UTF-8
+ false
+
+ 4.7.3
+ 3.0.2
+ 24.0.0
+
+ 1.8.10
+ ${maven.compiler.source}
+
+ 2.0.6
+
+
+ 5.9.2
+ 5.5.5
+
+
+
+
+
+ com.github.spotbugs
+ spotbugs-annotations
+ true
+
+
+ com.google.code.findbugs
+ jsr305
+ true
+
+
+ org.jetbrains
+ annotations
+ true
+
+
+
+
+ org.slf4j
+ slf4j-simple
+ test
+
+
+ io.github.microutils
+ kotlin-logging-jvm
+ test
+
+
+
+
+ io.kotest
+ kotest-runner-junit4-jvm
+ test
+
+
+ io.kotest
+ kotest-runner-junit5-jvm
+ test
+
+
+ io.kotest
+ kotest-assertions-core-jvm
+ test
+
+
+ io.kotest
+ kotest-property-jvm
+ test
+
+
+
+ org.javatuples
+ javatuples
+
+
+ org.apache.commons
+ commons-lang3
+
+
+
+
+
+
+
+ org.jetbrains.kotlin
+ kotlin-bom
+ ${kotlin.version}
+ pom
+ import
+
+
+ org.junit
+ junit-bom
+ ${junit5.version}
+ pom
+ import
+
+
+
+
+
+ com.github.spotbugs
+ spotbugs-annotations
+ ${spotbugs.annotations.version}
+ true
+
+
+ com.google.code.findbugs
+ jsr305
+ ${jsr305.version}
+ true
+
+
+
+ org.jetbrains
+ annotations
+ ${jetbrains.annotations.version}
+ true
+
+
+
+ org.javatuples
+ javatuples
+ 1.2
+
+
+ org.apache.commons
+ commons-lang3
+ 3.12.0
+
+
+
+
+ org.slf4j
+ slf4j-api
+ ${slf4j.version}
+
+
+ org.slf4j
+ slf4j-simple
+ ${slf4j.version}
+ test
+
+
+ io.github.microutils
+ kotlin-logging-jvm
+ 3.0.0
+
+
+
+
+
+ io.kotest
+ kotest-runner-junit4-jvm
+ ${kotest.version}
+ test
+
+
+ io.kotest
+ kotest-runner-junit5-jvm
+ ${kotest.version}
+ test
+
+
+ io.kotest
+ kotest-assertions-core-jvm
+ ${kotest.version}
+ test
+
+
+ io.kotest
+ kotest-property-jvm
+ ${kotest.version}
+ test
+
+
+
+
+
+
+ ossrh
+ https://oss.sonatype.org/content/repositories/snapshots
+
+
+
+
+
+
+
+ org.jetbrains.kotlin
+ kotlin-maven-plugin
+
+
+ compile
+
+ compile
+
+
+
+ ${project.basedir}/src/main/java
+
+
+
+
+ test-compile
+
+ test-compile
+
+
+
+ ${project.basedir}/src/test/java
+
+
+
+
+
+
+ maven-compiler-plugin
+
+
+
+ default-compile
+ none
+
+
+
+ default-testCompile
+ none
+
+
+ java-compile
+ compile
+
+ compile
+
+
+
+ java-test-compile
+ test-compile
+
+ testCompile
+
+
+
+
+
+
+ maven-enforcer-plugin
+
+
+ enforce-maven
+
+ enforce
+
+
+
+
+ 3.3.9
+
+
+
+
+
+
+
+
+
+
+ maven-clean-plugin
+ 3.2.0
+
+
+ maven-resources-plugin
+ 3.3.0
+
+
+ org.jetbrains.kotlin
+ kotlin-maven-plugin
+ ${kotlin.version}
+
+
+ maven-compiler-plugin
+ 3.10.1
+
+
+ maven-surefire-plugin
+ 3.0.0-M8
+
+
+ maven-jar-plugin
+ 3.3.0
+
+
+ maven-shade-plugin
+ 3.4.1
+
+ true
+
+ ${project.build.directory}/dependency-reduced-pom.xml
+
+
+
+
+ maven-source-plugin
+ 3.2.1
+
+
+ maven-javadoc-plugin
+ 3.4.1
+
+
+ maven-gpg-plugin
+ 3.0.1
+
+
+ maven-site-plugin
+ 3.12.1
+
+
+ maven-install-plugin
+ 3.1.0
+
+
+ maven-deploy-plugin
+ 3.1.0
+
+
+ maven-enforcer-plugin
+ 3.2.1
+
+
+ io.github.git-commit-id
+ git-commit-id-maven-plugin
+ 5.0.0
+
+
+ com.github.spotbugs
+ spotbugs-maven-plugin
+ 4.7.2.1
+
+
+ org.jacoco
+ jacoco-maven-plugin
+ 0.8.8
+
+
+ org.sonatype.plugins
+ nexus-staging-maven-plugin
+ 1.6.13
+
+
+
+ org.codehaus.mojo
+ versions-maven-plugin
+ 2.14.2
+
+ file://${project.basedir}/src/versions-rules.xml
+ false
+
+
+
+
+
+
+
+ gen-src
+
+
+ performRelease
+ true
+
+
+
+
+
+ maven-source-plugin
+
+
+
+
+
+ gen-api-doc
+
+
+ performRelease
+ true
+
+
+
+
+ *.internal:*.internal.*:*.internal.*.*:*.internal.*.*.*:*.internal.*.*.*.*
+
+
+ ${project.basedir}/src/package-list
+
+
+
+
+
+ maven-javadoc-plugin
+
+
+ protected
+ UTF-8
+ UTF-8
+ UTF-8
+ true
+
+ all,-missing
+
+ ${javadoc.default.exclude.packages}
+ true
+
+ false
+
+
+ https://docs.oracle.com/javase/10/docs/api/
+ ${javadoc.package.list.dir}/java/
+
+
+
+ https://www.javadoc.io/doc/com.github.spotbugs/spotbugs-annotations/${spotbugs.annotations.version}/
+
+ ${javadoc.package.list.dir}/spotbugs-annotations/
+
+
+ https://www.javadoc.io/doc/com.google.code.findbugs/jsr305/${jsr305.version}/
+ ${javadoc.package.list.dir}/jsr305/
+
+
+ https://www.javadoc.io/doc/org.jetbrains/annotations/${jetbrains.annotations.version}/
+ ${javadoc.package.list.dir}/jetbrains-annotations/
+
+
+
+
+ --no-module-directories
+ -html5
+
+
+ -J-Duser.language=en
+ -J-Duser.country=US
+
+
+
+
+
+
+
+ gen-sign
+
+
+ performRelease
+ true
+
+
+
+
+
+ maven-gpg-plugin
+
+
+ sign-artifacts
+ verify
+
+ sign
+
+
+
+
+
+
+
+
+ lint
+
+
+ performRelease
+ true
+
+
+
+
+
+
+ com.github.spotbugs
+ spotbugs-maven-plugin
+
+
+ verify
+
+ check
+
+
+
+
+
+
+
+
+ gen-git-properties
+
+
+ performRelease
+ true
+
+
+
+
+
+
+ io.github.git-commit-id
+ git-commit-id-maven-plugin
+
+
+ get-the-git-infos
+
+ revision
+
+
+
+ validate-the-git-infos
+
+ validateRevision
+
+
+
+
+
+
+
+ validating git dirty
+ ${git.dirty}
+ false
+
+
+ true
+
+ ${project.build.outputDirectory}/META-INF/scm/${project.groupId}/${project.artifactId}/git.properties
+
+
+
+
+
+
+
+ gen-code-cov
+
+
+
+
+
+
+ org.jacoco
+ jacoco-maven-plugin
+
+
+
+ prepare-agent
+
+
+
+ report
+ test
+
+ report
+
+
+
+
+
+
+
+
+ force-jdk11-when-release
+
+
+ performRelease
+ true
+
+
+
+
+
+
+ maven-enforcer-plugin
+
+
+ enforce-jdk-versions
+
+ enforce
+
+
+
+
+ 11
+
+
+
+
+
+
+
+
+
+
+ deploy-settings
+
+
+ performRelease
+ true
+
+
+
+
+
+ org.sonatype.plugins
+ nexus-staging-maven-plugin
+ true
+
+
+ ossrh
+ https://oss.sonatype.org/
+ true
+
+ ${maven.deploy.skip}
+
+
+
+
+
+
diff --git a/src/main/java/io/foldright/cffu/Cffu.java b/src/main/java/io/foldright/cffu/Cffu.java
new file mode 100644
index 00000000..26c24b6b
--- /dev/null
+++ b/src/main/java/io/foldright/cffu/Cffu.java
@@ -0,0 +1,58 @@
+package io.foldright.cffu;
+
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.commons.lang3.tuple.Triple;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+
+public class Cffu {
+ @SuppressWarnings("unchecked")
+ public static CompletableFuture> allOf(List extends CompletableFuture> cfs) {
+ final int size = cfs.size();
+ final Object[] result = new Object[size];
+
+ final CompletableFuture>[] wrappedCfs = new CompletableFuture[size];
+ for (int i = 0; i < size; i++) {
+ final int index = i;
+
+ CompletableFuture cf = cfs.get(index);
+
+ CompletableFuture wrapped = cf.thenAccept(t -> result[index] = t);
+ wrappedCfs[index] = wrapped;
+ }
+
+ return CompletableFuture.allOf(wrappedCfs)
+ .thenApply(unused -> (List) Arrays.asList(result));
+ }
+
+ @SuppressWarnings("unchecked")
+ public static CompletableFuture> allOf(
+ CompletableFuture cf1, CompletableFuture cf2) {
+ final Object[] result = {null, null};
+
+ return CompletableFuture.allOf(
+ cf1.thenAccept(t -> result[0] = t),
+ cf2.thenAccept(u -> result[1] = u)
+ )
+ .thenApply(unused ->
+ Pair.of((T) result[0], (U) result[1])
+ );
+ }
+
+ @SuppressWarnings("unchecked")
+ public static CompletableFuture> allOf(
+ CompletableFuture cf1, CompletableFuture cf2, CompletableFuture cf3) {
+ final Object[] ret = {null, null, null};
+
+ return CompletableFuture.allOf(
+ cf1.thenAccept(t -> ret[0] = t),
+ cf2.thenAccept(u -> ret[1] = u),
+ cf3.thenAccept(v -> ret[2] = v)
+ )
+ .thenApply(unused ->
+ Triple.of((T) ret[0], (U) ret[1], (V) ret[2])
+ );
+ }
+}
diff --git a/src/main/java/org/example/App.java b/src/main/java/org/example/App.java
deleted file mode 100644
index 5f21d2e2..00000000
--- a/src/main/java/org/example/App.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package org.example;
-
-/**
- * Hello world!
- *
- */
-public class App
-{
- public static void main( String[] args )
- {
- System.out.println( "Hello World!" );
- }
-}
diff --git a/src/package-list/java/package-list b/src/package-list/java/package-list
new file mode 100644
index 00000000..24c17a89
--- /dev/null
+++ b/src/package-list/java/package-list
@@ -0,0 +1,315 @@
+com.sun.jarsigner
+com.sun.java.accessibility.util
+com.sun.javadoc
+com.sun.jdi
+com.sun.jdi.connect
+com.sun.jdi.connect.spi
+com.sun.jdi.event
+com.sun.jdi.request
+com.sun.management
+com.sun.net.httpserver
+com.sun.net.httpserver.spi
+com.sun.nio.sctp
+com.sun.security.auth
+com.sun.security.auth.callback
+com.sun.security.auth.login
+com.sun.security.auth.module
+com.sun.security.jgss
+com.sun.source.doctree
+com.sun.source.tree
+com.sun.source.util
+com.sun.tools.attach
+com.sun.tools.attach.spi
+com.sun.tools.doclets
+com.sun.tools.doclets.standard
+com.sun.tools.javac
+com.sun.tools.javadoc
+com.sun.tools.jconsole
+java.applet
+java.awt
+java.awt.color
+java.awt.datatransfer
+java.awt.desktop
+java.awt.dnd
+java.awt.event
+java.awt.font
+java.awt.geom
+java.awt.im
+java.awt.im.spi
+java.awt.image
+java.awt.image.renderable
+java.awt.print
+java.beans
+java.beans.beancontext
+java.io
+java.lang
+java.lang.annotation
+java.lang.instrument
+java.lang.invoke
+java.lang.management
+java.lang.module
+java.lang.ref
+java.lang.reflect
+java.math
+java.net
+java.net.spi
+java.nio
+java.nio.channels
+java.nio.channels.spi
+java.nio.charset
+java.nio.charset.spi
+java.nio.file
+java.nio.file.attribute
+java.nio.file.spi
+java.rmi
+java.rmi.activation
+java.rmi.dgc
+java.rmi.registry
+java.rmi.server
+java.security
+java.security.acl
+java.security.cert
+java.security.interfaces
+java.security.spec
+java.sql
+java.text
+java.text.spi
+java.time
+java.time.chrono
+java.time.format
+java.time.temporal
+java.time.zone
+java.util
+java.util.concurrent
+java.util.concurrent.atomic
+java.util.concurrent.locks
+java.util.function
+java.util.jar
+java.util.logging
+java.util.prefs
+java.util.regex
+java.util.spi
+java.util.stream
+java.util.zip
+javafx.animation
+javafx.application
+javafx.beans
+javafx.beans.binding
+javafx.beans.property
+javafx.beans.property.adapter
+javafx.beans.value
+javafx.collections
+javafx.collections.transformation
+javafx.concurrent
+javafx.css
+javafx.css.converter
+javafx.embed.swing
+javafx.event
+javafx.fxml
+javafx.geometry
+javafx.print
+javafx.scene
+javafx.scene.canvas
+javafx.scene.chart
+javafx.scene.control
+javafx.scene.control.cell
+javafx.scene.control.skin
+javafx.scene.effect
+javafx.scene.image
+javafx.scene.input
+javafx.scene.layout
+javafx.scene.media
+javafx.scene.paint
+javafx.scene.shape
+javafx.scene.text
+javafx.scene.transform
+javafx.scene.web
+javafx.stage
+javafx.util
+javafx.util.converter
+javax.accessibility
+javax.activation
+javax.activity
+javax.annotation
+javax.annotation.processing
+javax.crypto
+javax.crypto.interfaces
+javax.crypto.spec
+javax.imageio
+javax.imageio.event
+javax.imageio.metadata
+javax.imageio.plugins.bmp
+javax.imageio.plugins.jpeg
+javax.imageio.plugins.tiff
+javax.imageio.spi
+javax.imageio.stream
+javax.jnlp
+javax.jws
+javax.jws.soap
+javax.lang.model
+javax.lang.model.element
+javax.lang.model.type
+javax.lang.model.util
+javax.management
+javax.management.loading
+javax.management.modelmbean
+javax.management.monitor
+javax.management.openmbean
+javax.management.relation
+javax.management.remote
+javax.management.remote.rmi
+javax.management.timer
+javax.naming
+javax.naming.directory
+javax.naming.event
+javax.naming.ldap
+javax.naming.spi
+javax.net
+javax.net.ssl
+javax.print
+javax.print.attribute
+javax.print.attribute.standard
+javax.print.event
+javax.rmi
+javax.rmi.CORBA
+javax.rmi.ssl
+javax.script
+javax.security.auth
+javax.security.auth.callback
+javax.security.auth.kerberos
+javax.security.auth.login
+javax.security.auth.spi
+javax.security.auth.x500
+javax.security.cert
+javax.security.sasl
+javax.smartcardio
+javax.sound.midi
+javax.sound.midi.spi
+javax.sound.sampled
+javax.sound.sampled.spi
+javax.sql
+javax.sql.rowset
+javax.sql.rowset.serial
+javax.sql.rowset.spi
+javax.swing
+javax.swing.border
+javax.swing.colorchooser
+javax.swing.event
+javax.swing.filechooser
+javax.swing.plaf
+javax.swing.plaf.basic
+javax.swing.plaf.metal
+javax.swing.plaf.multi
+javax.swing.plaf.nimbus
+javax.swing.plaf.synth
+javax.swing.table
+javax.swing.text
+javax.swing.text.html
+javax.swing.text.html.parser
+javax.swing.text.rtf
+javax.swing.tree
+javax.swing.undo
+javax.tools
+javax.transaction
+javax.transaction.xa
+javax.xml
+javax.xml.bind
+javax.xml.bind.annotation
+javax.xml.bind.annotation.adapters
+javax.xml.bind.attachment
+javax.xml.bind.helpers
+javax.xml.bind.util
+javax.xml.catalog
+javax.xml.crypto
+javax.xml.crypto.dom
+javax.xml.crypto.dsig
+javax.xml.crypto.dsig.dom
+javax.xml.crypto.dsig.keyinfo
+javax.xml.crypto.dsig.spec
+javax.xml.datatype
+javax.xml.namespace
+javax.xml.parsers
+javax.xml.soap
+javax.xml.stream
+javax.xml.stream.events
+javax.xml.stream.util
+javax.xml.transform
+javax.xml.transform.dom
+javax.xml.transform.sax
+javax.xml.transform.stax
+javax.xml.transform.stream
+javax.xml.validation
+javax.xml.ws
+javax.xml.ws.handler
+javax.xml.ws.handler.soap
+javax.xml.ws.http
+javax.xml.ws.soap
+javax.xml.ws.spi
+javax.xml.ws.spi.http
+javax.xml.ws.wsaddressing
+javax.xml.xpath
+jdk.dynalink
+jdk.dynalink.beans
+jdk.dynalink.linker
+jdk.dynalink.linker.support
+jdk.dynalink.support
+jdk.incubator.http
+jdk.javadoc.doclet
+jdk.jfr
+jdk.jfr.consumer
+jdk.jshell
+jdk.jshell.execution
+jdk.jshell.spi
+jdk.jshell.tool
+jdk.management.cmm
+jdk.management.jfr
+jdk.management.resource
+jdk.nashorn.api.scripting
+jdk.nashorn.api.tree
+jdk.net
+jdk.packager.services
+jdk.security.jarsigner
+netscape.javascript
+org.ietf.jgss
+org.omg.CORBA
+org.omg.CORBA_2_3
+org.omg.CORBA_2_3.portable
+org.omg.CORBA.DynAnyPackage
+org.omg.CORBA.ORBPackage
+org.omg.CORBA.portable
+org.omg.CORBA.TypeCodePackage
+org.omg.CosNaming
+org.omg.CosNaming.NamingContextExtPackage
+org.omg.CosNaming.NamingContextPackage
+org.omg.Dynamic
+org.omg.DynamicAny
+org.omg.DynamicAny.DynAnyFactoryPackage
+org.omg.DynamicAny.DynAnyPackage
+org.omg.IOP
+org.omg.IOP.CodecFactoryPackage
+org.omg.IOP.CodecPackage
+org.omg.Messaging
+org.omg.PortableInterceptor
+org.omg.PortableInterceptor.ORBInitInfoPackage
+org.omg.PortableServer
+org.omg.PortableServer.CurrentPackage
+org.omg.PortableServer.POAManagerPackage
+org.omg.PortableServer.POAPackage
+org.omg.PortableServer.portable
+org.omg.PortableServer.ServantLocatorPackage
+org.omg.SendingContext
+org.omg.stub.java.rmi
+org.w3c.dom
+org.w3c.dom.bootstrap
+org.w3c.dom.css
+org.w3c.dom.events
+org.w3c.dom.html
+org.w3c.dom.ls
+org.w3c.dom.ranges
+org.w3c.dom.stylesheets
+org.w3c.dom.traversal
+org.w3c.dom.views
+org.w3c.dom.xpath
+org.xml.sax
+org.xml.sax.ext
+org.xml.sax.helpers
diff --git a/src/package-list/jetbrains-annotations/package-list b/src/package-list/jetbrains-annotations/package-list
new file mode 100644
index 00000000..b9d8d522
--- /dev/null
+++ b/src/package-list/jetbrains-annotations/package-list
@@ -0,0 +1,2 @@
+org.intellij.lang.annotations
+org.jetbrains.annotations
diff --git a/src/package-list/jsr305/package-list b/src/package-list/jsr305/package-list
new file mode 100644
index 00000000..cc08202c
--- /dev/null
+++ b/src/package-list/jsr305/package-list
@@ -0,0 +1,3 @@
+javax.annotation
+javax.annotation.concurrent
+javax.annotation.meta
diff --git a/src/package-list/spotbugs-annotations/package-list b/src/package-list/spotbugs-annotations/package-list
new file mode 100644
index 00000000..5f3bb2e5
--- /dev/null
+++ b/src/package-list/spotbugs-annotations/package-list
@@ -0,0 +1 @@
+edu.umd.cs.findbugs.annotations
diff --git a/src/test/java/io/foldright/cffu/CffuTest.kt b/src/test/java/io/foldright/cffu/CffuTest.kt
new file mode 100644
index 00000000..a50c9fe0
--- /dev/null
+++ b/src/test/java/io/foldright/cffu/CffuTest.kt
@@ -0,0 +1,34 @@
+package io.foldright.cffu
+
+import io.kotest.core.spec.style.AnnotationSpec
+import io.kotest.matchers.shouldBe
+import org.apache.commons.lang3.tuple.Pair
+import org.apache.commons.lang3.tuple.Triple
+import java.util.concurrent.CompletableFuture
+
+class CffuTest : AnnotationSpec() {
+ @Test
+ fun testAllOf() {
+ val f1 = CompletableFuture.completedFuture(42)
+ val f2 = CompletableFuture.completedFuture(43)
+ val f3 = CompletableFuture.completedFuture(44)
+
+ val result = Cffu.allOf(listOf(f1, f2, f3)).get()
+ result shouldBe listOf(42, 43, 44)
+ }
+
+
+ @Test
+ fun testAllOf_2_3() {
+ Cffu.allOf(
+ CompletableFuture.completedFuture(42),
+ CompletableFuture.completedFuture("S42"),
+ ).get() shouldBe Pair.of(42, "S42")
+
+ Cffu.allOf(
+ CompletableFuture.completedFuture(42),
+ CompletableFuture.completedFuture("S42"),
+ CompletableFuture.completedFuture(42.1),
+ ).get() shouldBe Triple.of(42, "S42", 42.1)
+ }
+}
diff --git a/src/test/java/org/example/AppTest.java b/src/test/java/org/example/AppTest.java
deleted file mode 100644
index d5f435df..00000000
--- a/src/test/java/org/example/AppTest.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package org.example;
-
-import junit.framework.Test;
-import junit.framework.TestCase;
-import junit.framework.TestSuite;
-
-/**
- * Unit test for simple App.
- */
-public class AppTest
- extends TestCase
-{
- /**
- * Create the test case
- *
- * @param testName name of the test case
- */
- public AppTest( String testName )
- {
- super( testName );
- }
-
- /**
- * @return the suite of tests being tested
- */
- public static Test suite()
- {
- return new TestSuite( AppTest.class );
- }
-
- /**
- * Rigourous Test :-)
- */
- public void testApp()
- {
- assertTrue( true );
- }
-}