From cf09707a100d6c7dbfc5b0cfefc1df2d77cd9b54 Mon Sep 17 00:00:00 2001 From: huhaosumail <995483610@qq.com> Date: Wed, 26 Jun 2024 22:23:52 +0800 Subject: [PATCH] =?UTF-8?q?`Cffu`=E6=96=B0=E5=A2=9E`Then-Multi-Actions(the?= =?UTF-8?q?nM*)`/`thenTupleMApplyMostSuccessAsync`=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E5=8F=8A=E7=9B=B8=E5=85=B3=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/io/foldright/cffu/Cffu.java | 369 +++++++++++++++++- .../test/java/io/foldright/cffu/CffuTest.java | 110 +++++- 2 files changed, 473 insertions(+), 6 deletions(-) diff --git a/cffu-core/src/main/java/io/foldright/cffu/Cffu.java b/cffu-core/src/main/java/io/foldright/cffu/Cffu.java index afab1116..aca4be49 100644 --- a/cffu-core/src/main/java/io/foldright/cffu/Cffu.java +++ b/cffu-core/src/main/java/io/foldright/cffu/Cffu.java @@ -10,6 +10,7 @@ import org.jetbrains.annotations.Blocking; import org.jetbrains.annotations.Contract; +import java.util.List; import java.util.concurrent.*; import java.util.function.*; @@ -210,7 +211,236 @@ public Cffu thenRunAsync(Runnable action, Executor executor) { // region## Then-Multi-Actions(thenM*) Methods //////////////////////////////////////////////////////////// - // TODO: TO BE implemented!! + /** + * Returns a new Cffu that, when the given stage completes normally, + * is executed using the CompletableFuture's default asynchronous execution facility, + * with the values obtained by calling the given Functions + * (with the given stage's result as the argument to the given functions) + * in the same order of the given Functions arguments. + *

+ * This method is the same as {@link #thenMApplyAsync(CompletionStage, Function[])} + * except for the fast-fail behavior. + * + * @param fns the functions to use to compute the values of the returned Cffu + * @param the functions' return type + * @return the new Cffu + */ + public Cffu> thenMApplyFastFailAsync( + CompletionStage cf, Function... fns) { + return thenMApplyFastFailAsync(cf,fac.defaultExecutor(),fns); + } + + /** + * Returns a new Cffu that, when the given stage completes normally, + * is executed using the given Executor, with the values obtained by calling the given Functions + * (with the given stage's result as the argument to the given functions) + * in the same order of the given Functions arguments. + *

+ * This method is the same as {@link #thenMApplyAsync(CompletionStage, Executor, Function[])} + * except for the fast-fail behavior. + * + * @param fns the functions to use to compute the values of the returned Cffu + * @param executor executor + * @param the functions' return type + * @return the new Cffu + */ + public Cffu> thenMApplyFastFailAsync( + CompletionStage cf, Executor executor, Function... fns) { + return reset0(CompletableFutureUtils.thenMApplyFastFailAsync(cf, executor, fns)); + } + + /** + * Returns a new Cffu that, when the given stage completes normally, + * is executed using the CompletableFuture's default asynchronous execution facility, + * with the most values obtained by calling the given Functions + * (with the given stage's result as the argument to the given functions) + * in the given time({@code timeout}, aka as many results as possible in the given time) + * in the same order of the given Functions arguments. + *

+ * If the given function is successful in the given time, the return result is the completed value; + * Otherwise the given valueIfNotSuccess. + * + * @param valueIfNotSuccess the value to return if not completed successfully + * @param timeout how long to wait in units of {@code unit} + * @param unit a {@code TimeUnit} determining how to interpret the {@code timeout} parameter + * @param fns the functions to use to compute the values of the returned Cffu + * @param the functions' return type + * @return the new Cffu + */ + public Cffu> thenMApplyMostSuccessAsync( + CompletionStage cf, @Nullable U valueIfNotSuccess, + long timeout, TimeUnit unit, Function... fns) { + return thenMApplyMostSuccessAsync(cf, valueIfNotSuccess, fac.defaultExecutor(),timeout, unit, fns); + } + + /** + * Returns a new Cffu that, when the given stage completes normally, + * is executed using the given Executor, with the most values obtained by calling the given Functions + * (with the given stage's result as the argument to the given functions) + * in the given time({@code timeout}, aka as many results as possible in the given time) + * in the same order of the given Functions arguments. + *

+ * If the given function is successful in the given time, the return result is the completed value; + * Otherwise the given valueIfNotSuccess. + * + * @param valueIfNotSuccess the value to return if not completed successfully + * @param executor the executor to use for asynchronous execution + * @param timeout how long to wait in units of {@code unit} + * @param unit a {@code TimeUnit} determining how to interpret the {@code timeout} parameter + * @param fns the functions to use to compute the values of the returned Cffu + * @param the functions' return type + * @return the new Cffu + */ + public Cffu> thenMApplyMostSuccessAsync( + CompletionStage cf, @Nullable U valueIfNotSuccess, + Executor executor, long timeout, TimeUnit unit, Function... fns) { + return reset0(CompletableFutureUtils.thenMApplyMostSuccessAsync(cf, valueIfNotSuccess, executor, timeout, unit, fns)); + } + + /** + * Returns a new Cffu that, when the given stage completes normally, + * is executed using the CompletableFuture's default asynchronous execution facility, + * with the values obtained by calling the given Functions + * (with the given stage's result as the argument to the given functions) + * in the same order of the given Functions arguments. + * + * @param fns the functions to use to compute the values of the returned Cffu + * @param the functions' return type + * @return the new Cffu + */ + public Cffu> thenMApplyAsync( + CompletionStage cf, Function... fns) { + return thenMApplyAsync(cf,fac.defaultExecutor(), fns); + } + + /** + * Returns a new Cffu that, when the given stage completes normally, + * is executed using the given Executor, with the values obtained by calling the given Functions + * (with the given stage's result as the argument to the given functions) + * in the same order of the given Functions arguments. + * + * @param fns the functions to use to compute the values of the returned Cffu + * @param the functions' return type + * @return the new Cffu + */ + public Cffu> thenMApplyAsync( + CompletionStage cf, Executor executor, Function... fns) { + return reset0(CompletableFutureUtils.thenMApplyAsync(cf, executor, fns)); + } + + + /** + * Returns a new Cffu that, when the given stage completes normally, + * is executed using the CompletableFuture's default asynchronous execution facility, + * with the given stage's result as the argument to the given actions. + * + * @param actions the actions to perform before completing the returned Cffu + * @return the new Cffu + */ + public Cffu thenMAcceptAsync( + CompletionStage cf, Consumer... actions) { + return thenMAcceptAsync(cf,fac.defaultExecutor(), actions); + } + + /** + * Returns a new Cffu that, when the given stage completes normally, + * is executed using the given Executor, with the given stage's result as the argument to the given actions. + * + * @param actions the actions to perform before completing the returned Cffu + * @return the new Cffu + */ + public Cffu thenMAcceptAsync( + CompletionStage cf, Executor executor, Consumer... actions) { + return reset0(CompletableFutureUtils.thenMAcceptAsync(cf, executor, actions)); + } + + /** + * Returns a new Cffu that, when the given stage completes normally, + * is executed using the CompletableFuture's default asynchronous execution facility, + * with the given stage's result as the argument to the given actions. + *

+ * This method is the same as {@link #thenMAcceptAsync(CompletionStage, Consumer[])} + * except for the fast-fail behavior. + * + * @param actions the actions to perform before completing the returned Cffu + * @return the new Cffu + */ + public Cffu thenMAcceptFastFailAsync( + CompletionStage cf, Consumer... actions) { + return thenMAcceptFastFailAsync(cf,fac.defaultExecutor(), actions); + } + + /** + * Returns a new Cffu that, when the given stage completes normally, + * is executed using the given Executor, with the given stage's result as the argument to the given actions. + *

+ * This method is the same as {@link #thenMAcceptAsync(CompletionStage, Executor, Consumer[])} + * except for the fast-fail behavior. + * + * @param actions the actions to perform before completing the returned Cffu + * @return the new Cffu + */ + public Cffu thenMAcceptFastFailAsync( + CompletionStage cf, Executor executor, Consumer... actions) { + return reset0(CompletableFutureUtils.thenMAcceptFastFailAsync(cf, executor, actions)); + } + + + /** + * Returns a new Cffu that, when the given stage completes normally, + * executes the given actions using the CompletableFuture's default asynchronous execution facility. + *

+ * This method is the same as {@link #thenMRunAsync(CompletionStage, Runnable...)} + * except for the fast-fail behavior. + * + * @param actions the actions to perform before completing the returned Cffu + * @return the new Cffu + * @see CompletableFuture#thenRunAsync(Runnable) + */ + public Cffu thenMRunFastFailAsync(CompletionStage cf, Runnable... actions) { + return thenMRunFastFailAsync(cf,fac.defaultExecutor(), actions); + } + + /** + * Returns a new Cffu that, when the given stage completes normally, + * executes the given actions using the given Executor. + *

+ * This method is the same as {@link #thenMRunAsync(CompletionStage, Executor, Runnable...)} + * except for the fast-fail behavior. + * + * @param actions the actions to perform before completing the returned Cffu + * @return the new Cffu + * @see CompletableFuture#thenRunAsync(Runnable, Executor) + */ + public Cffu thenMRunFastFailAsync( + CompletionStage cf, Executor executor, Runnable... actions) { + return reset0(CompletableFutureUtils.thenMRunFastFailAsync(cf, executor, actions)); + } + + /** + * Returns a new Cffu that, when the given stage completes normally, + * executes the given actions using the CompletableFuture's default asynchronous execution facility. + * + * @param actions the actions to perform before completing the returned Cffu + * @return the new Cffu + * @see CompletableFuture#thenRunAsync(Runnable) + */ + public Cffu thenMRunAsync(CompletionStage cf, Runnable... actions) { + return thenMRunAsync(cf,fac.defaultExecutor(), actions); + } + + /** + * Returns a new Cffu that, when the given stage completes normally, + * executes the given actions using the given Executor. + * + * @param actions the actions to perform before completing the returned Cffu + * @return the new Cffu + * @see CompletableFuture#thenRunAsync(Runnable, Executor) + */ + public Cffu thenMRunAsync(CompletionStage cf, Executor executor, Runnable... actions) { + return reset0(CompletableFutureUtils.thenMRunAsync(cf, executor, actions)); + } + // endregion //////////////////////////////////////////////////////////// @@ -353,6 +583,143 @@ public Cffu> thenTupleMApplyFast return reset0(CompletableFutureUtils.thenTupleMApplyFastFailAsync(cf, executor, fn1, fn2, fn3, fn4, fn5)); } + + /** + * Returns a new Cffu that, when this Cffu completes normally, is executed using the {@link #defaultExecutor()}, + * with the values obtained by calling the given Functions + * (with this Cffu's result as the argument to the given functions) + * in the same order of the given Functions arguments. + *

+ * This method is the same as {@link #thenTupleMApplyAsync(Function, Function)} + * except for the fast-fail behavior. + * + * @return the new Cffu + */ + public Cffu> thenTupleMApplyMostSuccessAsync( + long timeout, TimeUnit unit, Function fn1, Function fn2) { + return thenTupleMApplyMostSuccessAsync(fac.defaultExecutor(), timeout, unit, fn1, fn2); + } + + /** + * Returns a new Cffu that, when this Cffu completes normally, is executed using the supplied Executor, + * with the values obtained by calling the given Functions + * (with this Cffu's result as the argument to the given functions) + * in the same order of the given Functions arguments. + *

+ * This method is the same as {@link #thenTupleMApplyAsync(Executor, Function, Function)} + * except for the fast-fail behavior. + * + * @return the new Cffu + */ + public Cffu> thenTupleMApplyMostSuccessAsync( + Executor executor, long timeout, TimeUnit unit, Function fn1, Function fn2) { + return reset0(CompletableFutureUtils.thenTupleMApplyMostSuccessAsync(cf, executor, timeout, unit, fn1, fn2)); + } + + /** + * Returns a new Cffu that, when this Cffu completes normally, is executed using the {@link #defaultExecutor()}, + * with the values obtained by calling the given Functions + * (with this Cffu's result as the argument to the given functions) + * in the same order of the given Functions arguments. + *

+ * This method is the same as {@link #thenTupleMApplyAsync(Function, Function, Function)} + * except for the fast-fail behavior. + * + * @return the new Cffu + */ + public Cffu> thenTupleMApplyMostSuccessAsync( + long timeout, TimeUnit unit, Function fn1, + Function fn2, Function fn3) { + return thenTupleMApplyMostSuccessAsync(fac.defaultExecutor(), timeout, unit, fn1, fn2, fn3); + } + + /** + * Returns a new Cffu that, when this Cffu completes normally, is executed using the supplied Executor, + * with the values obtained by calling the given Functions + * (with this Cffu's result as the argument to the given functions) + * in the same order of the given Functions arguments. + *

+ * This method is the same as {@link #thenTupleMApplyAsync(Executor, Function, Function, Function)} + * except for the fast-fail behavior. + * + * @return the new Cffu + */ + public Cffu> thenTupleMApplyMostSuccessAsync( + Executor executor, long timeout, TimeUnit unit, Function fn1, + Function fn2, Function fn3) { + return reset0(CompletableFutureUtils.thenTupleMApplyMostSuccessAsync(cf, executor, timeout, unit, fn1, fn2, fn3)); + } + + /** + * Returns a new Cffu that, when this Cffu completes normally, is executed using the {@link #defaultExecutor()}, + * with the values obtained by calling the given Functions + * (with this Cffu's result as the argument to the given functions) + * in the same order of the given Functions arguments. + *

+ * This method is the same as {@link #thenTupleMApplyAsync(Function, Function, Function, Function)} + * except for the fast-fail behavior. + * + * @return the new Cffu + */ + public Cffu> thenTupleMApplyMostSuccessAsync( + long timeout, TimeUnit unit, Function fn1, Function fn2, + Function fn3, Function fn4) { + return thenTupleMApplyMostSuccessAsync(fac.defaultExecutor(), timeout, unit, fn1, fn2, fn3, fn4); + } + + /** + * Returns a new Cffu that, when this Cffu completes normally, is executed using the supplied Executor, + * with the values obtained by calling the given Functions + * (with this Cffu's result as the argument to the given functions) + * in the same order of the given Functions arguments. + *

+ * This method is the same as {@link #thenTupleMApplyAsync(Executor, Function, Function, Function, Function)} + * except for the fast-fail behavior. + * + * @return the new Cffu + */ + public Cffu> thenTupleMApplyMostSuccessAsync( + Executor executor, long timeout, TimeUnit unit, Function fn1, Function fn2, + Function fn3, Function fn4) { + return reset0(CompletableFutureUtils.thenTupleMApplyMostSuccessAsync(cf, executor, timeout, unit, fn1, fn2, fn3, fn4)); + } + + /** + * Returns a new Cffu that, when this Cffu completes normally, is executed using the {@link #defaultExecutor()}, + * with the values obtained by calling the given Functions + * (with this Cffu's result as the argument to the given functions) + * in the same order of the given Functions arguments. + *

+ * This method is the same as {@link #thenTupleMApplyAsync(Function, Function, Function, Function, Function)} + * except for the fast-fail behavior. + * + * @return the new Cffu + */ + public Cffu> thenTupleMApplyMostSuccessAsync( + long timeout, TimeUnit unit, Function fn1, + Function fn2, Function fn3, + Function fn4, Function fn5) { + return thenTupleMApplyMostSuccessAsync(fac.defaultExecutor(), timeout, unit, fn1, fn2, fn3, fn4, fn5); + } + + /** + * Returns a new Cffu that, when this Cffu completes normally, is executed using the supplied Executor, + * with the values obtained by calling the given Functions + * (with this Cffu's result as the argument to the given functions) + * in the same order of the given Functions arguments. + *

+ * This method is the same as {@link #thenTupleMApplyAsync(Executor, Function, Function, Function, Function, Function)} + * except for the fast-fail behavior. + * + * @return the new Cffu + */ + public Cffu> thenTupleMApplyMostSuccessAsync( + Executor executor, long timeout, TimeUnit unit, Function fn1, + Function fn2, Function fn3, + Function fn4, Function fn5) { + return reset0(CompletableFutureUtils.thenTupleMApplyMostSuccessAsync(cf, executor, timeout, unit, fn1, fn2, fn3, fn4, fn5)); + } + /** * Returns a new Cffu that, when this Cffu completes normally, is executed using the {@link #defaultExecutor()}, * with the values obtained by calling the given Functions diff --git a/cffu-core/src/test/java/io/foldright/cffu/CffuTest.java b/cffu-core/src/test/java/io/foldright/cffu/CffuTest.java index 6d4c641d..f9229314 100644 --- a/cffu-core/src/test/java/io/foldright/cffu/CffuTest.java +++ b/cffu-core/src/test/java/io/foldright/cffu/CffuTest.java @@ -11,6 +11,8 @@ import org.junit.jupiter.api.condition.EnabledForJreRange; import org.junit.jupiter.api.condition.JRE; +import java.util.Arrays; +import java.util.List; import java.util.concurrent.*; import java.util.function.BiConsumer; import java.util.function.Consumer; @@ -33,42 +35,140 @@ class CffuTest { private static CffuFactory forbidObtrudeMethodsCffuFactory; + //////////////////////////////////////////////////////////////////////////////// + //# multi-actions(M*) methods + //////////////////////////////////////////////////////////////////////////////// + @Test - void test_thenTupleMApplyAsync() throws Exception { + void test_thenMApply() throws Exception { final Cffu completed = cffuFactory.completedFuture(n); + final Function function_n = (x) -> { sleep(100); return n; }; - final Function function_s = (x) -> { + + final long tick = System.currentTimeMillis(); + @SuppressWarnings("unchecked") + Cffu[] cfs = new Cffu[]{ + completed.thenMApplyFastFailAsync(completed, function_n, function_n), + completed.thenMApplyFastFailAsync(completed, executorService, function_n, function_n), + completed.thenMApplyMostSuccessAsync(completed, 100, 500, TimeUnit.MILLISECONDS, function_n, function_n), + completed.thenMApplyMostSuccessAsync(completed, 100, executorService, 500, TimeUnit.MILLISECONDS, function_n, function_n), + completed.thenMApplyAsync(completed, function_n, function_n), + completed.thenMApplyAsync(completed, executorService, function_n, function_n) + }; + + assertTrue(System.currentTimeMillis() - tick < 50); + for (Cffu cf : cfs) { + assertEquals(Arrays.asList(n, n), cf.get()); + } + } + + @Test + void test_thenMAccept() throws Exception { + final Cffu completed = cffuFactory.completedFuture(n); + final Consumer consumer = (x) -> { + assertEquals(n, x); + sleep(100); + }; + + final long tick = System.currentTimeMillis(); + + @SuppressWarnings("unchecked") + Cffu>[] cfs = new Cffu[]{ + completed.thenMAcceptAsync(completed, consumer, consumer), + completed.thenMAcceptAsync(completed, executorService, consumer, consumer), + completed.thenMAcceptFastFailAsync(completed, consumer, consumer), + completed.thenMAcceptFastFailAsync(completed, executorService, consumer, consumer) + }; + + assertTrue(System.currentTimeMillis() - tick < 50); + for (Cffu> cf : cfs) { + assertNull(cf.get()); + } + } + + @Test + void test_thenMRun() throws Exception { + final Cffu completed = cffuFactory.completedFuture(null); + final Runnable runnable = () -> { sleep(100); + }; + + final long tick = System.currentTimeMillis(); + + @SuppressWarnings("unchecked") + Cffu>[] cfs = new Cffu[]{ + completed.thenMRunAsync(completed, runnable, runnable), + completed.thenMRunAsync(completed, executorService, runnable, runnable), + completed.thenMRunFastFailAsync(completed, runnable, runnable), + completed.thenMRunFastFailAsync(completed, executorService, runnable, runnable) + }; + + assertTrue(System.currentTimeMillis() - tick < 50); + for (Cffu> cf : cfs) { + assertNull(cf.get()); + } + } + + //////////////////////////////////////////////////////////////////////////////// + // Then-Tuple-Multi-Actions(thenTupleM*) Methods + //////////////////////////////////////////////////////////////////////////////// + + @Test + void test_thenTupleMApplyAsync() throws Exception { + final Cffu completed = cffuFactory.completedFuture(n); + final Function function_n = (x) -> { + sleep(10); + return n; + }; + + final Function function_s = (x) -> { + sleep(10); return s; }; final Function function_d = (x) -> { - sleep(100); + sleep(10); return d; }; final Function function_an = (x) -> { - sleep(100); + sleep(10); return anotherN; }; final Function function_nn = (x) -> { - sleep(100); + sleep(10); return n + n; }; assertEquals(Tuple2.of(n, s), completed.thenTupleMApplyAsync(function_n, function_s).get()); + assertEquals(Tuple2.of(n, s), completed.thenTupleMApplyAsync(executorService, function_n, function_s).get()); assertEquals(Tuple2.of(n, s), completed.thenTupleMApplyFastFailAsync(function_n, function_s).get()); + assertEquals(Tuple2.of(n, s), completed.thenTupleMApplyFastFailAsync(executorService, function_n, function_s).get()); + assertEquals(Tuple2.of(n, s), completed.thenTupleMApplyMostSuccessAsync(100, TimeUnit.MILLISECONDS, function_n, function_s).get()); + assertEquals(Tuple2.of(n, s), completed.thenTupleMApplyMostSuccessAsync(executorService, 100, TimeUnit.MILLISECONDS, function_n, function_s).get()); assertEquals(Tuple3.of(n, s, d), completed.thenTupleMApplyAsync(function_n, function_s, function_d).get()); + assertEquals(Tuple3.of(n, s, d), completed.thenTupleMApplyAsync(executorService, function_n, function_s, function_d).get()); assertEquals(Tuple3.of(n, s, d), completed.thenTupleMApplyFastFailAsync(function_n, function_s, function_d).get()); + assertEquals(Tuple3.of(n, s, d), completed.thenTupleMApplyFastFailAsync(executorService, function_n, function_s, function_d).get()); + assertEquals(Tuple3.of(n, s, d), completed.thenTupleMApplyMostSuccessAsync(100, TimeUnit.MILLISECONDS, function_n, function_s, function_d).get()); + assertEquals(Tuple3.of(n, s, d), completed.thenTupleMApplyMostSuccessAsync(executorService, 100, TimeUnit.MILLISECONDS, function_n, function_s, function_d).get()); assertEquals(Tuple4.of(n, s, d, anotherN), completed.thenTupleMApplyAsync(function_n, function_s, function_d, function_an).get()); + assertEquals(Tuple4.of(n, s, d, anotherN), completed.thenTupleMApplyAsync(executorService, function_n, function_s, function_d, function_an).get()); assertEquals(Tuple4.of(n, s, d, anotherN), completed.thenTupleMApplyFastFailAsync(function_n, function_s, function_d, function_an).get()); + assertEquals(Tuple4.of(n, s, d, anotherN), completed.thenTupleMApplyFastFailAsync(executorService, function_n, function_s, function_d, function_an).get()); + assertEquals(Tuple4.of(n, s, d, anotherN), completed.thenTupleMApplyMostSuccessAsync(100, TimeUnit.MILLISECONDS, function_n, function_s, function_d, function_an).get()); + assertEquals(Tuple4.of(n, s, d, anotherN), completed.thenTupleMApplyMostSuccessAsync(executorService, 100, TimeUnit.MILLISECONDS, function_n, function_s, function_d, function_an).get()); assertEquals(Tuple5.of(n, s, d, anotherN, n + n), completed.thenTupleMApplyAsync(function_n, function_s, function_d, function_an, function_nn).get()); + assertEquals(Tuple5.of(n, s, d, anotherN, n + n), completed.thenTupleMApplyAsync(executorService, function_n, function_s, function_d, function_an, function_nn).get()); assertEquals(Tuple5.of(n, s, d, anotherN, n + n), completed.thenTupleMApplyFastFailAsync(function_n, function_s, function_d, function_an, function_nn).get()); + assertEquals(Tuple5.of(n, s, d, anotherN, n + n), completed.thenTupleMApplyFastFailAsync(executorService, function_n, function_s, function_d, function_an, function_nn).get()); + assertEquals(Tuple5.of(n, s, d, anotherN, n + n), completed.thenTupleMApplyMostSuccessAsync(100, TimeUnit.MILLISECONDS, function_n, function_s, function_d, function_an, function_nn).get()); + assertEquals(Tuple5.of(n, s, d, anotherN, n + n), completed.thenTupleMApplyMostSuccessAsync(executorService, 100, TimeUnit.MILLISECONDS, function_n, function_s, function_d, function_an, function_nn).get()); } ////////////////////////////////////////////////////////////////////////////////