diff --git a/wrappers/s2i/java/wrapper/.gitignore b/wrappers/s2i/java/wrapper/.gitignore deleted file mode 100644 index b83d22266a..0000000000 --- a/wrappers/s2i/java/wrapper/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/target/ diff --git a/wrappers/s2i/java/wrapper/Makefile b/wrappers/s2i/java/wrapper/Makefile deleted file mode 100644 index b7c19da8e3..0000000000 --- a/wrappers/s2i/java/wrapper/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -IMAGE_NAME=seldon-java-wrapper -VERSION_FILE=target/version.txt - -build_jar: update_proto - mvn clean package -B - -update_proto: - @cp -v ../../../../proto/prediction.proto src/main/proto/ - -clean: - rm -rf src/main/proto/* - mvn clean diff --git a/wrappers/s2i/java/wrapper/pom.xml b/wrappers/s2i/java/wrapper/pom.xml deleted file mode 100644 index 157e92f74a..0000000000 --- a/wrappers/s2i/java/wrapper/pom.xml +++ /dev/null @@ -1,288 +0,0 @@ - - 4.0.0 - io.seldon.wrapper - seldon-core-wrapper - jar - 0.1.1 - Seldon Core Java Wrapper - http://maven.apache.org - Wrapper for seldon-core Java prediction models. Allows easy creation of a Spring Boot app with Tomcat and gRPC servers for handling the microservice APIs for seldon-core. - - Seldon - https://www.seldon.io/ - - - - Apache License, Version 2.0 - http://www.apache.org/licenses/LICENSE-2.0 - - - - - cc - Clive Cox - cc at seldon.io - Seldon - http://www.seldon.io - - Project lead - - - - - scm:git:git://github.com/SeldonIO/seldon-core.git - https://github.com/SeldonIO/seldon-core/tree/master - scm:git:git@github.com:SeldonIO/seldon-core.git - - - - org.springframework.boot - spring-boot-starter-parent - 1.5.1.RELEASE - - - - 1.8 - UTF-8 - UTF-8 - 1.0.0 - 1.0.0-rc.1 - io.seldon.wrapper.App - - - - ossrh - https://oss.sonatype.org/content/repositories/snapshots - - - ossrh - https://oss.sonatype.org/service/local/staging/deploy/maven2/ - - - - ${project.artifactId}-${project.version} - - - kr.motd.maven - os-maven-plugin - 1.4.1.Final - - - - - org.springframework.boot - spring-boot-maven-plugin - 1.4.1.RELEASE - - - - repackage - - - exec - - - - - - maven-compiler-plugin - 3.5.1 - - 1.8 - 1.8 - UTF-8 - - - - org.springframework.boot - spring-boot-maven-plugin - - - org.xolstice.maven.plugins - protobuf-maven-plugin - 0.5.0 - - com.google.protobuf:protoc:3.1.0:exe:${os.detected.classifier} - grpc-java - io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier} - false - true - - k8s.io/**/*.proto - **/v1.proto - - - - - - compile - compile-custom - - - - - - org.apache.maven.plugins - maven-source-plugin - 2.2.1 - - - attach-sources - - jar-no-fork - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - 2.9.1 - - - attach-javadocs - - jar - - - - - - org.sonatype.plugins - nexus-staging-maven-plugin - 1.6.7 - true - - ossrh - https://oss.sonatype.org/ - true - - - - org.apache.maven.plugins - maven-gpg-plugin - 1.5 - - Seldon Dev Team - - - - sign-artifacts - verify - - sign - - - - - - - - - - - org.springframework.boot - spring-boot-starter-test - test - - - log4j - log4j - 1.2.17 - - - com.fasterxml.jackson.core - jackson-core - 2.8.6 - - - com.fasterxml.jackson.core - jackson-databind - 2.8.6 - - - commons-lang - commons-lang - 2.6 - - - - org.apache.commons - commons-lang3 - 3.5 - - - org.springframework.boot - spring-boot-starter-web - - - org.apache.httpcomponents - httpclient - 4.3.4 - - - - - io.grpc - grpc-netty - ${grpc.version} - - - io.grpc - grpc-stub - ${grpc.version} - - - io.grpc - grpc-protobuf - ${grpc.version} - - - - com.google.protobuf - protobuf-java - 3.2.0 - - - com.google.protobuf - protobuf-java-util - 3.2.0rc2 - - - com.google.guava - guava - 22.0 - - - - org.springframework.boot - spring-boot-starter-actuator - - - - ai.h2o - h2o-genmodel - 3.18.0.5 - - - org.nd4j - nd4j-native-platform - 0.9.1 - - - - org.jpmml - pmml-evaluator - 1.4.1 - - - org.jpmml - pmml-evaluator-extension - 1.4.1 - - - - - diff --git a/wrappers/s2i/java/wrapper/src/main/config/application.properties b/wrappers/s2i/java/wrapper/src/main/config/application.properties deleted file mode 100644 index 4a35865320..0000000000 --- a/wrappers/s2i/java/wrapper/src/main/config/application.properties +++ /dev/null @@ -1,7 +0,0 @@ -server.port = 9000 - -seldon.api.model.enabled=true -seldon.api.route.enabled=false - -spring.jmx.enabled = false - diff --git a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/App.java b/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/App.java deleted file mode 100644 index 239d613eb7..0000000000 --- a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/App.java +++ /dev/null @@ -1,20 +0,0 @@ -package io.seldon.wrapper; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; -import org.springframework.context.annotation.Import; -import org.springframework.scheduling.annotation.EnableAsync; - -import io.seldon.wrapper.config.AppConfig; - -@SpringBootApplication -@EnableAsync -@Import({ AppConfig.class }) -public class App { - public static void main(String[] args) throws Exception { - SpringApplication.run(App.class, args); - } - - -} diff --git a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/api/CombinerRestController.java b/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/api/CombinerRestController.java deleted file mode 100644 index e1ad4db692..0000000000 --- a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/api/CombinerRestController.java +++ /dev/null @@ -1,58 +0,0 @@ -package io.seldon.wrapper.api; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import com.google.protobuf.InvalidProtocolBufferException; - -import io.seldon.protos.PredictionProtos.SeldonMessage; -import io.seldon.protos.PredictionProtos.SeldonMessageList; -import io.seldon.wrapper.exception.APIException; -import io.seldon.wrapper.exception.APIException.ApiExceptionType; -import io.seldon.wrapper.pb.ProtoBufUtils; - -@RestController -@ConditionalOnExpression("${seldon.api.combiner.enabled:false}") -public class CombinerRestController { - - private static Logger logger = LoggerFactory.getLogger(RouterRestController.class.getName()); - - @Autowired - SeldonPredictionService predictionService; - - @RequestMapping(value = "/aggregate", method = {RequestMethod.GET, RequestMethod.POST}, produces = "application/json; charset=utf-8") - public ResponseEntity route( @RequestParam("json") String json) - { - SeldonMessageList request; - try - { - SeldonMessageList.Builder builder = SeldonMessageList.newBuilder(); - ProtoBufUtils.updateMessageBuilderFromJson(builder, json ); - request = builder.build(); - } - catch (InvalidProtocolBufferException e) - { - logger.error("Bad request",e); - throw new APIException(ApiExceptionType.WRAPPER_INVALID_MESSAGE,json); - } - - try - { - SeldonMessage response = predictionService.aggregate(request); - String res = ProtoBufUtils.toJson(response); - return new ResponseEntity(res,HttpStatus.OK); - } - catch (InvalidProtocolBufferException e) { - throw new APIException(ApiExceptionType.WRAPPER_INVALID_MESSAGE,""); - } - } -} - \ No newline at end of file diff --git a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/api/ModelRestController.java b/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/api/ModelRestController.java deleted file mode 100644 index 7ef1b857e8..0000000000 --- a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/api/ModelRestController.java +++ /dev/null @@ -1,59 +0,0 @@ -package io.seldon.wrapper.api; - - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import com.google.protobuf.InvalidProtocolBufferException; - -import io.seldon.protos.PredictionProtos.SeldonMessage; -import io.seldon.wrapper.exception.APIException; -import io.seldon.wrapper.exception.APIException.ApiExceptionType; -import io.seldon.wrapper.pb.ProtoBufUtils; - -@RestController -@ConditionalOnExpression("${seldon.api.model.enabled:false}") -public class ModelRestController { - private static Logger logger = LoggerFactory.getLogger(ModelRestController.class.getName()); - - - @Autowired - SeldonPredictionService predictionService; - - @RequestMapping(value = "/predict", method = {RequestMethod.GET, RequestMethod.POST}, produces = "application/json; charset=utf-8") - public ResponseEntity predictions( @RequestParam("json") String json) - { - SeldonMessage request; - try - { - SeldonMessage.Builder builder = SeldonMessage.newBuilder(); - ProtoBufUtils.updateMessageBuilderFromJson(builder, json ); - request = builder.build(); - } - catch (InvalidProtocolBufferException e) - { - logger.error("Bad request",e); - throw new APIException(ApiExceptionType.WRAPPER_INVALID_MESSAGE,json); - } - - try - { - SeldonMessage response = predictionService.predict(request); - String res = ProtoBufUtils.toJson(response); - return new ResponseEntity(res,HttpStatus.OK); - } - catch (InvalidProtocolBufferException e) { - throw new APIException(ApiExceptionType.WRAPPER_INVALID_MESSAGE,""); - } - - - } -} diff --git a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/api/RouterRestController.java b/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/api/RouterRestController.java deleted file mode 100644 index bc0a74a0fb..0000000000 --- a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/api/RouterRestController.java +++ /dev/null @@ -1,85 +0,0 @@ -package io.seldon.wrapper.api; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import com.google.protobuf.InvalidProtocolBufferException; - -import io.seldon.protos.PredictionProtos.Feedback; -import io.seldon.protos.PredictionProtos.SeldonMessage; -import io.seldon.wrapper.exception.APIException; -import io.seldon.wrapper.exception.APIException.ApiExceptionType; -import io.seldon.wrapper.pb.ProtoBufUtils; - -@RestController -@ConditionalOnExpression("${seldon.api.router.enabled:false}") -public class RouterRestController { - - private static Logger logger = LoggerFactory.getLogger(RouterRestController.class.getName()); - - @Autowired - SeldonPredictionService predictionService; - - @RequestMapping(value = "/route", method = {RequestMethod.GET, RequestMethod.POST}, produces = "application/json; charset=utf-8") - public ResponseEntity route( @RequestParam("json") String json) - { - SeldonMessage request; - try - { - SeldonMessage.Builder builder = SeldonMessage.newBuilder(); - ProtoBufUtils.updateMessageBuilderFromJson(builder, json ); - request = builder.build(); - } - catch (InvalidProtocolBufferException e) - { - logger.error("Bad request",e); - throw new APIException(ApiExceptionType.WRAPPER_INVALID_MESSAGE,json); - } - - try - { - SeldonMessage response = predictionService.route(request); - String res = ProtoBufUtils.toJson(response); - return new ResponseEntity(res,HttpStatus.OK); - } - catch (InvalidProtocolBufferException e) { - throw new APIException(ApiExceptionType.WRAPPER_INVALID_MESSAGE,""); - } - } - - @RequestMapping(value = "/send-feedback", method = {RequestMethod.GET, RequestMethod.POST}, produces = "application/json; charset=utf-8") - public ResponseEntity sendFeedback( @RequestParam("json") String json) - { - Feedback request; - try - { - Feedback.Builder builder = Feedback.newBuilder(); - ProtoBufUtils.updateMessageBuilderFromJson(builder, json ); - request = builder.build(); - } - catch (InvalidProtocolBufferException e) - { - logger.error("Bad request",e); - throw new APIException(ApiExceptionType.WRAPPER_INVALID_MESSAGE,json); - } - - try - { - SeldonMessage response = predictionService.sendFeedback(request); - String res = ProtoBufUtils.toJson(response); - return new ResponseEntity(res,HttpStatus.OK); - } - catch (InvalidProtocolBufferException e) { - throw new APIException(ApiExceptionType.WRAPPER_INVALID_MESSAGE,""); - } - } - -} \ No newline at end of file diff --git a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/api/SeldonPredictionService.java b/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/api/SeldonPredictionService.java deleted file mode 100644 index 70f575689d..0000000000 --- a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/api/SeldonPredictionService.java +++ /dev/null @@ -1,26 +0,0 @@ -package io.seldon.wrapper.api; - -import io.seldon.protos.PredictionProtos.Feedback; -import io.seldon.protos.PredictionProtos.SeldonMessage; -import io.seldon.protos.PredictionProtos.SeldonMessageList; - -public interface SeldonPredictionService { - default public SeldonMessage predict(SeldonMessage request) { - return null; - } - default public SeldonMessage route(SeldonMessage request) { - return null; - } - default public SeldonMessage sendFeedback(Feedback request) { - return null; - } - default public SeldonMessage transformInput(SeldonMessage request) { - return null; - } - default public SeldonMessage transformOutput(SeldonMessage request) { - return null; - } - default public SeldonMessage aggregate(SeldonMessageList request) { - return null; - } -} diff --git a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/api/TransformerRestController.java b/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/api/TransformerRestController.java deleted file mode 100644 index 474ec8c706..0000000000 --- a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/api/TransformerRestController.java +++ /dev/null @@ -1,84 +0,0 @@ -package io.seldon.wrapper.api; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import com.google.protobuf.InvalidProtocolBufferException; - -import io.seldon.protos.PredictionProtos.SeldonMessage; -import io.seldon.wrapper.exception.APIException; -import io.seldon.wrapper.exception.APIException.ApiExceptionType; -import io.seldon.wrapper.pb.ProtoBufUtils; - -@RestController -@ConditionalOnExpression("${seldon.api.transformer.enabled:false}") -public class TransformerRestController { - - private static Logger logger = LoggerFactory.getLogger(TransformerRestController.class.getName()); - - @Autowired - SeldonPredictionService predictionService; - - @RequestMapping(value = "/transform-input", method = {RequestMethod.GET, RequestMethod.POST}, produces = "application/json; charset=utf-8") - public ResponseEntity transformInput( @RequestParam("json") String json) - { - SeldonMessage request; - try - { - SeldonMessage.Builder builder = SeldonMessage.newBuilder(); - ProtoBufUtils.updateMessageBuilderFromJson(builder, json ); - request = builder.build(); - } - catch (InvalidProtocolBufferException e) - { - logger.error("Bad request",e); - throw new APIException(ApiExceptionType.WRAPPER_INVALID_MESSAGE,json); - } - - try - { - SeldonMessage response = predictionService.transformInput(request); - String res = ProtoBufUtils.toJson(response); - return new ResponseEntity(res,HttpStatus.OK); - } - catch (InvalidProtocolBufferException e) { - throw new APIException(ApiExceptionType.WRAPPER_INVALID_MESSAGE,""); - } - } - - @RequestMapping(value = "/transform-output", method = {RequestMethod.GET, RequestMethod.POST}, produces = "application/json; charset=utf-8") - public ResponseEntity transformOutput( @RequestParam("json") String json) - { - SeldonMessage request; - try - { - SeldonMessage.Builder builder = SeldonMessage.newBuilder(); - ProtoBufUtils.updateMessageBuilderFromJson(builder, json ); - request = builder.build(); - } - catch (InvalidProtocolBufferException e) - { - logger.error("Bad request",e); - throw new APIException(ApiExceptionType.WRAPPER_INVALID_MESSAGE,json); - } - - try - { - SeldonMessage response = predictionService.transformOutput(request); - String res = ProtoBufUtils.toJson(response); - return new ResponseEntity(res,HttpStatus.OK); - } - catch (InvalidProtocolBufferException e) { - throw new APIException(ApiExceptionType.WRAPPER_INVALID_MESSAGE,""); - } - } -} - \ No newline at end of file diff --git a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/config/AppConfig.java b/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/config/AppConfig.java deleted file mode 100644 index d55b9e53ce..0000000000 --- a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/config/AppConfig.java +++ /dev/null @@ -1,100 +0,0 @@ -package io.seldon.wrapper.config; - -import java.util.concurrent.Executor; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; - -import org.apache.catalina.connector.Connector; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.config.ConfigurableBeanFactory; -import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer; -import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer; -import org.springframework.boot.context.embedded.tomcat.TomcatConnectorCustomizer; -import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory; -import org.springframework.context.ApplicationListener; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Scope; -import org.springframework.context.event.ContextClosedEvent; - - -/** - * Spring REST config - * @author clive - * - */ -public class AppConfig { - - @Bean - @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) - public EmbeddedServletContainerCustomizer containerCustomizer() { - return new CustomizationBean(); - } - - @Bean - public GracefulShutdown gracefulShutdown() { - return new GracefulShutdown(); - } - - @Bean - public EmbeddedServletContainerCustomizer tomcatCustomizer() { - return new EmbeddedServletContainerCustomizer() { - - @Override - public void customize(ConfigurableEmbeddedServletContainer container) { - if (container instanceof TomcatEmbeddedServletContainerFactory) { - ((TomcatEmbeddedServletContainerFactory) container) - .addConnectorCustomizers(gracefulShutdown()); - } - - } - }; - } - - /** - * Ensure a graceful shutdown of Tomcat to allow requests in process to complete. - * @author clive - * - */ - private static class GracefulShutdown implements TomcatConnectorCustomizer, - ApplicationListener { - - private static final Logger log = LoggerFactory.getLogger(GracefulShutdown.class); - - private volatile Connector connector; - - @Override - public void customize(Connector connector) { - this.connector = connector; - } - - @Override - public void onApplicationEvent(ContextClosedEvent event) { - log.info("Starting graceful shutdown of Tomcat"); - if (this.connector != null) - { - this.connector.pause(); - Executor executor = this.connector.getProtocolHandler().getExecutor(); - if (executor instanceof ThreadPoolExecutor) { - try { - ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor; - threadPoolExecutor.shutdown(); - if (!threadPoolExecutor.awaitTermination(20, TimeUnit.SECONDS)) { - log.warn("Tomcat thread pool did not shut down gracefully within " - + "20 seconds. Proceeding with forceful shutdown"); - } - else - { - log.info("Thread pool has closed"); - } - } - catch (InterruptedException ex) { - Thread.currentThread().interrupt(); - } - } - } - } - - } -} - diff --git a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/config/CustomizationBean.java b/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/config/CustomizationBean.java deleted file mode 100644 index bb9839d6ca..0000000000 --- a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/config/CustomizationBean.java +++ /dev/null @@ -1,47 +0,0 @@ -/******************************************************************************* - * Copyright 2017 Seldon Technologies Ltd (http://www.seldon.io/) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *******************************************************************************/ -package io.seldon.wrapper.config; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer; -import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer; - -/** - * Customization of the Tomcat embedded servlet engne - * @author clive - * - */ -public class CustomizationBean implements EmbeddedServletContainerCustomizer { - - private final static Logger logger = LoggerFactory.getLogger(CustomizationBean.class); - - @Value("${server.port}") - private Integer defaultServerPort; - - @Override - public void customize(ConfigurableEmbeddedServletContainer container) { - logger.info("Customizing EmbeddedServlet"); - - Integer serverPort; - serverPort = defaultServerPort; - - logger.info("setting serverPort[{}]", serverPort); - container.setPort(serverPort); - } - -} diff --git a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/exception/APIException.java b/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/exception/APIException.java deleted file mode 100644 index 33603cb49b..0000000000 --- a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/exception/APIException.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Seldon -- open source prediction engine - * ======================================= - * - * Copyright 2011-2017 Seldon Technologies Ltd and Rummble Ltd (http://www.seldon.io/) - * - * ******************************************************************************************** - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * ******************************************************************************************** - */ - -package io.seldon.wrapper.exception; - -/** - * API Exceptions - * @author clive - * - */ -public class APIException extends RuntimeException { - - public enum ApiExceptionType { - - WRAPPER_INVALID_MESSAGE(201,"Invalid prediction message",500); - - int id; - String message; - int httpCode; - - ApiExceptionType(int id,String message,int httpCode) { - this.id = id; - this.message = message; - this.httpCode = httpCode; - } - - public int getId() { - return id; - } - - public String getMessage() { - return message; - } - - public int getHttpCode() { - return httpCode; - } - - - }; - - ApiExceptionType apiExceptionType; - String info; - - public APIException(ApiExceptionType apiExceptionType,String info) { - super(); - this.apiExceptionType = apiExceptionType; - this.info = info; - } - - public ApiExceptionType getApiExceptionType() { - return apiExceptionType; - } - - public void setApiExceptionType(ApiExceptionType apiExceptionType) { - this.apiExceptionType = apiExceptionType; - } - - public String getInfo() { - return info; - } - - public void setInfo(String info) { - this.info = info; - } - -} diff --git a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/grpc/CombinerService.java b/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/grpc/CombinerService.java deleted file mode 100644 index 90d74c735c..0000000000 --- a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/grpc/CombinerService.java +++ /dev/null @@ -1,26 +0,0 @@ -package io.seldon.wrapper.grpc; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.seldon.protos.CombinerGrpc; - -public class CombinerService extends CombinerGrpc.CombinerImplBase { - - protected static Logger logger = LoggerFactory.getLogger(CombinerService.class.getName()); - - private SeldonGrpcServer server; - - public CombinerService(SeldonGrpcServer server) { - super(); - this.server = server; - } - - @Override - public void aggregate(io.seldon.protos.PredictionProtos.SeldonMessageList request, - io.grpc.stub.StreamObserver responseObserver) { - logger.debug("Received aggregate request"); - responseObserver.onNext(server.getPredictionService().aggregate(request)); - responseObserver.onCompleted(); - } -} \ No newline at end of file diff --git a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/grpc/GenericService.java b/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/grpc/GenericService.java deleted file mode 100644 index b4047324a7..0000000000 --- a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/grpc/GenericService.java +++ /dev/null @@ -1,60 +0,0 @@ -package io.seldon.wrapper.grpc; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.seldon.protos.GenericGrpc; - -public class GenericService extends GenericGrpc.GenericImplBase { - - protected static Logger logger = LoggerFactory.getLogger(GenericService.class.getName()); - - private SeldonGrpcServer server; - - public GenericService(SeldonGrpcServer server) { - super(); - this.server = server; - } - - @Override - public void transformInput(io.seldon.protos.PredictionProtos.SeldonMessage request, - io.grpc.stub.StreamObserver responseObserver) { - logger.debug("Received transformInput request"); - responseObserver.onNext(server.getPredictionService().transformInput(request)); - responseObserver.onCompleted(); - } - - @Override - public void route(io.seldon.protos.PredictionProtos.SeldonMessage request, - io.grpc.stub.StreamObserver responseObserver) { - logger.debug("Received route request"); - responseObserver.onNext(server.getPredictionService().route(request)); - responseObserver.onCompleted(); - } - - @Override - public void sendFeedback(io.seldon.protos.PredictionProtos.Feedback request, - io.grpc.stub.StreamObserver responseObserver) { - logger.debug("Received sendFeedback request"); - responseObserver.onNext(server.getPredictionService().sendFeedback(request)); - responseObserver.onCompleted(); - } - - - - @Override - public void transformOutput(io.seldon.protos.PredictionProtos.SeldonMessage request, - io.grpc.stub.StreamObserver responseObserver) { - logger.debug("Received transformOutput request"); - responseObserver.onNext(server.getPredictionService().transformOutput(request)); - responseObserver.onCompleted(); - } - - @Override - public void aggregate(io.seldon.protos.PredictionProtos.SeldonMessageList request, - io.grpc.stub.StreamObserver responseObserver) { - logger.debug("Received aggregate request"); - responseObserver.onNext(server.getPredictionService().aggregate(request)); - responseObserver.onCompleted(); - } -} diff --git a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/grpc/ModelService.java b/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/grpc/ModelService.java deleted file mode 100644 index 25f558bef2..0000000000 --- a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/grpc/ModelService.java +++ /dev/null @@ -1,48 +0,0 @@ -/******************************************************************************* - * Copyright 2017 Seldon Technologies Ltd (http://www.seldon.io/) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *******************************************************************************/ -package io.seldon.wrapper.grpc; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.seldon.protos.ModelGrpc; - -/** - * Passes gRPC requests on to the engine. - * @author clive - * - */ -public class ModelService extends ModelGrpc.ModelImplBase { - - protected static Logger logger = LoggerFactory.getLogger(ModelService.class.getName()); - - private SeldonGrpcServer server; - - public ModelService(SeldonGrpcServer server) { - super(); - this.server = server; - } - - @Override - public void predict(io.seldon.protos.PredictionProtos.SeldonMessage request, - io.grpc.stub.StreamObserver responseObserver) { - logger.debug("Received predict request"); - - responseObserver.onNext(server.getPredictionService().predict(request)); - responseObserver.onCompleted(); - } - -} diff --git a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/grpc/OutputTransformerService.java b/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/grpc/OutputTransformerService.java deleted file mode 100644 index 6ccedcc99c..0000000000 --- a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/grpc/OutputTransformerService.java +++ /dev/null @@ -1,26 +0,0 @@ -package io.seldon.wrapper.grpc; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.seldon.protos.OutputTransformerGrpc; - -public class OutputTransformerService extends OutputTransformerGrpc.OutputTransformerImplBase { - - protected static Logger logger = LoggerFactory.getLogger(OutputTransformerService.class.getName()); - - private SeldonGrpcServer server; - - public OutputTransformerService(SeldonGrpcServer server) { - super(); - this.server = server; - } - - @Override - public void transformOutput(io.seldon.protos.PredictionProtos.SeldonMessage request, - io.grpc.stub.StreamObserver responseObserver) { - logger.debug("Received transformOutput request"); - responseObserver.onNext(server.getPredictionService().transformOutput(request)); - responseObserver.onCompleted(); - } -} \ No newline at end of file diff --git a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/grpc/RouterService.java b/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/grpc/RouterService.java deleted file mode 100644 index 6589451723..0000000000 --- a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/grpc/RouterService.java +++ /dev/null @@ -1,38 +0,0 @@ -package io.seldon.wrapper.grpc; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.seldon.protos.RouterGrpc; - -public class RouterService extends RouterGrpc.RouterImplBase { - - protected static Logger logger = LoggerFactory.getLogger(RouterService.class.getName()); - - private SeldonGrpcServer server; - - public RouterService(SeldonGrpcServer server) { - super(); - this.server = server; - } - - @Override - public void route(io.seldon.protos.PredictionProtos.SeldonMessage request, - io.grpc.stub.StreamObserver responseObserver) { - logger.debug("Received route request"); - responseObserver.onNext(server.getPredictionService().route(request)); - responseObserver.onCompleted(); - } - - @Override - public void sendFeedback(io.seldon.protos.PredictionProtos.Feedback request, - io.grpc.stub.StreamObserver responseObserver) { - logger.debug("Received sendFeedback request"); - responseObserver.onNext(server.getPredictionService().sendFeedback(request)); - responseObserver.onCompleted(); - } - - - -} - diff --git a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/grpc/SeldonGrpcServer.java b/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/grpc/SeldonGrpcServer.java deleted file mode 100644 index 24e08640eb..0000000000 --- a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/grpc/SeldonGrpcServer.java +++ /dev/null @@ -1,109 +0,0 @@ -/******************************************************************************* - * Copyright 2017 Seldon Technologies Ltd (http://www.seldon.io/) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *******************************************************************************/ -package io.seldon.wrapper.grpc; - -import java.io.IOException; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.scheduling.annotation.Async; -import org.springframework.stereotype.Component; - -import io.grpc.Server; -import io.grpc.ServerBuilder; -import io.seldon.wrapper.api.SeldonPredictionService; - -@Component -public class SeldonGrpcServer { - protected static Logger logger = LoggerFactory.getLogger(SeldonGrpcServer.class.getName()); - - public static final int SERVER_PORT = 5001; - - private final int port; - private final Server server; - - private final SeldonPredictionService predictionService; - - @Autowired - public SeldonGrpcServer(SeldonPredictionService predictionService,@Value("${grpc.port}") Integer grpcPort) - { - logger.info("grpc port {}",grpcPort); - - port = grpcPort; - - this.predictionService = predictionService; - server = ServerBuilder - .forPort(port) - .addService(new ModelService(this)) - .addService(new RouterService(this)) - .addService(new TransformerService(this)) - .addService(new OutputTransformerService(this)) - .addService(new CombinerService(this)) - .addService(new GenericService(this)) - .build(); - } - - - - public SeldonPredictionService getPredictionService() { - return predictionService; - } - - @Async - public void runServer() throws InterruptedException, IOException - { - logger.info("Starting grpc server"); - start(); - blockUntilShutdown(); - } - - /** - * Start serving requests. - */ - public void start() throws IOException { - server.start(); - logger.info("Server started, listening on " + port); - Runtime.getRuntime().addShutdownHook(new Thread() { - @Override - public void run() { - // Use stderr here since the logger may has been reset by its JVM shutdown hook. - System.err.println("*** shutting down gRPC server since JVM is shutting down"); - SeldonGrpcServer.this.stop(); - System.err.println("*** server shut down"); - } - }); - } - - /** Stop serving requests and shutdown resources. */ - public void stop() { - if (server != null) { - server.shutdown(); - } - } - - /** - * Await termination on the main thread since the grpc library uses daemon threads. - */ - private void blockUntilShutdown() throws InterruptedException { - if (server != null) { - server.awaitTermination(); - } - } - - -} diff --git a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/grpc/SeldonGrpcServerInitializer.java b/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/grpc/SeldonGrpcServerInitializer.java deleted file mode 100644 index 0555cbdef0..0000000000 --- a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/grpc/SeldonGrpcServerInitializer.java +++ /dev/null @@ -1,47 +0,0 @@ -/******************************************************************************* - * Copyright 2017 Seldon Technologies Ltd (http://www.seldon.io/) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *******************************************************************************/ -package io.seldon.wrapper.grpc; - -import java.io.IOException; - -import javax.annotation.PostConstruct; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -@Component -public class SeldonGrpcServerInitializer { - - protected static Logger logger = LoggerFactory.getLogger(SeldonGrpcServerInitializer.class.getName()); - - @Autowired - SeldonGrpcServer server; - - @PostConstruct - public void initialise() { - try - { - server.runServer(); - } catch (InterruptedException e) { - logger.error("Failed to start grc server",e); - } catch (IOException e) { - logger.error("Failed to start grc server",e); - } - } - -} diff --git a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/grpc/TransformerService.java b/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/grpc/TransformerService.java deleted file mode 100644 index d9c60a05cc..0000000000 --- a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/grpc/TransformerService.java +++ /dev/null @@ -1,26 +0,0 @@ -package io.seldon.wrapper.grpc; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.seldon.protos.TransformerGrpc; - -public class TransformerService extends TransformerGrpc.TransformerImplBase { - - protected static Logger logger = LoggerFactory.getLogger(TransformerService.class.getName()); - - private SeldonGrpcServer server; - - public TransformerService(SeldonGrpcServer server) { - super(); - this.server = server; - } - - @Override - public void transformInput(io.seldon.protos.PredictionProtos.SeldonMessage request, - io.grpc.stub.StreamObserver responseObserver) { - logger.debug("Received transformInput request"); - responseObserver.onNext(server.getPredictionService().transformInput(request)); - responseObserver.onCompleted(); - } -} diff --git a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/pb/ProtoBufUtils.java b/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/pb/ProtoBufUtils.java deleted file mode 100644 index 7794ec8bb2..0000000000 --- a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/pb/ProtoBufUtils.java +++ /dev/null @@ -1,69 +0,0 @@ -/******************************************************************************* - * Copyright 2017 Seldon Technologies Ltd (http://www.seldon.io/) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *******************************************************************************/ -package io.seldon.wrapper.pb; - -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.Message; -import com.google.protobuf.util.JsonFormat; -import com.google.protobuf.util.JsonFormat.Printer; - -public class ProtoBufUtils { - - private ProtoBufUtils() { - } - - /** - * Serialize a protobuf message to JSON, indicating if whitespace needs to be stripped. - * - * @param message - * The protobuf message to serialize. - * @param omittingInsignificantWhitespace - * True if needs to be stripped of whitespace. - * @return json string - * @throws InvalidProtocolBufferException - */ - public static String toJson(Message message, boolean omittingInsignificantWhitespace) throws InvalidProtocolBufferException { - String json = null; - // json = JsonFormat.printer().includingDefaultValueFields().preservingProtoFieldNames().print(message); - // json = - // JsonFormat.printer().includingDefaultValueFields().preservingProtoFieldNames().omittingInsignificantWhitespace().print(message); - - Printer jsonPrinter = JsonFormat.printer().includingDefaultValueFields().preservingProtoFieldNames(); - if (omittingInsignificantWhitespace) { - jsonPrinter = jsonPrinter.omittingInsignificantWhitespace(); - } - return jsonPrinter.print(message); - } - - /** - * Serialize a protobuf message to JSON, allowing the inclusion of whitespace. - * - * @param message - * The protobuf message to serialize. - * @return json string - * @throws InvalidProtocolBufferException - */ - public static String toJson(Message message) throws InvalidProtocolBufferException { - boolean omittingInsignificantWhitespace = false; - return toJson(message, omittingInsignificantWhitespace); - } - - public static void updateMessageBuilderFromJson(T messageBuilder, String json) throws InvalidProtocolBufferException { - JsonFormat.parser().ignoringUnknownFields() - .merge(json, messageBuilder); - } - -} diff --git a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/utils/DL4JUtils.java b/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/utils/DL4JUtils.java deleted file mode 100644 index db6ae5f4e2..0000000000 --- a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/utils/DL4JUtils.java +++ /dev/null @@ -1,115 +0,0 @@ -package io.seldon.wrapper.utils; - -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; - -import org.nd4j.linalg.api.ndarray.INDArray; -import org.nd4j.linalg.factory.Nd4j; - -import com.google.protobuf.ListValue; -import com.google.protobuf.Value; - -import io.seldon.protos.PredictionProtos.DefaultData; -import io.seldon.protos.PredictionProtos.Tensor; -import io.seldon.protos.PredictionProtos.DefaultData.DataOneofCase; - -/** - * Utilities for working with Deep Learning4J Models - * @author clive - * - */ -public class DL4JUtils { - - /** - * Convert seldon protobuf DefaultData to nd4j Array - * @param data Seldon protobuf message - * @return nd4j Array - */ - public static INDArray getINDArray(DefaultData data) { - - if (data.getDataOneofCase() == DataOneofCase.TENSOR) { - - List valuesList = data.getTensor().getValuesList(); - List shapeList = data.getTensor().getShapeList(); - - double[] values = new double[valuesList.size()]; - int[] shape = new int[shapeList.size()]; - for (int i = 0; i < values.length; i++) { - values[i] = valuesList.get(i); - } - for (int i = 0; i < shape.length; i++) { - shape[i] = shapeList.get(i); - } - - INDArray newArr = Nd4j.create(values, shape, 'c'); - - return newArr; - } else if (data.getDataOneofCase() == DataOneofCase.NDARRAY) { - ListValue list = data.getNdarray(); - int bLength = list.getValuesCount(); - int vLength = list.getValues(0).getListValue().getValuesCount(); - - double[] values = new double[bLength * vLength]; - int[] shape = { bLength, vLength }; - - for (int i = 0; i < bLength; ++i) { - for (int j = 0; j < vLength; j++) { - values[i * bLength + j] = list.getValues(i).getListValue().getValues(j).getNumberValue(); - } - } - - INDArray newArr = Nd4j.create(values, shape, 'c'); - - return newArr; - } - return null; - } - - /** - * Convert a nd4j array into a seldon protobuf DefaultData following same type as oldData - * @param oldData original data - * @param newData nd4j array - * @return seldon DefaultData protobuf message - */ - public static DefaultData updateData(DefaultData oldData, INDArray newData) { - DefaultData.Builder dataBuilder = DefaultData.newBuilder(); - - dataBuilder.addAllNames(oldData.getNamesList()); - - // int index=0; - // for (Iterator i = oldData.getFeaturesList().iterator(); - // i.hasNext();){ - // dataBuilder.setFeatures(index, i.next()); - // index++; - // } - - if (oldData == null || oldData.getDataOneofCase() == DataOneofCase.TENSOR) { - Tensor.Builder tBuilder = Tensor.newBuilder(); - List shapeList = Arrays.stream(newData.shape()).boxed().collect(Collectors.toList()); - tBuilder.addAllShape(shapeList); - - for (int i = 0; i < shapeList.get(0); ++i) { - for (int j = 0; j < shapeList.get(1); ++j) { - tBuilder.addValues(newData.getDouble(i, j)); - } - } - dataBuilder.setTensor(tBuilder); - return dataBuilder.build(); - } else if (oldData.getDataOneofCase() == DataOneofCase.NDARRAY) { - ListValue.Builder b1 = ListValue.newBuilder(); - for (int i = 0; i < newData.shape()[0]; ++i) { - ListValue.Builder b2 = ListValue.newBuilder(); - for (int j = 0; j < newData.shape()[1]; j++) { - b2.addValues(Value.newBuilder().setNumberValue(newData.getDouble(i, j))); - } - b1.addValues(Value.newBuilder().setListValue(b2.build())); - } - dataBuilder.setNdarray(b1.build()); - return dataBuilder.build(); - } - return null; - - } - -} diff --git a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/utils/H2OUtils.java b/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/utils/H2OUtils.java deleted file mode 100644 index 9c8a956d3f..0000000000 --- a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/utils/H2OUtils.java +++ /dev/null @@ -1,183 +0,0 @@ -package io.seldon.wrapper.utils; - -import java.util.ArrayList; -import java.util.List; - -import org.nd4j.linalg.dataset.api.iterator.CachingDataSetIterator; - -import com.google.protobuf.ListValue; -import com.google.protobuf.Value; - -import hex.genmodel.easy.RowData; -import hex.genmodel.easy.prediction.AbstractPrediction; -import hex.genmodel.easy.prediction.BinomialModelPrediction; -import hex.genmodel.easy.prediction.ClusteringModelPrediction; -import hex.genmodel.easy.prediction.DimReductionModelPrediction; -import hex.genmodel.easy.prediction.MultinomialModelPrediction; -import hex.genmodel.easy.prediction.OrdinalModelPrediction; -import hex.genmodel.easy.prediction.RegressionModelPrediction; -import io.seldon.protos.PredictionProtos.DefaultData; -import io.seldon.protos.PredictionProtos.Tensor; -import io.seldon.protos.PredictionProtos.DefaultData.DataOneofCase; - -/** - * Utilities for working with H2O models - * - * @author clive - * - */ -public class H2OUtils { - - /** - * Convert a Seldon Default Data into H2O RowData - * @param data Seldon protobuf data - * @return List of H2O RowData - */ - public static List convertSeldonMessage(DefaultData data) { - List out = new ArrayList<>(); - if (data.getDataOneofCase() == DataOneofCase.TENSOR) { - - List valuesList = data.getTensor().getValuesList(); - List shapeList = data.getTensor().getShapeList(); - - if (shapeList.size() > 2) { - return null; - } - - int cols = 0; - if (shapeList.size() == 1) - cols = shapeList.get(0); - else - cols = shapeList.get(1); - RowData row = new RowData(); - for (int i = 0; i < valuesList.size(); i++) { - if (i > 0 && i % cols == 0) { - out.add(row); - row = new RowData(); - } - String name = data.getNamesCount() > 0 ? data.getNames(i % cols) : "" + (i % cols); - row.put(name, valuesList.get(i)); - } - out.add(row); - - return out; - } else if (data.getDataOneofCase() == DataOneofCase.NDARRAY) { - ListValue list = data.getNdarray(); - int rows = list.getValuesCount(); - int cols = list.getValues(0).getListValue().getValuesCount(); - - for (int i = 0; i < rows; ++i) { - RowData row = new RowData(); - for (int j = 0; j < cols; j++) { - String name = data.getNamesCount() > 0 ? data.getNames(j % cols) : "" + (j % cols); - Object value; - Value listValue = list.getValues(i).getListValue().getValues(j); - switch(listValue.getKindCase()) { - case NUMBER_VALUE: - value = listValue.getNumberValue(); - break; - case STRING_VALUE: - value = listValue.getStringValue(); - break; - case BOOL_VALUE: - //Get value as String - value = listValue.getStringValue(); - break; - case NULL_VALUE: - // Treat Nulls as 0 - value = 0.0; - break; - case LIST_VALUE: - throw new UnsupportedOperationException("Only 2-D arrays unsupported for H2O conversion"); - case STRUCT_VALUE: - throw new UnsupportedOperationException("Struct in NDArray unsupported for H2O conversion"); - default: - throw new UnsupportedOperationException("Unknown kind in NDArray"); - } - row.put(name, value); - } - out.add(row); - } - return out; - } else - return null; - } - - /** - * Convert a prediction result from H2O to Seldon protobuf DefaultData with same type as input - * @param predictions The H2O predictions - * @param input The original input - * @return A seldon DefaultData protobuf message - */ - public static DefaultData convertH2OPrediction(List predictions, DefaultData input) { - if (input == null || input.getDataOneofCase() == DataOneofCase.TENSOR) { - int rows = predictions.size(); - Tensor.Builder tBuilder = Tensor.newBuilder(); - for (AbstractPrediction p : predictions) { - if (p instanceof BinomialModelPrediction) { - BinomialModelPrediction bp = (BinomialModelPrediction) p; - for (int i = 0; i < bp.classProbabilities.length; i++) - tBuilder.addValues(bp.classProbabilities[i]); - } else if (p instanceof MultinomialModelPrediction) { - MultinomialModelPrediction mp = (MultinomialModelPrediction) p; - for (int i = 0; i < mp.classProbabilities.length; i++) - tBuilder.addValues(mp.classProbabilities[i]); - } else if (p instanceof OrdinalModelPrediction) { - OrdinalModelPrediction op = (OrdinalModelPrediction) p; - for (int i = 0; i < op.classProbabilities.length; i++) - tBuilder.addValues(op.classProbabilities[i]); - } else if (p instanceof ClusteringModelPrediction) { - ClusteringModelPrediction cp = (ClusteringModelPrediction) p; - for (int i = 0; i < cp.distances.length; i++) - tBuilder.addValues(cp.distances[i]); - } else if (p instanceof RegressionModelPrediction) { - RegressionModelPrediction r = (RegressionModelPrediction) p; - tBuilder.addValues(r.value); - } else if (p instanceof DimReductionModelPrediction) { - DimReductionModelPrediction cp = (DimReductionModelPrediction) p; - for (int i = 0; i < cp.dimensions.length; i++) - tBuilder.addValues(cp.dimensions[i]); - } else - return null; - } - DefaultData.Builder dataBuilder = DefaultData.newBuilder(); - dataBuilder.setTensor(tBuilder); - return dataBuilder.build(); - } else if (input.getDataOneofCase() == DataOneofCase.NDARRAY) { - ListValue.Builder rows = ListValue.newBuilder(); - for (AbstractPrediction p : predictions) { - ListValue.Builder row = ListValue.newBuilder(); - if (p instanceof BinomialModelPrediction) { - BinomialModelPrediction bp = (BinomialModelPrediction) p; - for (int i = 0; i < bp.classProbabilities.length; i++) - row.addValues(Value.newBuilder().setNumberValue(bp.classProbabilities[i])); - } else if (p instanceof MultinomialModelPrediction) { - MultinomialModelPrediction mp = (MultinomialModelPrediction) p; - for (int i = 0; i < mp.classProbabilities.length; i++) - row.addValues(Value.newBuilder().setNumberValue(mp.classProbabilities[i])); - } else if (p instanceof OrdinalModelPrediction) { - OrdinalModelPrediction op = (OrdinalModelPrediction) p; - for (int i = 0; i < op.classProbabilities.length; i++) - row.addValues(Value.newBuilder().setNumberValue(op.classProbabilities[i])); - } else if (p instanceof ClusteringModelPrediction) { - ClusteringModelPrediction cp = (ClusteringModelPrediction) p; - for (int i = 0; i < cp.distances.length; i++) - row.addValues(Value.newBuilder().setNumberValue(cp.distances[i])); - } else if (p instanceof RegressionModelPrediction) { - RegressionModelPrediction r = (RegressionModelPrediction) p; - row.addValues(Value.newBuilder().setNumberValue(r.value)); - } else if (p instanceof DimReductionModelPrediction) { - DimReductionModelPrediction cp = (DimReductionModelPrediction) p; - for (int i = 0; i < cp.dimensions.length; i++) - row.addValues(Value.newBuilder().setNumberValue(cp.dimensions[i])); - } else - return null; - rows.addValues(Value.newBuilder().setListValue(row.build())); - } - DefaultData.Builder dataBuilder = DefaultData.newBuilder(); - dataBuilder.setNdarray(rows.build()); - return dataBuilder.build(); - } else - return null; - } -} diff --git a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/utils/PMMLUtils.java b/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/utils/PMMLUtils.java deleted file mode 100644 index 266b9ebcd0..0000000000 --- a/wrappers/s2i/java/wrapper/src/main/java/io/seldon/wrapper/utils/PMMLUtils.java +++ /dev/null @@ -1,193 +0,0 @@ -package io.seldon.wrapper.utils; - -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.dmg.pmml.FieldName; -import org.dmg.pmml.MiningFunction; -import org.dmg.pmml.PMML; -import org.jpmml.evaluator.Evaluator; -import org.jpmml.evaluator.FieldValue; -import org.jpmml.evaluator.InputField; -import org.jpmml.evaluator.ModelEvaluatorFactory; -import org.jpmml.evaluator.ProbabilityDistribution; -import org.jpmml.evaluator.ReportingValueFactoryFactory; -import org.jpmml.evaluator.TargetField; -import org.jpmml.evaluator.ValueFactoryFactory; - -import com.google.protobuf.ListValue; -import com.google.protobuf.Value; - -import hex.genmodel.easy.RowData; -import io.seldon.protos.PredictionProtos.DefaultData; -import io.seldon.protos.PredictionProtos.DefaultData.DataOneofCase; -import io.seldon.protos.PredictionProtos.Tensor; -import io.seldon.wrapper.exception.APIException; -import io.seldon.wrapper.exception.APIException.ApiExceptionType; - -public class PMMLUtils { - - - public static abstract class ValuesBuilder { - public abstract void addValues(double v); - } - - public static class TensorBuilder extends ValuesBuilder { - Tensor.Builder b; - - public TensorBuilder(Tensor.Builder b) { - super(); - this.b = b; - } - - @Override - public void addValues(double v) { - b.addValues(v); - } - } - - public static class ListBuilder extends ValuesBuilder { - ListValue.Builder b; - - public ListBuilder(ListValue.Builder b) { - super(); - this.b = b; - } - - @Override - public void addValues(double v) { - b.addValues(Value.newBuilder().setNumberValue(v)); - } - } - - private Map getInputFieldMap(Evaluator evaluator) - { - Map fieldMap = new HashMap<>(); - List inputFields = evaluator.getInputFields(); - for(InputField inputField : inputFields){ - FieldName inputFieldName = inputField.getName(); - fieldMap.put(inputFieldName.getValue(), inputField); - } - return fieldMap; - } - - - private void evaluateForTensor(Evaluator evaluator,Map arguments,ValuesBuilder tBuilder) - { - Map result = evaluator.evaluate(arguments); - List targetFields = evaluator.getTargetFields(); - MiningFunction miningFunction = evaluator.getMiningFunction(); - TargetField targetField = targetFields.get(0); - switch(miningFunction){ - case CLASSIFICATION: - FieldName targetFieldName = targetField.getName(); - Object targetFieldValue = result.get(targetFieldName); - if (targetFieldValue instanceof ProbabilityDistribution) - { - ProbabilityDistribution prob = (ProbabilityDistribution) targetFieldValue; - Set categories = prob.getCategories(); - for (String k : categories) - { - Double v = prob.getValue(k); - tBuilder.addValues(v); - } - arguments.clear(); - return; - } - else - throw new IllegalArgumentException("Expected probability distribution"); - case REGRESSION: - default: - throw new IllegalArgumentException("Expected a classification model, got " + miningFunction); - } - } - - public DefaultData evaluate(PMML model,DefaultData data) { - - if (data.getNamesCount() == 0) - { - throw new APIException(APIException.ApiExceptionType.WRAPPER_INVALID_MESSAGE, "Data for PMML models must contain names for the fields in the prediction message"); - } - - ModelEvaluatorFactory modelEvaluatorFactory = ModelEvaluatorFactory.newInstance(); - ValueFactoryFactory valueFactoryFactory = ReportingValueFactoryFactory.newInstance(); - modelEvaluatorFactory.setValueFactoryFactory(valueFactoryFactory); - Evaluator evaluator = (Evaluator)modelEvaluatorFactory.newModelEvaluator(model); - Map arguments = new LinkedHashMap<>(); - Map fieldMap = getInputFieldMap(evaluator); - - if (data.getDataOneofCase() == DataOneofCase.TENSOR) { - Tensor.Builder tBuilder = Tensor.newBuilder(); - TensorBuilder tb = new TensorBuilder(tBuilder); - List valuesList = data.getTensor().getValuesList(); - List shapeList = data.getTensor().getShapeList(); - - if (shapeList.size() > 2) { - return null; - } - - int cols = 0; - if (shapeList.size() == 1) - cols = shapeList.get(0); - else - cols = shapeList.get(1); - - for (int i = 0; i < valuesList.size(); i++) { - if (i > 0 && i % cols == 0) { - evaluateForTensor(evaluator, arguments, tb); - } - String name = data.getNames(i % cols); - InputField field = fieldMap.get(name); - if (field != null) - { - Object rawValue = valuesList.get(i); - FieldValue inputFieldValue = field.prepare(rawValue); - arguments.put(field.getName(), inputFieldValue); - } - } - evaluateForTensor(evaluator, arguments, tb); - if (shapeList.size() == 1) - tBuilder.addShape(tBuilder.getValuesCount()); - else - { - int outCols = tBuilder.getValuesCount() / shapeList.get(0); - tBuilder.addShape(tBuilder.getValuesCount() / outCols).addShape(outCols); - } - DefaultData.Builder dataBuilder = DefaultData.newBuilder(); - dataBuilder.setTensor(tBuilder); - return dataBuilder.build(); - }else if (data.getDataOneofCase() == DataOneofCase.NDARRAY) { - ListValue list = data.getNdarray(); - int rows = list.getValuesCount(); - int cols = list.getValues(0).getListValue().getValuesCount(); - - ListValue.Builder rowsBuilder = ListValue.newBuilder(); - for (int i = 0; i < rows; ++i) { - - ListValue.Builder row = ListValue.newBuilder(); - ListBuilder lb = new ListBuilder(row); - for (int j = 0; j < cols; j++) { - String name = data.getNames(j % cols); - InputField field = fieldMap.get(name); - if (field != null) - { - Double rawValue = list.getValues(i).getListValue().getValues(j).getNumberValue(); - FieldValue inputFieldValue = field.prepare(rawValue); - arguments.put(field.getName(), inputFieldValue); - } - } - evaluateForTensor(evaluator, arguments, lb); - rowsBuilder.addValues(Value.newBuilder().setListValue(row.build())); - } - DefaultData.Builder dataBuilder = DefaultData.newBuilder(); - dataBuilder.setNdarray(rowsBuilder.build()); - return dataBuilder.build(); - } - else - throw new UnsupportedOperationException("Only Tensor or NDArray is supported"); - } - -} diff --git a/wrappers/s2i/java/wrapper/src/main/proto/.keep b/wrappers/s2i/java/wrapper/src/main/proto/.keep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/wrappers/s2i/java/wrapper/src/main/resources/application.properties b/wrappers/s2i/java/wrapper/src/main/resources/application.properties deleted file mode 100644 index 650ed26ff9..0000000000 --- a/wrappers/s2i/java/wrapper/src/main/resources/application.properties +++ /dev/null @@ -1,8 +0,0 @@ -server.port = 9000 -grpc.port = 9001 - -seldon.api.model.enabled=true -seldon.api.route.enabled=false - -spring.jmx.enabled = false - diff --git a/wrappers/s2i/java/wrapper/src/test/java/io/seldon/wrapper/utils/TestPMMMLUtils.java b/wrappers/s2i/java/wrapper/src/test/java/io/seldon/wrapper/utils/TestPMMMLUtils.java deleted file mode 100644 index 9c46cafa1b..0000000000 --- a/wrappers/s2i/java/wrapper/src/test/java/io/seldon/wrapper/utils/TestPMMMLUtils.java +++ /dev/null @@ -1,79 +0,0 @@ -package io.seldon.wrapper.utils; - -import java.util.ArrayList; -import java.util.List; -import java.util.Random; - -import javax.xml.bind.JAXBException; - -import org.dmg.pmml.PMML; -import org.jpmml.model.PMMLUtil; -import org.junit.Test; -import org.xml.sax.SAXException; - -import com.google.protobuf.ListValue; -import com.google.protobuf.Value; - -import io.seldon.protos.PredictionProtos.DefaultData; -import io.seldon.protos.PredictionProtos.Tensor; - -public class TestPMMMLUtils { - - @Test - public void testTensorMnist() throws SAXException, JAXBException - { - PMML model = PMMLUtil.unmarshal(getClass().getClassLoader().getResourceAsStream( - "mnist.pmml")); - - Tensor.Builder tBuilder = Tensor.newBuilder(); - Random r = new Random(); - List names = new ArrayList<>(); - int numRows = 2; - for(int rows = 0;rows < numRows;rows++) - for(int i=0;i<784;i++) - { - tBuilder.addValues(r.nextInt() % 255); - names.add("_c"+i); - } - if (numRows == 1) - tBuilder.addShape(784); - else - tBuilder.addShape(numRows).addShape(784); - DefaultData.Builder dataBuilder = DefaultData.newBuilder(); - dataBuilder.setTensor(tBuilder).addAllNames(names); - - PMMLUtils util = new PMMLUtils(); - DefaultData resp = util.evaluate(model, dataBuilder.build()); - System.out.println(resp); - } - @Test - - public void testNDArrayMnist() throws SAXException, JAXBException - { - PMML model = PMMLUtil.unmarshal(getClass().getClassLoader().getResourceAsStream( - "mnist.pmml")); - - ListValue.Builder rowsBuilder = ListValue.newBuilder(); - Random r = new Random(); - List names = new ArrayList<>(); - int numRows = 2; - for(int rows = 0;rows < numRows;rows++) - { - ListValue.Builder row = ListValue.newBuilder(); - for(int i=0;i<784;i++) - { - - row.addValues(Value.newBuilder().setNumberValue(r.nextInt() % 255)); - names.add("_c"+i); - } - rowsBuilder.addValues(Value.newBuilder().setListValue(row.build())); - } - DefaultData.Builder dataBuilder = DefaultData.newBuilder(); - dataBuilder.setNdarray(rowsBuilder).addAllNames(names); - - PMMLUtils util = new PMMLUtils(); - DefaultData resp = util.evaluate(model, dataBuilder.build()); - System.out.println(resp); - } - -} diff --git a/wrappers/s2i/java/wrapper/src/test/resources/mnist.pmml b/wrappers/s2i/java/wrapper/src/test/resources/mnist.pmml deleted file mode 100644 index 352a2d287b..0000000000 --- a/wrappers/s2i/java/wrapper/src/test/resources/mnist.pmml +++ /dev/null @@ -1,8710 +0,0 @@ - - -
- - 2018-05-19T15:57:10Z -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 - 0 - - - 1 - 1 - - - 2 - 2 - - - 3 - 3 - - - 4 - 4 - - - 5 - 5 - - - 6 - 6 - - - 7 - 7 - - - 8 - 8 - - - 9 - 9 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -