// Path: http-builder-ng-core/src/main/java/groovyx/net/http/fn/ClosureBiFunction.java
// public class ClosureBiFunction<IN_0, IN_1, OUT> implements BiFunction<IN_0, IN_1, OUT> {
// 
//     private final Closure<OUT> closure;
// 
//     public ClosureBiFunction(final Closure<OUT> closure) {
//         this.closure = closure;
//     }
// 
//     public Closure<OUT> getClosure() {
//         return closure;
//     }
// 
//     @Override
//     public OUT apply(IN_0 in_0, IN_1 in_1) {
//         return closure.call(closureArgs(in_0, in_1));
//     }
// 
//     private Object[] closureArgs(final IN_0 in_0, final IN_1 in_1) {
//         final int size = closure.getMaximumNumberOfParameters();
//         final Object[] args = new Object[size];
// 
//         if (size >= 1) {
//             args[0] = in_0;
//         }
// 
//         if (size >= 2) {
//             args[1] = in_1;
//         }
// 
//         return args;
//     }
// }
// 
// Path: http-builder-ng-core/src/main/java/groovyx/net/http/fn/ClosureFunction.java
// public class ClosureFunction<IN_0, OUT> implements Function<IN_0, OUT> {
// 
//     private final Closure<OUT> closure;
//     private final int size;
//     
//     public ClosureFunction(final Closure<OUT> closure) {
//         this.closure = closure;
//         this.size = closure.getMaximumNumberOfParameters();
//         if(size != 1) {
//             throw new IllegalArgumentException("Closure needs to accept a single argument");
//         }
//     }
// 
//     public Closure<OUT> getClosure() {
//         return closure;
//     }
// 
//     @Override
//     public OUT apply(final IN_0 in_0) {
//         return closure.call(in_0);
//     }
// }


import groovy.lang.Closure;
import groovyx.net.http.fn.ClosureBiFunction;
import groovyx.net.http.fn.ClosureFunction;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.Charset;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
         * different from a failure condition because there is no response, no status code, no headers, etc. The `closure` will be called with
         * the best guess as to what was the original exception. Some attempts will be made to unwrap exceptions that are of type
         * {@link groovyx.net.http.TransportingException} or {@link java.lang.reflect.UndeclaredThrowableException}. The `closure`
         * should have a single {@link java.lang.Throwable} argument.
         *
         * The value returned from the closure will be used as the result value of the request. Since there is no response
         * body for the closure to process, this usually means that the closure should do one of three things: re-throw the exception or 
         * throw a wrapped version of the exception, return null, or return a predefined empty value.
         *
         * [source,groovy]
         * ----
         * def http = HttpBuilder.configure {
         *      request.uri = 'http://localhost:10101'
         * }
         *
         * http.get {
         *      request.uri.path = '/foo'
         *      response.exception { Throwable t ->
         *          t.printStackTrace();
         *          throw new RuntimeException(t);
         *      }
         * }
         * ----
         *
         * The default exception method wraps the exception in a {@link java.lang.RuntimeException} (if it is
         * not already of that type) and rethrows.
         *
         * @param closure the closure to be executed
         */
        default void exception(Closure<?> closure) {
// Path: http-builder-ng-core/src/main/java/groovyx/net/http/fn/ClosureBiFunction.java
// public class ClosureBiFunction<IN_0, IN_1, OUT> implements BiFunction<IN_0, IN_1, OUT> {
// 
//     private final Closure<OUT> closure;
// 
//     public ClosureBiFunction(final Closure<OUT> closure) {
//         this.closure = closure;
//     }
// 
//     public Closure<OUT> getClosure() {
//         return closure;
//     }
// 
//     @Override
//     public OUT apply(IN_0 in_0, IN_1 in_1) {
//         return closure.call(closureArgs(in_0, in_1));
//     }
// 
//     private Object[] closureArgs(final IN_0 in_0, final IN_1 in_1) {
//         final int size = closure.getMaximumNumberOfParameters();
//         final Object[] args = new Object[size];
// 
//         if (size >= 1) {
//             args[0] = in_0;
//         }
// 
//         if (size >= 2) {
//             args[1] = in_1;
//         }
// 
//         return args;
//     }
// }
// 
// Path: http-builder-ng-core/src/main/java/groovyx/net/http/fn/ClosureFunction.java
// public class ClosureFunction<IN_0, OUT> implements Function<IN_0, OUT> {
// 
//     private final Closure<OUT> closure;
//     private final int size;
//     
//     public ClosureFunction(final Closure<OUT> closure) {
//         this.closure = closure;
//         this.size = closure.getMaximumNumberOfParameters();
//         if(size != 1) {
//             throw new IllegalArgumentException("Closure needs to accept a single argument");
//         }
//     }
// 
//     public Closure<OUT> getClosure() {
//         return closure;
//     }
// 
//     @Override
//     public OUT apply(final IN_0 in_0) {
//         return closure.call(in_0);
//     }
// }


// Path: http-builder-ng-core/src/main/java/groovyx/net/http/HttpConfig.java
import groovy.lang.Closure;
import groovyx.net.http.fn.ClosureBiFunction;
import groovyx.net.http.fn.ClosureFunction;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.Charset;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;

         * different from a failure condition because there is no response, no status code, no headers, etc. The `closure` will be called with
         * the best guess as to what was the original exception. Some attempts will be made to unwrap exceptions that are of type
         * {@link groovyx.net.http.TransportingException} or {@link java.lang.reflect.UndeclaredThrowableException}. The `closure`
         * should have a single {@link java.lang.Throwable} argument.
         *
         * The value returned from the closure will be used as the result value of the request. Since there is no response
         * body for the closure to process, this usually means that the closure should do one of three things: re-throw the exception or 
         * throw a wrapped version of the exception, return null, or return a predefined empty value.
         *
         * [source,groovy]
         * ----
         * def http = HttpBuilder.configure {
         *      request.uri = 'http://localhost:10101'
         * }
         *
         * http.get {
         *      request.uri.path = '/foo'
         *      response.exception { Throwable t ->
         *          t.printStackTrace();
         *          throw new RuntimeException(t);
         *      }
         * }
         * ----
         *
         * The default exception method wraps the exception in a {@link java.lang.RuntimeException} (if it is
         * not already of that type) and rethrows.
         *
         * @param closure the closure to be executed
         */
        default void exception(Closure<?> closure) {
            exception(new ClosureFunction<>(closure));