// Path: src/main/java/com/scorpiac/javarant/ApiEndpoint.java
// public enum ApiEndpoint {
//     API("/api"),
//     API_DEVRANT(API, "devrant"),
//     COMMENTS(API, "comments"),
//     VOTE("vote"),
//     // Rants.
//     RANTS(API_DEVRANT, "rants"),
//     SURPRISE(RANTS, "surprise"),
//     SEARCH(API_DEVRANT, "search"),
//     WEEKLY(API_DEVRANT, "weekly-rants"),
//     STORIES(API_DEVRANT, "story-rants"),
//     COLLABS(API_DEVRANT, "collabs"),
//     // Users.
//     USER_ID(API, "get-user-id"),
//     USERS(API, "users"),
//     AUTH_TOKEN(USERS, "auth-token");
// 
//     private final String endpoint;
// 
//     ApiEndpoint(String endpoint) {
//         this.endpoint = endpoint;
//     }
// 
//     ApiEndpoint(ApiEndpoint base, String endpoint) {
//         this(base.toString() + '/' + endpoint);
//     }
// 
//     @Override
//     public String toString() {
//         return endpoint;
//     }
// }
// 
// Path: src/main/java/com/scorpiac/javarant/DevRantException.java
// public class DevRantException extends RuntimeException {
//     public DevRantException(String message) {
//         super(message);
//     }
// 
//     public DevRantException(String message, Throwable cause) {
//         super(message, cause);
//     }
// }
// 
// Path: src/main/java/com/scorpiac/javarant/responses/Response.java
// public abstract class Response<T> {
//     @JsonProperty
//     private boolean success;
//     @JsonProperty
//     private String error;
// 
//     // The actual result value.
//     T value;
// 
//     /**
//      * Get the error message.
//      *
//      * @return The error message.
//      */
//     public String getError() {
//         return error != null ? error : "An unknown error occurred.";
//     }
// 
//     /**
//      * Get the result value.
//      *
//      * @return An optional containing the result value.
//      */
//     public Optional<T> getValue() {
//         return Optional.ofNullable(value);
//     }
// 
//     public T getValueOrError() {
//         if (!success) {
//             throw new DevRantApiException(error);
//         }
//         return value;
//     }
// }


import com.scorpiac.javarant.ApiEndpoint;
import com.scorpiac.javarant.DevRantException;
import com.scorpiac.javarant.responses.Response;
import org.apache.http.NameValuePair;
import org.apache.http.client.fluent.Request;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.message.BasicNameValuePair;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
                .socketTimeout(timeout);
    }

    /**
     * Resolve an endpoint to a URI.
     * This method's main purpose is to be overridden for the tests.
     *
     * @param endpoint The endpoint to resolve.
     * @return A complete URI.
     */
    URI resolve(String endpoint) {
        return BASE_URI.resolve(endpoint);
    }

    /**
     * Handle a request.
     *
     * @param request The request to handle.
     * @param clazz   The class to map the response to.
     * @param <T>     The type of the class to use in the result.
     * @param <R>     The type of the class to map the internal response to.
     * @return The mapped response.
     */
    // This is because of the last line, which cannot be checked. Just make sure it is tested properly.
    @SuppressWarnings("unchecked")
    private <T, R extends Response<T>> R handleRequest(Request request, Class<R> clazz) {
        R response;
        try {
            response = request.execute().handleResponse(responseHandlerFactory.getResponseHandler(clazz));
        } catch (IOException e) {
// Path: src/main/java/com/scorpiac/javarant/ApiEndpoint.java
// public enum ApiEndpoint {
//     API("/api"),
//     API_DEVRANT(API, "devrant"),
//     COMMENTS(API, "comments"),
//     VOTE("vote"),
//     // Rants.
//     RANTS(API_DEVRANT, "rants"),
//     SURPRISE(RANTS, "surprise"),
//     SEARCH(API_DEVRANT, "search"),
//     WEEKLY(API_DEVRANT, "weekly-rants"),
//     STORIES(API_DEVRANT, "story-rants"),
//     COLLABS(API_DEVRANT, "collabs"),
//     // Users.
//     USER_ID(API, "get-user-id"),
//     USERS(API, "users"),
//     AUTH_TOKEN(USERS, "auth-token");
// 
//     private final String endpoint;
// 
//     ApiEndpoint(String endpoint) {
//         this.endpoint = endpoint;
//     }
// 
//     ApiEndpoint(ApiEndpoint base, String endpoint) {
//         this(base.toString() + '/' + endpoint);
//     }
// 
//     @Override
//     public String toString() {
//         return endpoint;
//     }
// }
// 
// Path: src/main/java/com/scorpiac/javarant/DevRantException.java
// public class DevRantException extends RuntimeException {
//     public DevRantException(String message) {
//         super(message);
//     }
// 
//     public DevRantException(String message, Throwable cause) {
//         super(message, cause);
//     }
// }
// 
// Path: src/main/java/com/scorpiac/javarant/responses/Response.java
// public abstract class Response<T> {
//     @JsonProperty
//     private boolean success;
//     @JsonProperty
//     private String error;
// 
//     // The actual result value.
//     T value;
// 
//     /**
//      * Get the error message.
//      *
//      * @return The error message.
//      */
//     public String getError() {
//         return error != null ? error : "An unknown error occurred.";
//     }
// 
//     /**
//      * Get the result value.
//      *
//      * @return An optional containing the result value.
//      */
//     public Optional<T> getValue() {
//         return Optional.ofNullable(value);
//     }
// 
//     public T getValueOrError() {
//         if (!success) {
//             throw new DevRantApiException(error);
//         }
//         return value;
//     }
// }


// Path: src/main/java/com/scorpiac/javarant/services/RequestHandler.java
import com.scorpiac.javarant.ApiEndpoint;
import com.scorpiac.javarant.DevRantException;
import com.scorpiac.javarant.responses.Response;
import org.apache.http.NameValuePair;
import org.apache.http.client.fluent.Request;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.message.BasicNameValuePair;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

                .socketTimeout(timeout);
    }

    /**
     * Resolve an endpoint to a URI.
     * This method's main purpose is to be overridden for the tests.
     *
     * @param endpoint The endpoint to resolve.
     * @return A complete URI.
     */
    URI resolve(String endpoint) {
        return BASE_URI.resolve(endpoint);
    }

    /**
     * Handle a request.
     *
     * @param request The request to handle.
     * @param clazz   The class to map the response to.
     * @param <T>     The type of the class to use in the result.
     * @param <R>     The type of the class to map the internal response to.
     * @return The mapped response.
     */
    // This is because of the last line, which cannot be checked. Just make sure it is tested properly.
    @SuppressWarnings("unchecked")
    private <T, R extends Response<T>> R handleRequest(Request request, Class<R> clazz) {
        R response;
        try {
            response = request.execute().handleResponse(responseHandlerFactory.getResponseHandler(clazz));
        } catch (IOException e) {
            throw new DevRantException("Failed to execute request.", e);