/**
 * Copyright (c) Microsoft Corporation. All rights reserved.
 * Licensed under the MIT License. See License.txt in the project root for
 * license information.
 *
 * Code generated by Microsoft (R) AutoRest Code Generator.
 */

package com.microsoft.azure.cognitiveservices.vision.faceapi.implementation;

import com.microsoft.azure.cognitiveservices.vision.faceapi.models.CreateFaceListsOptionalParameter;
import com.microsoft.azure.cognitiveservices.vision.faceapi.models.UpdateFaceListsOptionalParameter;
import com.microsoft.azure.cognitiveservices.vision.faceapi.models.AddFaceFromUrlOptionalParameter;
import com.microsoft.azure.cognitiveservices.vision.faceapi.models.AddFaceFromStreamOptionalParameter;
import retrofit2.Retrofit;
import com.microsoft.azure.cognitiveservices.vision.faceapi.FaceLists;
import com.google.common.base.Joiner;
import com.google.common.reflect.TypeToken;
import com.microsoft.azure.cognitiveservices.vision.faceapi.models.APIErrorException;
import com.microsoft.azure.cognitiveservices.vision.faceapi.models.FaceList;
import com.microsoft.azure.cognitiveservices.vision.faceapi.models.ImageUrl;
import com.microsoft.azure.cognitiveservices.vision.faceapi.models.NameAndUserDataContract;
import com.microsoft.azure.cognitiveservices.vision.faceapi.models.PersistedFace;
import com.microsoft.rest.CollectionFormat;
import com.microsoft.rest.ServiceCallback;
import com.microsoft.rest.ServiceFuture;
import com.microsoft.rest.ServiceResponse;
import com.microsoft.rest.Validator;
import java.io.IOException;
import java.util.List;
import java.util.UUID;
import okhttp3.MediaType;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.Header;
import retrofit2.http.Headers;
import retrofit2.http.HTTP;
import retrofit2.http.PATCH;
import retrofit2.http.Path;
import retrofit2.http.POST;
import retrofit2.http.PUT;
import retrofit2.http.Query;
import retrofit2.Response;
import rx.functions.Func1;
import rx.Observable;

/**
 * An instance of this class provides access to all the operations defined
 * in FaceLists.
 */
public class FaceListsImpl implements FaceLists {
    /** The Retrofit service to perform REST calls. */
    private FaceListsService service;
    /** The service client containing this operation class. */
    private FaceAPIImpl client;

    /**
     * Initializes an instance of FaceListsImpl.
     *
     * @param retrofit the Retrofit instance built from a Retrofit Builder.
     * @param client the instance of the service client containing this operation class.
     */
    public FaceListsImpl(Retrofit retrofit, FaceAPIImpl client) {
        this.service = retrofit.create(FaceListsService.class);
        this.client = client;
    }

    /**
     * The interface defining all the services for FaceLists to be
     * used by Retrofit to perform actually REST calls.
     */
    interface FaceListsService {
        @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.cognitiveservices.vision.faceapi.FaceLists create" })
        @PUT("facelists/{faceListId}")
        Observable<Response<ResponseBody>> create(@Path("faceListId") String faceListId, @Header("accept-language") String acceptLanguage, @Body NameAndUserDataContract bodyParameter, @Header("x-ms-parameterized-host") String parameterizedHost, @Header("User-Agent") String userAgent);

        @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.cognitiveservices.vision.faceapi.FaceLists get" })
        @GET("facelists/{faceListId}")
        Observable<Response<ResponseBody>> get(@Path("faceListId") String faceListId, @Header("accept-language") String acceptLanguage, @Header("x-ms-parameterized-host") String parameterizedHost, @Header("User-Agent") String userAgent);

        @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.cognitiveservices.vision.faceapi.FaceLists update" })
        @PATCH("facelists/{faceListId}")
        Observable<Response<ResponseBody>> update(@Path("faceListId") String faceListId, @Header("accept-language") String acceptLanguage, @Body NameAndUserDataContract bodyParameter, @Header("x-ms-parameterized-host") String parameterizedHost, @Header("User-Agent") String userAgent);

        @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.cognitiveservices.vision.faceapi.FaceLists delete" })
        @HTTP(path = "facelists/{faceListId}", method = "DELETE", hasBody = true)
        Observable<Response<ResponseBody>> delete(@Path("faceListId") String faceListId, @Header("accept-language") String acceptLanguage, @Header("x-ms-parameterized-host") String parameterizedHost, @Header("User-Agent") String userAgent);

        @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.cognitiveservices.vision.faceapi.FaceLists list" })
        @GET("facelists")
        Observable<Response<ResponseBody>> list(@Header("accept-language") String acceptLanguage, @Header("x-ms-parameterized-host") String parameterizedHost, @Header("User-Agent") String userAgent);

        @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.cognitiveservices.vision.faceapi.FaceLists deleteFace" })
        @HTTP(path = "facelists/{faceListId}/persistedFaces/{persistedFaceId}", method = "DELETE", hasBody = true)
        Observable<Response<ResponseBody>> deleteFace(@Path("faceListId") String faceListId, @Path("persistedFaceId") UUID persistedFaceId, @Header("accept-language") String acceptLanguage, @Header("x-ms-parameterized-host") String parameterizedHost, @Header("User-Agent") String userAgent);

        @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.cognitiveservices.vision.faceapi.FaceLists addFaceFromUrl" })
        @POST("facelists/{faceListId}/persistedFaces")
        Observable<Response<ResponseBody>> addFaceFromUrl(@Path("faceListId") String faceListId, @Query("userData") String userData, @Query("targetFace") String targetFace, @Header("accept-language") String acceptLanguage, @Body ImageUrl imageUrl, @Header("x-ms-parameterized-host") String parameterizedHost, @Header("User-Agent") String userAgent);

        @Headers({ "Content-Type: application/octet-stream", "x-ms-logging-context: com.microsoft.azure.cognitiveservices.vision.faceapi.FaceLists addFaceFromStream" })
        @POST("facelists/{faceListId}/persistedFaces")
        Observable<Response<ResponseBody>> addFaceFromStream(@Path("faceListId") String faceListId, @Query("userData") String userData, @Query("targetFace") String targetFace, @Body RequestBody image, @Header("accept-language") String acceptLanguage, @Header("x-ms-parameterized-host") String parameterizedHost, @Header("User-Agent") String userAgent);

    }


    /**
     * Create an empty face list. Up to 64 face lists are allowed to exist in one subscription.
     *
     * @param faceListId Id referencing a particular face list.
     * @param createOptionalParameter the object representing the optional parameters to be set before calling this API
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @throws APIErrorException thrown if the request is rejected by server
     * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
     */
    public void create(String faceListId, CreateFaceListsOptionalParameter createOptionalParameter) {
        createWithServiceResponseAsync(faceListId, createOptionalParameter).toBlocking().single().body();
    }

    /**
     * Create an empty face list. Up to 64 face lists are allowed to exist in one subscription.
     *
     * @param faceListId Id referencing a particular face list.
     * @param createOptionalParameter the object representing the optional parameters to be set before calling this API
     * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the {@link ServiceFuture} object
     */
    public ServiceFuture<Void> createAsync(String faceListId, CreateFaceListsOptionalParameter createOptionalParameter, final ServiceCallback<Void> serviceCallback) {
        return ServiceFuture.fromResponse(createWithServiceResponseAsync(faceListId, createOptionalParameter), serviceCallback);
    }

    /**
     * Create an empty face list. Up to 64 face lists are allowed to exist in one subscription.
     *
     * @param faceListId Id referencing a particular face list.
     * @param createOptionalParameter the object representing the optional parameters to be set before calling this API
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the {@link ServiceResponse} object if successful.
     */
    public Observable<Void> createAsync(String faceListId, CreateFaceListsOptionalParameter createOptionalParameter) {
        return createWithServiceResponseAsync(faceListId, createOptionalParameter).map(new Func1<ServiceResponse<Void>, Void>() {
            @Override
            public Void call(ServiceResponse<Void> response) {
                return response.body();
            }
        });
    }

    /**
     * Create an empty face list. Up to 64 face lists are allowed to exist in one subscription.
     *
     * @param faceListId Id referencing a particular face list.
     * @param createOptionalParameter the object representing the optional parameters to be set before calling this API
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the {@link ServiceResponse} object if successful.
     */
    public Observable<ServiceResponse<Void>> createWithServiceResponseAsync(String faceListId, CreateFaceListsOptionalParameter createOptionalParameter) {
        if (this.client.azureRegion() == null) {
            throw new IllegalArgumentException("Parameter this.client.azureRegion() is required and cannot be null.");
        }
        if (faceListId == null) {
            throw new IllegalArgumentException("Parameter faceListId is required and cannot be null.");
        }
        final String name = createOptionalParameter != null ? createOptionalParameter.name() : null;
        final String userData = createOptionalParameter != null ? createOptionalParameter.userData() : null;

        return createWithServiceResponseAsync(faceListId, name, userData);
    }

    /**
     * Create an empty face list. Up to 64 face lists are allowed to exist in one subscription.
     *
     * @param faceListId Id referencing a particular face list.
     * @param name User defined name, maximum length is 128.
     * @param userData User specified data. Length should not exceed 16KB.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the {@link ServiceResponse} object if successful.
     */
    public Observable<ServiceResponse<Void>> createWithServiceResponseAsync(String faceListId, String name, String userData) {
        if (this.client.azureRegion() == null) {
            throw new IllegalArgumentException("Parameter this.client.azureRegion() is required and cannot be null.");
        }
        if (faceListId == null) {
            throw new IllegalArgumentException("Parameter faceListId is required and cannot be null.");
        }
        NameAndUserDataContract bodyParameter = new NameAndUserDataContract();
        bodyParameter.withName(name);
        bodyParameter.withUserData(userData);
        String parameterizedHost = Joiner.on(", ").join("{AzureRegion}", this.client.azureRegion());
        return service.create(faceListId, this.client.acceptLanguage(), bodyParameter, parameterizedHost, this.client.userAgent())
            .flatMap(new Func1<Response<ResponseBody>, Observable<ServiceResponse<Void>>>() {
                @Override
                public Observable<ServiceResponse<Void>> call(Response<ResponseBody> response) {
                    try {
                        ServiceResponse<Void> clientResponse = createDelegate(response);
                        return Observable.just(clientResponse);
                    } catch (Throwable t) {
                        return Observable.error(t);
                    }
                }
            });
    }

    private ServiceResponse<Void> createDelegate(Response<ResponseBody> response) throws APIErrorException, IOException, IllegalArgumentException {
        return this.client.restClient().responseBuilderFactory().<Void, APIErrorException>newInstance(this.client.serializerAdapter())
                .register(200, new TypeToken<Void>() { }.getType())
                .registerError(APIErrorException.class)
                .build(response);
    }

    @Override
    public FaceListsCreateParameters create() {
        return new FaceListsCreateParameters(this);
    }

    /**
     * Internal class implementing FaceListsCreateDefinition.
     */
    class FaceListsCreateParameters implements FaceListsCreateDefinition {
        private FaceListsImpl parent;
        private String faceListId;
        private String name;
        private String userData;

        /**
         * Constructor.
         * @param parent the parent object.
         */
        FaceListsCreateParameters(FaceListsImpl parent) {
            this.parent = parent;
        }

        @Override
        public FaceListsCreateParameters withFaceListId(String faceListId) {
            this.faceListId = faceListId;
            return this;
        }

        @Override
        public FaceListsCreateParameters withName(String name) {
            this.name = name;
            return this;
        }

        @Override
        public FaceListsCreateParameters withUserData(String userData) {
            this.userData = userData;
            return this;
        }

        @Override
        public void execute() {
        createWithServiceResponseAsync(faceListId, name, userData).toBlocking().single().body();
    }

        @Override
        public Observable<Void> executeAsync() {
            return createWithServiceResponseAsync(faceListId, name, userData).map(new Func1<ServiceResponse<Void>, Void>() {
                @Override
                public Void call(ServiceResponse<Void> response) {
                    return response.body();
                }
            });
        }
    }

    /**
     * Retrieve a face list's information.
     *
     * @param faceListId Id referencing a particular face list.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @throws APIErrorException thrown if the request is rejected by server
     * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
     * @return the FaceList object if successful.
     */
    public FaceList get(String faceListId) {
        return getWithServiceResponseAsync(faceListId).toBlocking().single().body();
    }

    /**
     * Retrieve a face list's information.
     *
     * @param faceListId Id referencing a particular face list.
     * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the {@link ServiceFuture} object
     */
    public ServiceFuture<FaceList> getAsync(String faceListId, final ServiceCallback<FaceList> serviceCallback) {
        return ServiceFuture.fromResponse(getWithServiceResponseAsync(faceListId), serviceCallback);
    }

    /**
     * Retrieve a face list's information.
     *
     * @param faceListId Id referencing a particular face list.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the FaceList object
     */
    public Observable<FaceList> getAsync(String faceListId) {
        return getWithServiceResponseAsync(faceListId).map(new Func1<ServiceResponse<FaceList>, FaceList>() {
            @Override
            public FaceList call(ServiceResponse<FaceList> response) {
                return response.body();
            }
        });
    }

    /**
     * Retrieve a face list's information.
     *
     * @param faceListId Id referencing a particular face list.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the FaceList object
     */
    public Observable<ServiceResponse<FaceList>> getWithServiceResponseAsync(String faceListId) {
        if (this.client.azureRegion() == null) {
            throw new IllegalArgumentException("Parameter this.client.azureRegion() is required and cannot be null.");
        }
        if (faceListId == null) {
            throw new IllegalArgumentException("Parameter faceListId is required and cannot be null.");
        }
        String parameterizedHost = Joiner.on(", ").join("{AzureRegion}", this.client.azureRegion());
        return service.get(faceListId, this.client.acceptLanguage(), parameterizedHost, this.client.userAgent())
            .flatMap(new Func1<Response<ResponseBody>, Observable<ServiceResponse<FaceList>>>() {
                @Override
                public Observable<ServiceResponse<FaceList>> call(Response<ResponseBody> response) {
                    try {
                        ServiceResponse<FaceList> clientResponse = getDelegate(response);
                        return Observable.just(clientResponse);
                    } catch (Throwable t) {
                        return Observable.error(t);
                    }
                }
            });
    }

    private ServiceResponse<FaceList> getDelegate(Response<ResponseBody> response) throws APIErrorException, IOException, IllegalArgumentException {
        return this.client.restClient().responseBuilderFactory().<FaceList, APIErrorException>newInstance(this.client.serializerAdapter())
                .register(200, new TypeToken<FaceList>() { }.getType())
                .registerError(APIErrorException.class)
                .build(response);
    }


    /**
     * Update information of a face list.
     *
     * @param faceListId Id referencing a particular face list.
     * @param updateOptionalParameter the object representing the optional parameters to be set before calling this API
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @throws APIErrorException thrown if the request is rejected by server
     * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
     */
    public void update(String faceListId, UpdateFaceListsOptionalParameter updateOptionalParameter) {
        updateWithServiceResponseAsync(faceListId, updateOptionalParameter).toBlocking().single().body();
    }

    /**
     * Update information of a face list.
     *
     * @param faceListId Id referencing a particular face list.
     * @param updateOptionalParameter the object representing the optional parameters to be set before calling this API
     * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the {@link ServiceFuture} object
     */
    public ServiceFuture<Void> updateAsync(String faceListId, UpdateFaceListsOptionalParameter updateOptionalParameter, final ServiceCallback<Void> serviceCallback) {
        return ServiceFuture.fromResponse(updateWithServiceResponseAsync(faceListId, updateOptionalParameter), serviceCallback);
    }

    /**
     * Update information of a face list.
     *
     * @param faceListId Id referencing a particular face list.
     * @param updateOptionalParameter the object representing the optional parameters to be set before calling this API
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the {@link ServiceResponse} object if successful.
     */
    public Observable<Void> updateAsync(String faceListId, UpdateFaceListsOptionalParameter updateOptionalParameter) {
        return updateWithServiceResponseAsync(faceListId, updateOptionalParameter).map(new Func1<ServiceResponse<Void>, Void>() {
            @Override
            public Void call(ServiceResponse<Void> response) {
                return response.body();
            }
        });
    }

    /**
     * Update information of a face list.
     *
     * @param faceListId Id referencing a particular face list.
     * @param updateOptionalParameter the object representing the optional parameters to be set before calling this API
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the {@link ServiceResponse} object if successful.
     */
    public Observable<ServiceResponse<Void>> updateWithServiceResponseAsync(String faceListId, UpdateFaceListsOptionalParameter updateOptionalParameter) {
        if (this.client.azureRegion() == null) {
            throw new IllegalArgumentException("Parameter this.client.azureRegion() is required and cannot be null.");
        }
        if (faceListId == null) {
            throw new IllegalArgumentException("Parameter faceListId is required and cannot be null.");
        }
        final String name = updateOptionalParameter != null ? updateOptionalParameter.name() : null;
        final String userData = updateOptionalParameter != null ? updateOptionalParameter.userData() : null;

        return updateWithServiceResponseAsync(faceListId, name, userData);
    }

    /**
     * Update information of a face list.
     *
     * @param faceListId Id referencing a particular face list.
     * @param name User defined name, maximum length is 128.
     * @param userData User specified data. Length should not exceed 16KB.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the {@link ServiceResponse} object if successful.
     */
    public Observable<ServiceResponse<Void>> updateWithServiceResponseAsync(String faceListId, String name, String userData) {
        if (this.client.azureRegion() == null) {
            throw new IllegalArgumentException("Parameter this.client.azureRegion() is required and cannot be null.");
        }
        if (faceListId == null) {
            throw new IllegalArgumentException("Parameter faceListId is required and cannot be null.");
        }
        NameAndUserDataContract bodyParameter = new NameAndUserDataContract();
        bodyParameter.withName(name);
        bodyParameter.withUserData(userData);
        String parameterizedHost = Joiner.on(", ").join("{AzureRegion}", this.client.azureRegion());
        return service.update(faceListId, this.client.acceptLanguage(), bodyParameter, parameterizedHost, this.client.userAgent())
            .flatMap(new Func1<Response<ResponseBody>, Observable<ServiceResponse<Void>>>() {
                @Override
                public Observable<ServiceResponse<Void>> call(Response<ResponseBody> response) {
                    try {
                        ServiceResponse<Void> clientResponse = updateDelegate(response);
                        return Observable.just(clientResponse);
                    } catch (Throwable t) {
                        return Observable.error(t);
                    }
                }
            });
    }

    private ServiceResponse<Void> updateDelegate(Response<ResponseBody> response) throws APIErrorException, IOException, IllegalArgumentException {
        return this.client.restClient().responseBuilderFactory().<Void, APIErrorException>newInstance(this.client.serializerAdapter())
                .register(200, new TypeToken<Void>() { }.getType())
                .registerError(APIErrorException.class)
                .build(response);
    }

    @Override
    public FaceListsUpdateParameters update() {
        return new FaceListsUpdateParameters(this);
    }

    /**
     * Internal class implementing FaceListsUpdateDefinition.
     */
    class FaceListsUpdateParameters implements FaceListsUpdateDefinition {
        private FaceListsImpl parent;
        private String faceListId;
        private String name;
        private String userData;

        /**
         * Constructor.
         * @param parent the parent object.
         */
        FaceListsUpdateParameters(FaceListsImpl parent) {
            this.parent = parent;
        }

        @Override
        public FaceListsUpdateParameters withFaceListId(String faceListId) {
            this.faceListId = faceListId;
            return this;
        }

        @Override
        public FaceListsUpdateParameters withName(String name) {
            this.name = name;
            return this;
        }

        @Override
        public FaceListsUpdateParameters withUserData(String userData) {
            this.userData = userData;
            return this;
        }

        @Override
        public void execute() {
        updateWithServiceResponseAsync(faceListId, name, userData).toBlocking().single().body();
    }

        @Override
        public Observable<Void> executeAsync() {
            return updateWithServiceResponseAsync(faceListId, name, userData).map(new Func1<ServiceResponse<Void>, Void>() {
                @Override
                public Void call(ServiceResponse<Void> response) {
                    return response.body();
                }
            });
        }
    }

    /**
     * Delete an existing face list according to faceListId. Persisted face images in the face list will also be deleted.
     *
     * @param faceListId Id referencing a particular face list.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @throws APIErrorException thrown if the request is rejected by server
     * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
     */
    public void delete(String faceListId) {
        deleteWithServiceResponseAsync(faceListId).toBlocking().single().body();
    }

    /**
     * Delete an existing face list according to faceListId. Persisted face images in the face list will also be deleted.
     *
     * @param faceListId Id referencing a particular face list.
     * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the {@link ServiceFuture} object
     */
    public ServiceFuture<Void> deleteAsync(String faceListId, final ServiceCallback<Void> serviceCallback) {
        return ServiceFuture.fromResponse(deleteWithServiceResponseAsync(faceListId), serviceCallback);
    }

    /**
     * Delete an existing face list according to faceListId. Persisted face images in the face list will also be deleted.
     *
     * @param faceListId Id referencing a particular face list.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the {@link ServiceResponse} object if successful.
     */
    public Observable<Void> deleteAsync(String faceListId) {
        return deleteWithServiceResponseAsync(faceListId).map(new Func1<ServiceResponse<Void>, Void>() {
            @Override
            public Void call(ServiceResponse<Void> response) {
                return response.body();
            }
        });
    }

    /**
     * Delete an existing face list according to faceListId. Persisted face images in the face list will also be deleted.
     *
     * @param faceListId Id referencing a particular face list.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the {@link ServiceResponse} object if successful.
     */
    public Observable<ServiceResponse<Void>> deleteWithServiceResponseAsync(String faceListId) {
        if (this.client.azureRegion() == null) {
            throw new IllegalArgumentException("Parameter this.client.azureRegion() is required and cannot be null.");
        }
        if (faceListId == null) {
            throw new IllegalArgumentException("Parameter faceListId is required and cannot be null.");
        }
        String parameterizedHost = Joiner.on(", ").join("{AzureRegion}", this.client.azureRegion());
        return service.delete(faceListId, this.client.acceptLanguage(), parameterizedHost, this.client.userAgent())
            .flatMap(new Func1<Response<ResponseBody>, Observable<ServiceResponse<Void>>>() {
                @Override
                public Observable<ServiceResponse<Void>> call(Response<ResponseBody> response) {
                    try {
                        ServiceResponse<Void> clientResponse = deleteDelegate(response);
                        return Observable.just(clientResponse);
                    } catch (Throwable t) {
                        return Observable.error(t);
                    }
                }
            });
    }

    private ServiceResponse<Void> deleteDelegate(Response<ResponseBody> response) throws APIErrorException, IOException, IllegalArgumentException {
        return this.client.restClient().responseBuilderFactory().<Void, APIErrorException>newInstance(this.client.serializerAdapter())
                .register(200, new TypeToken<Void>() { }.getType())
                .registerError(APIErrorException.class)
                .build(response);
    }

    /**
     * Retrieve information about all existing face lists. Only faceListId, name and userData will be returned.
     *
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @throws APIErrorException thrown if the request is rejected by server
     * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
     * @return the List&lt;FaceList&gt; object if successful.
     */
    public List<FaceList> list() {
        return listWithServiceResponseAsync().toBlocking().single().body();
    }

    /**
     * Retrieve information about all existing face lists. Only faceListId, name and userData will be returned.
     *
     * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the {@link ServiceFuture} object
     */
    public ServiceFuture<List<FaceList>> listAsync(final ServiceCallback<List<FaceList>> serviceCallback) {
        return ServiceFuture.fromResponse(listWithServiceResponseAsync(), serviceCallback);
    }

    /**
     * Retrieve information about all existing face lists. Only faceListId, name and userData will be returned.
     *
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the List&lt;FaceList&gt; object
     */
    public Observable<List<FaceList>> listAsync() {
        return listWithServiceResponseAsync().map(new Func1<ServiceResponse<List<FaceList>>, List<FaceList>>() {
            @Override
            public List<FaceList> call(ServiceResponse<List<FaceList>> response) {
                return response.body();
            }
        });
    }

    /**
     * Retrieve information about all existing face lists. Only faceListId, name and userData will be returned.
     *
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the List&lt;FaceList&gt; object
     */
    public Observable<ServiceResponse<List<FaceList>>> listWithServiceResponseAsync() {
        if (this.client.azureRegion() == null) {
            throw new IllegalArgumentException("Parameter this.client.azureRegion() is required and cannot be null.");
        }
        String parameterizedHost = Joiner.on(", ").join("{AzureRegion}", this.client.azureRegion());
        return service.list(this.client.acceptLanguage(), parameterizedHost, this.client.userAgent())
            .flatMap(new Func1<Response<ResponseBody>, Observable<ServiceResponse<List<FaceList>>>>() {
                @Override
                public Observable<ServiceResponse<List<FaceList>>> call(Response<ResponseBody> response) {
                    try {
                        ServiceResponse<List<FaceList>> clientResponse = listDelegate(response);
                        return Observable.just(clientResponse);
                    } catch (Throwable t) {
                        return Observable.error(t);
                    }
                }
            });
    }

    private ServiceResponse<List<FaceList>> listDelegate(Response<ResponseBody> response) throws APIErrorException, IOException, IllegalArgumentException {
        return this.client.restClient().responseBuilderFactory().<List<FaceList>, APIErrorException>newInstance(this.client.serializerAdapter())
                .register(200, new TypeToken<List<FaceList>>() { }.getType())
                .registerError(APIErrorException.class)
                .build(response);
    }

    /**
     * Delete an existing face from a face list (given by a persisitedFaceId and a faceListId). Persisted image related to the face will also be deleted.
     *
     * @param faceListId Id referencing a particular face list.
     * @param persistedFaceId Id referencing a particular persistedFaceId of an existing face.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @throws APIErrorException thrown if the request is rejected by server
     * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
     */
    public void deleteFace(String faceListId, UUID persistedFaceId) {
        deleteFaceWithServiceResponseAsync(faceListId, persistedFaceId).toBlocking().single().body();
    }

    /**
     * Delete an existing face from a face list (given by a persisitedFaceId and a faceListId). Persisted image related to the face will also be deleted.
     *
     * @param faceListId Id referencing a particular face list.
     * @param persistedFaceId Id referencing a particular persistedFaceId of an existing face.
     * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the {@link ServiceFuture} object
     */
    public ServiceFuture<Void> deleteFaceAsync(String faceListId, UUID persistedFaceId, final ServiceCallback<Void> serviceCallback) {
        return ServiceFuture.fromResponse(deleteFaceWithServiceResponseAsync(faceListId, persistedFaceId), serviceCallback);
    }

    /**
     * Delete an existing face from a face list (given by a persisitedFaceId and a faceListId). Persisted image related to the face will also be deleted.
     *
     * @param faceListId Id referencing a particular face list.
     * @param persistedFaceId Id referencing a particular persistedFaceId of an existing face.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the {@link ServiceResponse} object if successful.
     */
    public Observable<Void> deleteFaceAsync(String faceListId, UUID persistedFaceId) {
        return deleteFaceWithServiceResponseAsync(faceListId, persistedFaceId).map(new Func1<ServiceResponse<Void>, Void>() {
            @Override
            public Void call(ServiceResponse<Void> response) {
                return response.body();
            }
        });
    }

    /**
     * Delete an existing face from a face list (given by a persisitedFaceId and a faceListId). Persisted image related to the face will also be deleted.
     *
     * @param faceListId Id referencing a particular face list.
     * @param persistedFaceId Id referencing a particular persistedFaceId of an existing face.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the {@link ServiceResponse} object if successful.
     */
    public Observable<ServiceResponse<Void>> deleteFaceWithServiceResponseAsync(String faceListId, UUID persistedFaceId) {
        if (this.client.azureRegion() == null) {
            throw new IllegalArgumentException("Parameter this.client.azureRegion() is required and cannot be null.");
        }
        if (faceListId == null) {
            throw new IllegalArgumentException("Parameter faceListId is required and cannot be null.");
        }
        if (persistedFaceId == null) {
            throw new IllegalArgumentException("Parameter persistedFaceId is required and cannot be null.");
        }
        String parameterizedHost = Joiner.on(", ").join("{AzureRegion}", this.client.azureRegion());
        return service.deleteFace(faceListId, persistedFaceId, this.client.acceptLanguage(), parameterizedHost, this.client.userAgent())
            .flatMap(new Func1<Response<ResponseBody>, Observable<ServiceResponse<Void>>>() {
                @Override
                public Observable<ServiceResponse<Void>> call(Response<ResponseBody> response) {
                    try {
                        ServiceResponse<Void> clientResponse = deleteFaceDelegate(response);
                        return Observable.just(clientResponse);
                    } catch (Throwable t) {
                        return Observable.error(t);
                    }
                }
            });
    }

    private ServiceResponse<Void> deleteFaceDelegate(Response<ResponseBody> response) throws APIErrorException, IOException, IllegalArgumentException {
        return this.client.restClient().responseBuilderFactory().<Void, APIErrorException>newInstance(this.client.serializerAdapter())
                .register(200, new TypeToken<Void>() { }.getType())
                .registerError(APIErrorException.class)
                .build(response);
    }


    /**
     * Add a face to a face list. The input face is specified as an image with a targetFace rectangle. It returns a persistedFaceId representing the added face, and persistedFaceId will not expire.
     *
     * @param faceListId Id referencing a particular face list.
     * @param url Publicly reachable URL of an image
     * @param addFaceFromUrlOptionalParameter the object representing the optional parameters to be set before calling this API
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @throws APIErrorException thrown if the request is rejected by server
     * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
     * @return the PersistedFace object if successful.
     */
    public PersistedFace addFaceFromUrl(String faceListId, String url, AddFaceFromUrlOptionalParameter addFaceFromUrlOptionalParameter) {
        return addFaceFromUrlWithServiceResponseAsync(faceListId, url, addFaceFromUrlOptionalParameter).toBlocking().single().body();
    }

    /**
     * Add a face to a face list. The input face is specified as an image with a targetFace rectangle. It returns a persistedFaceId representing the added face, and persistedFaceId will not expire.
     *
     * @param faceListId Id referencing a particular face list.
     * @param url Publicly reachable URL of an image
     * @param addFaceFromUrlOptionalParameter the object representing the optional parameters to be set before calling this API
     * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the {@link ServiceFuture} object
     */
    public ServiceFuture<PersistedFace> addFaceFromUrlAsync(String faceListId, String url, AddFaceFromUrlOptionalParameter addFaceFromUrlOptionalParameter, final ServiceCallback<PersistedFace> serviceCallback) {
        return ServiceFuture.fromResponse(addFaceFromUrlWithServiceResponseAsync(faceListId, url, addFaceFromUrlOptionalParameter), serviceCallback);
    }

    /**
     * Add a face to a face list. The input face is specified as an image with a targetFace rectangle. It returns a persistedFaceId representing the added face, and persistedFaceId will not expire.
     *
     * @param faceListId Id referencing a particular face list.
     * @param url Publicly reachable URL of an image
     * @param addFaceFromUrlOptionalParameter the object representing the optional parameters to be set before calling this API
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the PersistedFace object
     */
    public Observable<PersistedFace> addFaceFromUrlAsync(String faceListId, String url, AddFaceFromUrlOptionalParameter addFaceFromUrlOptionalParameter) {
        return addFaceFromUrlWithServiceResponseAsync(faceListId, url, addFaceFromUrlOptionalParameter).map(new Func1<ServiceResponse<PersistedFace>, PersistedFace>() {
            @Override
            public PersistedFace call(ServiceResponse<PersistedFace> response) {
                return response.body();
            }
        });
    }

    /**
     * Add a face to a face list. The input face is specified as an image with a targetFace rectangle. It returns a persistedFaceId representing the added face, and persistedFaceId will not expire.
     *
     * @param faceListId Id referencing a particular face list.
     * @param url Publicly reachable URL of an image
     * @param addFaceFromUrlOptionalParameter the object representing the optional parameters to be set before calling this API
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the PersistedFace object
     */
    public Observable<ServiceResponse<PersistedFace>> addFaceFromUrlWithServiceResponseAsync(String faceListId, String url, AddFaceFromUrlOptionalParameter addFaceFromUrlOptionalParameter) {
        if (this.client.azureRegion() == null) {
            throw new IllegalArgumentException("Parameter this.client.azureRegion() is required and cannot be null.");
        }
        if (faceListId == null) {
            throw new IllegalArgumentException("Parameter faceListId is required and cannot be null.");
        }
        if (url == null) {
            throw new IllegalArgumentException("Parameter url is required and cannot be null.");
        }
        final String userData = addFaceFromUrlOptionalParameter != null ? addFaceFromUrlOptionalParameter.userData() : null;
        final List<Integer> targetFace = addFaceFromUrlOptionalParameter != null ? addFaceFromUrlOptionalParameter.targetFace() : null;

        return addFaceFromUrlWithServiceResponseAsync(faceListId, url, userData, targetFace);
    }

    /**
     * Add a face to a face list. The input face is specified as an image with a targetFace rectangle. It returns a persistedFaceId representing the added face, and persistedFaceId will not expire.
     *
     * @param faceListId Id referencing a particular face list.
     * @param url Publicly reachable URL of an image
     * @param userData User-specified data about the face for any purpose. The maximum length is 1KB.
     * @param targetFace A face rectangle to specify the target face to be added to a person in the format of "targetFace=left,top,width,height". E.g. "targetFace=10,10,100,100". If there is more than one face in the image, targetFace is required to specify which face to add. No targetFace means there is only one face detected in the entire image.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the PersistedFace object
     */
    public Observable<ServiceResponse<PersistedFace>> addFaceFromUrlWithServiceResponseAsync(String faceListId, String url, String userData, List<Integer> targetFace) {
        if (this.client.azureRegion() == null) {
            throw new IllegalArgumentException("Parameter this.client.azureRegion() is required and cannot be null.");
        }
        if (faceListId == null) {
            throw new IllegalArgumentException("Parameter faceListId is required and cannot be null.");
        }
        if (url == null) {
            throw new IllegalArgumentException("Parameter url is required and cannot be null.");
        }
        Validator.validate(targetFace);
        ImageUrl imageUrl = new ImageUrl();
        imageUrl.withUrl(url);
        String parameterizedHost = Joiner.on(", ").join("{AzureRegion}", this.client.azureRegion());
        String targetFaceConverted = this.client.serializerAdapter().serializeList(targetFace, CollectionFormat.CSV);
        return service.addFaceFromUrl(faceListId, userData, targetFaceConverted, this.client.acceptLanguage(), imageUrl, parameterizedHost, this.client.userAgent())
            .flatMap(new Func1<Response<ResponseBody>, Observable<ServiceResponse<PersistedFace>>>() {
                @Override
                public Observable<ServiceResponse<PersistedFace>> call(Response<ResponseBody> response) {
                    try {
                        ServiceResponse<PersistedFace> clientResponse = addFaceFromUrlDelegate(response);
                        return Observable.just(clientResponse);
                    } catch (Throwable t) {
                        return Observable.error(t);
                    }
                }
            });
    }

    private ServiceResponse<PersistedFace> addFaceFromUrlDelegate(Response<ResponseBody> response) throws APIErrorException, IOException, IllegalArgumentException {
        return this.client.restClient().responseBuilderFactory().<PersistedFace, APIErrorException>newInstance(this.client.serializerAdapter())
                .register(200, new TypeToken<PersistedFace>() { }.getType())
                .registerError(APIErrorException.class)
                .build(response);
    }

    @Override
    public FaceListsAddFaceFromUrlParameters addFaceFromUrl() {
        return new FaceListsAddFaceFromUrlParameters(this);
    }

    /**
     * Internal class implementing FaceListsAddFaceFromUrlDefinition.
     */
    class FaceListsAddFaceFromUrlParameters implements FaceListsAddFaceFromUrlDefinition {
        private FaceListsImpl parent;
        private String faceListId;
        private String url;
        private String userData;
        private List<Integer> targetFace;

        /**
         * Constructor.
         * @param parent the parent object.
         */
        FaceListsAddFaceFromUrlParameters(FaceListsImpl parent) {
            this.parent = parent;
        }

        @Override
        public FaceListsAddFaceFromUrlParameters withFaceListId(String faceListId) {
            this.faceListId = faceListId;
            return this;
        }

        @Override
        public FaceListsAddFaceFromUrlParameters withUrl(String url) {
            this.url = url;
            return this;
        }

        @Override
        public FaceListsAddFaceFromUrlParameters withUserData(String userData) {
            this.userData = userData;
            return this;
        }

        @Override
        public FaceListsAddFaceFromUrlParameters withTargetFace(List<Integer> targetFace) {
            this.targetFace = targetFace;
            return this;
        }

        @Override
        public PersistedFace execute() {
        return addFaceFromUrlWithServiceResponseAsync(faceListId, url, userData, targetFace).toBlocking().single().body();
    }

        @Override
        public Observable<PersistedFace> executeAsync() {
            return addFaceFromUrlWithServiceResponseAsync(faceListId, url, userData, targetFace).map(new Func1<ServiceResponse<PersistedFace>, PersistedFace>() {
                @Override
                public PersistedFace call(ServiceResponse<PersistedFace> response) {
                    return response.body();
                }
            });
        }
    }


    /**
     * Add a face to a face list. The input face is specified as an image with a targetFace rectangle. It returns a persistedFaceId representing the added face, and persistedFaceId will not expire.
     *
     * @param faceListId Id referencing a particular face list.
     * @param image An image stream.
     * @param addFaceFromStreamOptionalParameter the object representing the optional parameters to be set before calling this API
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @throws APIErrorException thrown if the request is rejected by server
     * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
     * @return the PersistedFace object if successful.
     */
    public PersistedFace addFaceFromStream(String faceListId, byte[] image, AddFaceFromStreamOptionalParameter addFaceFromStreamOptionalParameter) {
        return addFaceFromStreamWithServiceResponseAsync(faceListId, image, addFaceFromStreamOptionalParameter).toBlocking().single().body();
    }

    /**
     * Add a face to a face list. The input face is specified as an image with a targetFace rectangle. It returns a persistedFaceId representing the added face, and persistedFaceId will not expire.
     *
     * @param faceListId Id referencing a particular face list.
     * @param image An image stream.
     * @param addFaceFromStreamOptionalParameter the object representing the optional parameters to be set before calling this API
     * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the {@link ServiceFuture} object
     */
    public ServiceFuture<PersistedFace> addFaceFromStreamAsync(String faceListId, byte[] image, AddFaceFromStreamOptionalParameter addFaceFromStreamOptionalParameter, final ServiceCallback<PersistedFace> serviceCallback) {
        return ServiceFuture.fromResponse(addFaceFromStreamWithServiceResponseAsync(faceListId, image, addFaceFromStreamOptionalParameter), serviceCallback);
    }

    /**
     * Add a face to a face list. The input face is specified as an image with a targetFace rectangle. It returns a persistedFaceId representing the added face, and persistedFaceId will not expire.
     *
     * @param faceListId Id referencing a particular face list.
     * @param image An image stream.
     * @param addFaceFromStreamOptionalParameter the object representing the optional parameters to be set before calling this API
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the PersistedFace object
     */
    public Observable<PersistedFace> addFaceFromStreamAsync(String faceListId, byte[] image, AddFaceFromStreamOptionalParameter addFaceFromStreamOptionalParameter) {
        return addFaceFromStreamWithServiceResponseAsync(faceListId, image, addFaceFromStreamOptionalParameter).map(new Func1<ServiceResponse<PersistedFace>, PersistedFace>() {
            @Override
            public PersistedFace call(ServiceResponse<PersistedFace> response) {
                return response.body();
            }
        });
    }

    /**
     * Add a face to a face list. The input face is specified as an image with a targetFace rectangle. It returns a persistedFaceId representing the added face, and persistedFaceId will not expire.
     *
     * @param faceListId Id referencing a particular face list.
     * @param image An image stream.
     * @param addFaceFromStreamOptionalParameter the object representing the optional parameters to be set before calling this API
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the PersistedFace object
     */
    public Observable<ServiceResponse<PersistedFace>> addFaceFromStreamWithServiceResponseAsync(String faceListId, byte[] image, AddFaceFromStreamOptionalParameter addFaceFromStreamOptionalParameter) {
        if (this.client.azureRegion() == null) {
            throw new IllegalArgumentException("Parameter this.client.azureRegion() is required and cannot be null.");
        }
        if (faceListId == null) {
            throw new IllegalArgumentException("Parameter faceListId is required and cannot be null.");
        }
        if (image == null) {
            throw new IllegalArgumentException("Parameter image is required and cannot be null.");
        }
        final String userData = addFaceFromStreamOptionalParameter != null ? addFaceFromStreamOptionalParameter.userData() : null;
        final List<Integer> targetFace = addFaceFromStreamOptionalParameter != null ? addFaceFromStreamOptionalParameter.targetFace() : null;

        return addFaceFromStreamWithServiceResponseAsync(faceListId, image, userData, targetFace);
    }

    /**
     * Add a face to a face list. The input face is specified as an image with a targetFace rectangle. It returns a persistedFaceId representing the added face, and persistedFaceId will not expire.
     *
     * @param faceListId Id referencing a particular face list.
     * @param image An image stream.
     * @param userData User-specified data about the face for any purpose. The maximum length is 1KB.
     * @param targetFace A face rectangle to specify the target face to be added to a person in the format of "targetFace=left,top,width,height". E.g. "targetFace=10,10,100,100". If there is more than one face in the image, targetFace is required to specify which face to add. No targetFace means there is only one face detected in the entire image.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the PersistedFace object
     */
    public Observable<ServiceResponse<PersistedFace>> addFaceFromStreamWithServiceResponseAsync(String faceListId, byte[] image, String userData, List<Integer> targetFace) {
        if (this.client.azureRegion() == null) {
            throw new IllegalArgumentException("Parameter this.client.azureRegion() is required and cannot be null.");
        }
        if (faceListId == null) {
            throw new IllegalArgumentException("Parameter faceListId is required and cannot be null.");
        }
        if (image == null) {
            throw new IllegalArgumentException("Parameter image is required and cannot be null.");
        }
        Validator.validate(targetFace);
        String parameterizedHost = Joiner.on(", ").join("{AzureRegion}", this.client.azureRegion());
        String targetFaceConverted = this.client.serializerAdapter().serializeList(targetFace, CollectionFormat.CSV);
        RequestBody imageConverted = RequestBody.create(MediaType.parse("application/octet-stream"), image);
        return service.addFaceFromStream(faceListId, userData, targetFaceConverted, imageConverted, this.client.acceptLanguage(), parameterizedHost, this.client.userAgent())
            .flatMap(new Func1<Response<ResponseBody>, Observable<ServiceResponse<PersistedFace>>>() {
                @Override
                public Observable<ServiceResponse<PersistedFace>> call(Response<ResponseBody> response) {
                    try {
                        ServiceResponse<PersistedFace> clientResponse = addFaceFromStreamDelegate(response);
                        return Observable.just(clientResponse);
                    } catch (Throwable t) {
                        return Observable.error(t);
                    }
                }
            });
    }

    private ServiceResponse<PersistedFace> addFaceFromStreamDelegate(Response<ResponseBody> response) throws APIErrorException, IOException, IllegalArgumentException {
        return this.client.restClient().responseBuilderFactory().<PersistedFace, APIErrorException>newInstance(this.client.serializerAdapter())
                .register(200, new TypeToken<PersistedFace>() { }.getType())
                .registerError(APIErrorException.class)
                .build(response);
    }

    @Override
    public FaceListsAddFaceFromStreamParameters addFaceFromStream() {
        return new FaceListsAddFaceFromStreamParameters(this);
    }

    /**
     * Internal class implementing FaceListsAddFaceFromStreamDefinition.
     */
    class FaceListsAddFaceFromStreamParameters implements FaceListsAddFaceFromStreamDefinition {
        private FaceListsImpl parent;
        private String faceListId;
        private byte[] image;
        private String userData;
        private List<Integer> targetFace;

        /**
         * Constructor.
         * @param parent the parent object.
         */
        FaceListsAddFaceFromStreamParameters(FaceListsImpl parent) {
            this.parent = parent;
        }

        @Override
        public FaceListsAddFaceFromStreamParameters withFaceListId(String faceListId) {
            this.faceListId = faceListId;
            return this;
        }

        @Override
        public FaceListsAddFaceFromStreamParameters withImage(byte[] image) {
            this.image = image;
            return this;
        }

        @Override
        public FaceListsAddFaceFromStreamParameters withUserData(String userData) {
            this.userData = userData;
            return this;
        }

        @Override
        public FaceListsAddFaceFromStreamParameters withTargetFace(List<Integer> targetFace) {
            this.targetFace = targetFace;
            return this;
        }

        @Override
        public PersistedFace execute() {
        return addFaceFromStreamWithServiceResponseAsync(faceListId, image, userData, targetFace).toBlocking().single().body();
    }

        @Override
        public Observable<PersistedFace> executeAsync() {
            return addFaceFromStreamWithServiceResponseAsync(faceListId, image, userData, targetFace).map(new Func1<ServiceResponse<PersistedFace>, PersistedFace>() {
                @Override
                public PersistedFace call(ServiceResponse<PersistedFace> response) {
                    return response.body();
                }
            });
        }
    }

}
