From 0dd5abcbf34b57858534c36d58319578a92423bb Mon Sep 17 00:00:00 2001 From: Frank Natividad Date: Sat, 2 Sep 2017 04:32:35 -0700 Subject: [PATCH 01/17] Update endpoints samples and add sample using Guice --- .../endpoints-v2-backend/README.md | 2 +- appengine-java8/endpoints-v2-backend/pom.xml | 206 +++++++++--------- appengine-java8/endpoints-v2-guice/README.md | 161 ++++++++++++++ .../endpoints-v2-guice/build.gradle | 70 ++++++ .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 54783 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + appengine-java8/endpoints-v2-guice/gradlew | 172 +++++++++++++++ .../endpoints-v2-guice/gradlew.bat | 84 +++++++ appengine-java8/endpoints-v2-guice/pom.xml | 140 ++++++++++++ .../src/main/java/com/example/echo/Echo.java | 173 +++++++++++++++ .../com/example/echo/EchoEndpointModule.java | 30 +++ .../com/example/echo/EchoGuiceListener.java | 31 +++ .../src/main/java/com/example/echo/Email.java | 30 +++ .../main/java/com/example/echo/Message.java | 31 +++ .../src/main/webapp/WEB-INF/appengine-web.xml | 32 +++ .../main/webapp/WEB-INF/logging.properties | 25 +++ .../src/main/webapp/WEB-INF/web.xml | 67 ++++++ .../endpoints-frameworks-v2/backend/README.md | 2 +- .../endpoints-frameworks-v2/backend/pom.xml | 105 ++++----- .../guice-example/README.md | 161 ++++++++++++++ .../guice-example/build.gradle | 70 ++++++ .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 54783 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + .../guice-example/gradlew | 172 +++++++++++++++ .../guice-example/gradlew.bat | 84 +++++++ .../guice-example/pom.xml | 118 ++++++++++ .../src/main/java/com/example/echo/Echo.java | 173 +++++++++++++++ .../com/example/echo/EchoEndpointModule.java | 30 +++ .../com/example/echo/EchoGuiceListener.java | 31 +++ .../src/main/java/com/example/echo/Email.java | 30 +++ .../main/java/com/example/echo/Message.java | 31 +++ .../guice-example/src/main/main74.iml | 12 + .../src/main/webapp/WEB-INF/appengine-web.xml | 33 +++ .../main/webapp/WEB-INF/logging.properties | 25 +++ .../src/main/webapp/WEB-INF/web.xml | 67 ++++++ 35 files changed, 2238 insertions(+), 172 deletions(-) create mode 100644 appengine-java8/endpoints-v2-guice/README.md create mode 100644 appengine-java8/endpoints-v2-guice/build.gradle create mode 100644 appengine-java8/endpoints-v2-guice/gradle/wrapper/gradle-wrapper.jar create mode 100644 appengine-java8/endpoints-v2-guice/gradle/wrapper/gradle-wrapper.properties create mode 100755 appengine-java8/endpoints-v2-guice/gradlew create mode 100644 appengine-java8/endpoints-v2-guice/gradlew.bat create mode 100644 appengine-java8/endpoints-v2-guice/pom.xml create mode 100644 appengine-java8/endpoints-v2-guice/src/main/java/com/example/echo/Echo.java create mode 100644 appengine-java8/endpoints-v2-guice/src/main/java/com/example/echo/EchoEndpointModule.java create mode 100644 appengine-java8/endpoints-v2-guice/src/main/java/com/example/echo/EchoGuiceListener.java create mode 100644 appengine-java8/endpoints-v2-guice/src/main/java/com/example/echo/Email.java create mode 100644 appengine-java8/endpoints-v2-guice/src/main/java/com/example/echo/Message.java create mode 100644 appengine-java8/endpoints-v2-guice/src/main/webapp/WEB-INF/appengine-web.xml create mode 100644 appengine-java8/endpoints-v2-guice/src/main/webapp/WEB-INF/logging.properties create mode 100644 appengine-java8/endpoints-v2-guice/src/main/webapp/WEB-INF/web.xml create mode 100644 appengine/endpoints-frameworks-v2/guice-example/README.md create mode 100644 appengine/endpoints-frameworks-v2/guice-example/build.gradle create mode 100644 appengine/endpoints-frameworks-v2/guice-example/gradle/wrapper/gradle-wrapper.jar create mode 100644 appengine/endpoints-frameworks-v2/guice-example/gradle/wrapper/gradle-wrapper.properties create mode 100755 appengine/endpoints-frameworks-v2/guice-example/gradlew create mode 100644 appengine/endpoints-frameworks-v2/guice-example/gradlew.bat create mode 100644 appengine/endpoints-frameworks-v2/guice-example/pom.xml create mode 100644 appengine/endpoints-frameworks-v2/guice-example/src/main/java/com/example/echo/Echo.java create mode 100644 appengine/endpoints-frameworks-v2/guice-example/src/main/java/com/example/echo/EchoEndpointModule.java create mode 100644 appengine/endpoints-frameworks-v2/guice-example/src/main/java/com/example/echo/EchoGuiceListener.java create mode 100644 appengine/endpoints-frameworks-v2/guice-example/src/main/java/com/example/echo/Email.java create mode 100644 appengine/endpoints-frameworks-v2/guice-example/src/main/java/com/example/echo/Message.java create mode 100644 appengine/endpoints-frameworks-v2/guice-example/src/main/main74.iml create mode 100644 appengine/endpoints-frameworks-v2/guice-example/src/main/webapp/WEB-INF/appengine-web.xml create mode 100644 appengine/endpoints-frameworks-v2/guice-example/src/main/webapp/WEB-INF/logging.properties create mode 100644 appengine/endpoints-frameworks-v2/guice-example/src/main/webapp/WEB-INF/web.xml diff --git a/appengine-java8/endpoints-v2-backend/README.md b/appengine-java8/endpoints-v2-backend/README.md index 2fba2449dc1..4f60f254d42 100644 --- a/appengine-java8/endpoints-v2-backend/README.md +++ b/appengine-java8/endpoints-v2-backend/README.md @@ -33,7 +33,7 @@ To build the project: To generate the required configuration file `openapi.json`: - mvn exec:java -DGetSwaggerDoc + mvn endpoints-framework:openApiDocs ### Deploying the sample API to App Engine diff --git a/appengine-java8/endpoints-v2-backend/pom.xml b/appengine-java8/endpoints-v2-backend/pom.xml index 501c1427802..994565b9aad 100644 --- a/appengine-java8/endpoints-v2-backend/pom.xml +++ b/appengine-java8/endpoints-v2-backend/pom.xml @@ -14,120 +14,112 @@ limitations under the License. --> - 4.0.0 - war - 1.0-SNAPSHOT + 4.0.0 + war + 1.0-SNAPSHOT - com.example.echo - echo-j8 + com.example.echo + echo - - appengine-java8-samples - com.google.cloud - 1.0.0 - .. - + + appengine-java8-samples + com.google.cloud + 1.0.0 + .. + - - UTF-8 + + UTF-8 - 2.0.7 - 1.0.4 + 2.0.7 + 1.0.4 - YOUR_PROJECT_ID - 1.8 - 1.8 - 1.3.1 - + YOUR-PROJECT-ID + 1.8 + 1.8 + 1.3.1 + - - - - javax.servlet - javax.servlet-api - 3.1.0 - jar - provided - + + + + com.google.endpoints + endpoints-framework + ${endpoints.framework.version} + + + com.google.endpoints + endpoints-management-control-appengine-all + 1.0.4 + + + com.google.appengine + appengine-api-1.0-sdk + 1.9.54 + + + javax.servlet + javax.servlet-api + 3.1.0 + jar + provided + + + javax.inject + javax.inject + 1 + + - - com.google.endpoints - endpoints-framework - ${endpoints.framework.version} - - - com.google.endpoints - endpoints-management-control-appengine-all - ${endpoints.management.version} - - - - - - GetSwaggerDoc - - - GetSwaggerDoc - - - + + + ${project.build.directory}/${project.build.finalName}/WEB-INF/classes - - org.codehaus.mojo - exec-maven-plugin - 1.4.0 - - true - com.google.api.server.spi.tools.EndpointsTool - - get-swagger-doc - --hostname=${endpoints.project.id}.appspot.com - --war=target/echo-1.0-SNAPSHOT - com.example.echo.Echo - - - - - com.google.endpoints - endpoints-framework-tools - ${endpoints.framework.version} - - - com.google.appengine - appengine-api-1.0-sdk - 1.9.52 - - - + + org.apache.maven.plugins + maven-war-plugin + 2.6 + + + + ${basedir}/src/main/webapp/WEB-INF + true + WEB-INF + + + + + + com.google.cloud.tools + appengine-maven-plugin + ${appengine.maven.plugin.version} + + + + + + com.google.cloud.tools + endpoints-framework-maven-plugin + 1.0.0 + + + ${endpoints.project.id}.appspot.com + + + + org.codehaus.mojo + versions-maven-plugin + 2.3 + + + compile + + display-dependency-updates + display-plugin-updates + + + + - - - - - - - ${project.build.directory}/${project.build.finalName}/WEB-INF/classes - - - org.apache.maven.plugins - maven-war-plugin - 2.6 - - - - ${basedir}/src/main/webapp/WEB-INF - true - WEB-INF - - - - - - - com.google.cloud.tools - appengine-maven-plugin - ${appengine.maven.plugin} - - - + diff --git a/appengine-java8/endpoints-v2-guice/README.md b/appengine-java8/endpoints-v2-guice/README.md new file mode 100644 index 00000000000..b35818ec1ad --- /dev/null +++ b/appengine-java8/endpoints-v2-guice/README.md @@ -0,0 +1,161 @@ +# App Engine Standard & Google Cloud Endpoints Frameworks + +This sample demonstrates how to use Google Cloud Endpoints Frameworks with Guice +on App Engine Standard. + +## Build with Maven + +### Adding the project ID to the sample API code + +You must add the project ID obtained when you created your project to the +sample's `pom.xml` before you can deploy the code. + +To add the project ID: + +0. Edit the file `pom.xml`. + +0. For ``, replace the value `YOUR_PROJECT_ID` with +your project ID. + +0. Edit the file `src/main/java/com/example/echo/Echo.java`. + +0. Replace the value `YOUR-PROJECT-ID` with your project ID. + +0. Save your changes. + +### Building the sample project + +To build the project: + + mvn clean package + +### Generating the openapi.json file + +To generate the required configuration file `openapi.json`: + + mvn endpoints-framework:openApiDoc + +### Deploying the sample API to App Engine + +To deploy the sample API: + +0. Invoke the `gcloud` command to deploy the API configuration file: + + gcloud service-management deploy openapi.json + +0. Deploy the API implementation code by invoking: + + mvn appengine:deploy + + The first time you upload a sample app, you may be prompted to authorize the + deployment. Follow the prompts: when you are presented with a browser window + containing a code, copy it to the terminal window. + +0. Wait for the upload to finish. + +### Sending a request to the sample API + +After you deploy the API and its configuration file, you can send requests +to the API. + +To send a request to the API, from a command line, invoke the following `cURL` +command: + + curl \ + -H "Content-Type: application/json" \ + -X POST \ + -d '{"message":"echo"}' \ + https://$PROJECT_ID.appspot.com/_ah/api/echo/v1/echo + +You will get a 200 response with the following data: + + { + "message": "echo" + } + +## Build with gradle + +### Adding the project ID to the sample API code + +0. Edit the file `build.gradle`. + +0. For `def projectId = 'YOUR_PROJECT_ID'`, replace the value `YOUR_PROJECT_ID` +with your project ID. + +0. Edit the file `src/main/java/com/example/echo/Echo.java + +0. Replace the value `YOUR-PROJECT-ID` with your project ID. + +0. Save your changes. + +### Building the sample project + +To build the project on unix-based systems: + + ./gradlew build + +Windows users: Use `gradlew.bat` instead of `./gradlew` + +
+ more details + The project contains the standard java and war plugins and in addition to that it contains the following plugins: + https://github.com/GoogleCloudPlatform/endpoints-framework-gradle-plugin for the endpoint related tasks and + https://github.com/GoogleCloudPlatform/app-gradle-plugin for the appengine standard related tasks. + + Check the links for details about the available Plugin Goals and Parameters. +
+ +### Generating the openapi.json file + +To generate the required configuration file `openapi.json`: + + ./gradlew endpointsOpenApiDocs + +This results in a file in build/endpointsOpenApiDocs/openapi.json + +### Deploying the sample API to App Engine + +To deploy the sample API: + +0. Invoke the `gcloud` command to deploy the API configuration file: + + gcloud service-management deploy build/endpointsOpenApiDocs/openapi.json + +0. Deploy the API implementation code by invoking: + + ./gradlew appengineDeploy + + The first time you upload a sample app, you may be prompted to authorize the + deployment. Follow the prompts: when you are presented with a browser window + containing a code, copy it to the terminal window. + +
+ ERROR: (gcloud.app.deploy) The current Google Cloud project [...] does not contain an App Engine application. + If you create a fresh cloud project that doesn't contain a appengine application you may receive this Error: + + ERROR: (gcloud.app.deploy) The current Google Cloud project [...] does not contain an App Engine application. Use `gcloud app create` to initialize an App Engine application within the project. + + In that case just execute `gcloud app create`, you will be asked to select a region and the app will be created. Then run gradle appengineDeploy again. +
+ +0. Wait for the upload to finish. + +### Sending a request to the sample API + +After you deploy the API and its configuration file, you can send requests +to the API. + +To send a request to the API, from a command line, invoke the following `cURL` +command: + + curl \ + -H "Content-Type: application/json" \ + -X POST \ + -d '{"message":"echo"}' \ + https://$PROJECT_ID.appspot.com/_ah/api/echo/v1/echo + +You will get a 200 response with the following data: + + { + "message": "echo" + } diff --git a/appengine-java8/endpoints-v2-guice/build.gradle b/appengine-java8/endpoints-v2-guice/build.gradle new file mode 100644 index 00000000000..fd412eff529 --- /dev/null +++ b/appengine-java8/endpoints-v2-guice/build.gradle @@ -0,0 +1,70 @@ +// Copyright 2017 Google Inc. +// +// 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.import org.apache.tools.ant.filters.ReplaceTokens + +buildscript { + repositories { + mavenCentral() + } + + dependencies { + classpath 'com.google.cloud.tools:endpoints-framework-gradle-plugin:+' + classpath 'com.google.cloud.tools:appengine-gradle-plugin:+' + } +} + +repositories { + maven { + url 'https://maven-central.storage.googleapis.com' + } + jcenter() + mavenCentral() +} + +task wrapper(type: Wrapper) { + gradleVersion = '3.5' +} + +def projectId = 'YOUR_PROJECT_ID' + +apply plugin: 'java' +apply plugin: 'war' +apply plugin: 'com.google.cloud.tools.endpoints-framework-server' +apply plugin: 'com.google.cloud.tools.appengine' + +dependencies { + // For real projects: use concrete versions here instead of the '+' to make your build consistent + compile 'com.google.endpoints:endpoints-framework:+' + compile 'com.google.endpoints:endpoints-framework-guice:+' + compile 'com.google.endpoints:endpoints-management-control-appengine:+' + compile 'com.google.endpoints:endpoints-framework-auth:+' +} + +endpointsServer { + // Endpoints Framework Plugin server-side configuration + hostname = "${projectId}.appspot.com" + serviceClasses = ['com.example.echo.Echo'] +} + +sourceCompatibility = 1.8 // App Engine Standard uses Java 8 +targetCompatibility = 1.8 // App Engine Standard uses Java 8 + +// this replaces the ${endpoints.project.id} in appengine-web.xml and web.xml +task replaceProjectId(type: Copy) { + from 'src/main/webapp/WEB-INF/' + include '*.xml' + into 'build/exploded-backend/WEB-INF' + expand(endpoints:[project:[id:projectId]]) + filteringCharset = 'UTF-8' +} +assemble.dependsOn replaceProjectId diff --git a/appengine-java8/endpoints-v2-guice/gradle/wrapper/gradle-wrapper.jar b/appengine-java8/endpoints-v2-guice/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..28caa99c2145affb398f37c26790a5549a489839 GIT binary patch literal 54783 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 \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save ( ) { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/appengine-java8/endpoints-v2-guice/gradlew.bat b/appengine-java8/endpoints-v2-guice/gradlew.bat new file mode 100644 index 00000000000..e95643d6a2c --- /dev/null +++ b/appengine-java8/endpoints-v2-guice/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/appengine-java8/endpoints-v2-guice/pom.xml b/appengine-java8/endpoints-v2-guice/pom.xml new file mode 100644 index 00000000000..ded54e35315 --- /dev/null +++ b/appengine-java8/endpoints-v2-guice/pom.xml @@ -0,0 +1,140 @@ + + + 4.0.0 + war + 1.0-SNAPSHOT + + com.example.echo + echo + + + appengine-java8-samples + com.google.cloud + 1.0.0 + .. + + + + UTF-8 + + 2.0.7 + 1.0.4 + + YOUR_PROJECT_ID + 1.8 + 1.8 + 1.3.1 + + + + + + com.google.endpoints + endpoints-framework + ${endpoints.framework.version} + + + com.google.endpoints + endpoints-framework-guice + 2.0.8 + + + com.google.endpoints + endpoints-management-control-appengine-all + 1.0.4 + + + com.google.appengine + appengine-api-1.0-sdk + 1.9.54 + + + javax.servlet + javax.servlet-api + 3.1.0 + jar + provided + + + javax.inject + javax.inject + 1 + + + + + + ${project.build.directory}/${project.build.finalName}/WEB-INF/classes + + + org.apache.maven.plugins + maven-war-plugin + 2.6 + + + + ${basedir}/src/main/webapp/WEB-INF + true + WEB-INF + + + + + + com.google.cloud.tools + appengine-maven-plugin + ${appengine.maven.plugin.version} + + + + + + com.google.cloud.tools + endpoints-framework-maven-plugin + 1.0.1 + + + ${endpoints.project.id}.appspot.com + + com.example.echo.Echo + + + + + com.google.endpoints + endpoints-management-control-appengine-all + 1.0.4 + + + + + org.codehaus.mojo + versions-maven-plugin + 2.3 + + + compile + + display-dependency-updates + display-plugin-updates + + + + + + + diff --git a/appengine-java8/endpoints-v2-guice/src/main/java/com/example/echo/Echo.java b/appengine-java8/endpoints-v2-guice/src/main/java/com/example/echo/Echo.java new file mode 100644 index 00000000000..5804e86dfca --- /dev/null +++ b/appengine-java8/endpoints-v2-guice/src/main/java/com/example/echo/Echo.java @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2016 Google Inc. + * + * 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 com.example.echo; + +import com.google.api.server.spi.auth.EspAuthenticator; +import com.google.api.server.spi.auth.common.User; +import com.google.api.server.spi.config.AnnotationBoolean; +import com.google.api.server.spi.config.Api; +import com.google.api.server.spi.config.ApiIssuer; +import com.google.api.server.spi.config.ApiIssuerAudience; +import com.google.api.server.spi.config.ApiMethod; +import com.google.api.server.spi.config.ApiNamespace; +import com.google.api.server.spi.config.Named; +import com.google.api.server.spi.config.Nullable; +import com.google.api.server.spi.response.UnauthorizedException; + +/** The Echo API which Endpoints will be exposing. */ +// [START echo_api_annotation] +@Api( + name = "echo", + version = "v1", + namespace = + @ApiNamespace( + ownerDomain = "echo.example.com", + ownerName = "echo.example.com", + packagePath = "" + ), + // [START_EXCLUDE] + issuers = { + @ApiIssuer( + name = "firebase", + issuer = "https://securetoken.google.com/YOUR-PROJECT-ID", + jwksUri = "https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com") + } + // [END_EXCLUDE] + ) +// [END echo_api_annotation] +public class Echo { + /** + * Echoes the received message back. If n is a non-negative integer, the message is copied that + * many times in the returned message. + * + * Note that name is specified and will override the default name of "{class name}.{method + * name}". For example, the default is "echo.echo". + * + * Note that httpMethod is not specified. This will default to a reasonable HTTP method + * depending on the API method name. In this case, the HTTP method will default to POST. + */ + // [START echo_method] + @ApiMethod(name = "echo") + public Message echo(Message message, @Named("n") @Nullable Integer n) { + return doEcho(message, n); + } + // [END echo_method] + + /** + * Echoes the received message back. If n is a non-negative integer, the message is copied that + * many times in the returned message. + * + * Note that name is specified and will override the default name of "{class name}.{method + * name}". For example, the default is "echo.echo". + * + * Note that httpMethod is not specified. This will default to a reasonable HTTP method + * depending on the API method name. In this case, the HTTP method will default to POST. + */ + // [START echo_path] + @ApiMethod(name = "echo_path_parameter", path = "echo/{n}") + public Message echoPathParameter(Message message, @Named("n") int n) { + return doEcho(message, n); + } + // [END echo_path] + + /** + * Echoes the received message back. If n is a non-negative integer, the message is copied that + * many times in the returned message. + * + * Note that name is specified and will override the default name of "{class name}.{method + * name}". For example, the default is "echo.echo". + * + * Note that httpMethod is not specified. This will default to a reasonable HTTP method + * depending on the API method name. In this case, the HTTP method will default to POST. + */ + // [START echo_api_key] + @ApiMethod(name = "echo_api_key", path = "echo_api_key", apiKeyRequired = AnnotationBoolean.TRUE) + public Message echoApiKey(Message message, @Named("n") @Nullable Integer n) { + return doEcho(message, n); + } + // [END echo_api_key] + + private Message doEcho(Message message, Integer n) { + if (n != null && n >= 0) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < n; i++) { + if (i > 0) { + sb.append(" "); + } + sb.append(message.getMessage()); + } + message.setMessage(sb.toString()); + } + return message; + } + + /** + * Gets the authenticated user's email. If the user is not authenticated, this will return an HTTP + * 401. + * + * Note that name is not specified. This will default to "{class name}.{method name}". For + * example, the default is "echo.getUserEmail". + * + * Note that httpMethod is not required here. Without httpMethod, this will default to GET due + * to the API method name. httpMethod is added here for example purposes. + */ + // [START google_id_token_auth] + @ApiMethod( + httpMethod = ApiMethod.HttpMethod.GET, + authenticators = {EspAuthenticator.class}, + audiences = {"YOUR_OAUTH_CLIENT_ID"}, + clientIds = {"YOUR_OAUTH_CLIENT_ID"} + ) + public Email getUserEmail(User user) throws UnauthorizedException { + if (user == null) { + throw new UnauthorizedException("Invalid credentials"); + } + + Email response = new Email(); + response.setEmail(user.getEmail()); + return response; + } + // [END google_id_token_auth] + + /** + * Gets the authenticated user's email. If the user is not authenticated, this will return an HTTP + * 401. + * + * Note that name is not specified. This will default to "{class name}.{method name}". For + * example, the default is "echo.getUserEmail". + * + * Note that httpMethod is not required here. Without httpMethod, this will default to GET due + * to the API method name. httpMethod is added here for example purposes. + */ + // [START firebase_auth] + @ApiMethod( + path = "firebase_user", + httpMethod = ApiMethod.HttpMethod.GET, + authenticators = {EspAuthenticator.class}, + issuerAudiences = {@ApiIssuerAudience(name = "firebase", audiences = {"YOUR-PROJECT-ID"})} + ) + public Email getUserEmailFirebase(User user) throws UnauthorizedException { + if (user == null) { + throw new UnauthorizedException("Invalid credentials"); + } + + Email response = new Email(); + response.setEmail(user.getEmail()); + return response; + } + // [END firebase_auth] +} diff --git a/appengine-java8/endpoints-v2-guice/src/main/java/com/example/echo/EchoEndpointModule.java b/appengine-java8/endpoints-v2-guice/src/main/java/com/example/echo/EchoEndpointModule.java new file mode 100644 index 00000000000..798648a1781 --- /dev/null +++ b/appengine-java8/endpoints-v2-guice/src/main/java/com/example/echo/EchoEndpointModule.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2017 Google Inc. + * + * 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 com.example.echo; + +import com.google.api.server.spi.guice.EndpointsModule; +import com.google.common.collect.ImmutableList; + +// [START endpoints_module] +public class EchoEndpointModule extends EndpointsModule { + @Override + public void configureServlets() { + bind(Echo.class).toInstance(new Echo()); + configureEndpoints("/_ah/api/*", ImmutableList.of(Echo.class)); + } +} +// [END endpoints_module] diff --git a/appengine-java8/endpoints-v2-guice/src/main/java/com/example/echo/EchoGuiceListener.java b/appengine-java8/endpoints-v2-guice/src/main/java/com/example/echo/EchoGuiceListener.java new file mode 100644 index 00000000000..b007f059606 --- /dev/null +++ b/appengine-java8/endpoints-v2-guice/src/main/java/com/example/echo/EchoGuiceListener.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2017 Google Inc. + * + * 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 com.example.echo; + +//import com.google.api.server.spi.guice.GuiceServletContextListener; +import com.google.inject.Guice; +import com.google.inject.Injector; +import com.google.inject.servlet.GuiceServletContextListener; + +// [START injector] +public class EchoGuiceListener extends GuiceServletContextListener { + @Override + protected Injector getInjector() { + return Guice.createInjector(new EchoEndpointModule()); + } +} +// [END injector] diff --git a/appengine-java8/endpoints-v2-guice/src/main/java/com/example/echo/Email.java b/appengine-java8/endpoints-v2-guice/src/main/java/com/example/echo/Email.java new file mode 100644 index 00000000000..e7725a9d9cc --- /dev/null +++ b/appengine-java8/endpoints-v2-guice/src/main/java/com/example/echo/Email.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2016 Google Inc. + * + * 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 com.example.echo; + +/** The email bean that will be used in the getUserEmail response. */ +public class Email { + private String email; + + public String getEmail() { + return this.email; + } + + public void setEmail(String email) { + this.email = email; + } +} diff --git a/appengine-java8/endpoints-v2-guice/src/main/java/com/example/echo/Message.java b/appengine-java8/endpoints-v2-guice/src/main/java/com/example/echo/Message.java new file mode 100644 index 00000000000..64c043c8857 --- /dev/null +++ b/appengine-java8/endpoints-v2-guice/src/main/java/com/example/echo/Message.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2016 Google Inc. + * + * 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 com.example.echo; + +/** The message bean that will be used in the echo request and response. */ +public class Message { + + private String message; + + public String getMessage() { + return this.message; + } + + public void setMessage(String message) { + this.message = message; + } +} diff --git a/appengine-java8/endpoints-v2-guice/src/main/webapp/WEB-INF/appengine-web.xml b/appengine-java8/endpoints-v2-guice/src/main/webapp/WEB-INF/appengine-web.xml new file mode 100644 index 00000000000..320f4fa09af --- /dev/null +++ b/appengine-java8/endpoints-v2-guice/src/main/webapp/WEB-INF/appengine-web.xml @@ -0,0 +1,32 @@ + + + + java8 + true + + + 2 + + + + + + + + + + diff --git a/appengine-java8/endpoints-v2-guice/src/main/webapp/WEB-INF/logging.properties b/appengine-java8/endpoints-v2-guice/src/main/webapp/WEB-INF/logging.properties new file mode 100644 index 00000000000..6279d0fef33 --- /dev/null +++ b/appengine-java8/endpoints-v2-guice/src/main/webapp/WEB-INF/logging.properties @@ -0,0 +1,25 @@ +# Copyright 2016 Google Inc. +# +# 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. + +# A default java.util.logging configuration. +# (All App Engine logging is through java.util.logging by default). +# +# To use this configuration, copy it into your application's WEB-INF +# folder and add the following to your appengine-web.xml: +# +# +# +# +# + +# Set the default logging level for all loggers to WARNING +.level = WARNING diff --git a/appengine-java8/endpoints-v2-guice/src/main/webapp/WEB-INF/web.xml b/appengine-java8/endpoints-v2-guice/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000000..08b68ffe06d --- /dev/null +++ b/appengine-java8/endpoints-v2-guice/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,67 @@ + + + + + + + guiceFilter + com.google.inject.servlet.GuiceFilter + + + + guiceFilter + /_ah/api/* + + + + com.example.echo.EchoGuiceListener + + + + index.html + + + + + endpoints-api-configuration + com.google.api.control.ServiceManagementConfigFilter + + + + + endpoints-api-controller + com.google.api.control.extensions.appengine.GoogleAppEngineControlFilter + + endpoints.projectId + ${endpoints.project.id} + + + endpoints.serviceName + ${endpoints.project.id}.appspot.com + + + + + endpoints-api-configuration + EndpointsServlet + + + + endpoints-api-controller + EndpointsServlet + + diff --git a/appengine/endpoints-frameworks-v2/backend/README.md b/appengine/endpoints-frameworks-v2/backend/README.md index 2fba2449dc1..4f60f254d42 100644 --- a/appengine/endpoints-frameworks-v2/backend/README.md +++ b/appengine/endpoints-frameworks-v2/backend/README.md @@ -33,7 +33,7 @@ To build the project: To generate the required configuration file `openapi.json`: - mvn exec:java -DGetSwaggerDoc + mvn endpoints-framework:openApiDocs ### Deploying the sample API to App Engine diff --git a/appengine/endpoints-frameworks-v2/backend/pom.xml b/appengine/endpoints-frameworks-v2/backend/pom.xml index 9465073f73c..60577923b85 100644 --- a/appengine/endpoints-frameworks-v2/backend/pom.xml +++ b/appengine/endpoints-frameworks-v2/backend/pom.xml @@ -34,7 +34,7 @@ 2.0.7 1.0.4 - YOUR_PROJECT_ID + YOUR-PROJECT-ID 1.7 1.7 1.3.1 @@ -42,12 +42,6 @@ - - javax.servlet - servlet-api - 2.5 - provided - com.google.endpoints endpoints-framework @@ -56,75 +50,60 @@ com.google.endpoints endpoints-management-control-appengine-all - ${endpoints.management.version} + 1.0.4 + + + com.google.appengine + appengine-api-1.0-sdk + 1.9.54 + + + javax.servlet + servlet-api + 2.5 + provided + + + javax.inject + javax.inject + 1 - - - GetSwaggerDoc - - - GetSwaggerDoc - - - - - - org.codehaus.mojo - exec-maven-plugin - 1.4.0 - - true - com.google.api.server.spi.tools.EndpointsTool - - get-swagger-doc - --hostname=${endpoints.project.id}.appspot.com - --war=target/echo-1.0-SNAPSHOT - com.example.echo.Echo - - - - - com.google.endpoints - endpoints-framework-tools - ${endpoints.framework.version} - - - com.google.appengine - appengine-api-1.0-sdk - 1.9.30 - - - - - - - - ${project.build.directory}/${project.build.finalName}/WEB-INF/classes - org.apache.maven.plugins - maven-war-plugin - 2.6 + com.google.cloud.tools + appengine-maven-plugin + ${appengine.maven.plugin.version} - - - ${basedir}/src/main/webapp/WEB-INF - true - WEB-INF - - + - com.google.cloud.tools - appengine-maven-plugin - ${appengine.maven.plugin.version} + endpoints-framework-maven-plugin + 1.0.0 + + + ${endpoints.project.id}.appspot.com + + + + org.codehaus.mojo + versions-maven-plugin + 2.3 + + + compile + + display-dependency-updates + display-plugin-updates + + + diff --git a/appengine/endpoints-frameworks-v2/guice-example/README.md b/appengine/endpoints-frameworks-v2/guice-example/README.md new file mode 100644 index 00000000000..b35818ec1ad --- /dev/null +++ b/appengine/endpoints-frameworks-v2/guice-example/README.md @@ -0,0 +1,161 @@ +# App Engine Standard & Google Cloud Endpoints Frameworks + +This sample demonstrates how to use Google Cloud Endpoints Frameworks with Guice +on App Engine Standard. + +## Build with Maven + +### Adding the project ID to the sample API code + +You must add the project ID obtained when you created your project to the +sample's `pom.xml` before you can deploy the code. + +To add the project ID: + +0. Edit the file `pom.xml`. + +0. For ``, replace the value `YOUR_PROJECT_ID` with +your project ID. + +0. Edit the file `src/main/java/com/example/echo/Echo.java`. + +0. Replace the value `YOUR-PROJECT-ID` with your project ID. + +0. Save your changes. + +### Building the sample project + +To build the project: + + mvn clean package + +### Generating the openapi.json file + +To generate the required configuration file `openapi.json`: + + mvn endpoints-framework:openApiDoc + +### Deploying the sample API to App Engine + +To deploy the sample API: + +0. Invoke the `gcloud` command to deploy the API configuration file: + + gcloud service-management deploy openapi.json + +0. Deploy the API implementation code by invoking: + + mvn appengine:deploy + + The first time you upload a sample app, you may be prompted to authorize the + deployment. Follow the prompts: when you are presented with a browser window + containing a code, copy it to the terminal window. + +0. Wait for the upload to finish. + +### Sending a request to the sample API + +After you deploy the API and its configuration file, you can send requests +to the API. + +To send a request to the API, from a command line, invoke the following `cURL` +command: + + curl \ + -H "Content-Type: application/json" \ + -X POST \ + -d '{"message":"echo"}' \ + https://$PROJECT_ID.appspot.com/_ah/api/echo/v1/echo + +You will get a 200 response with the following data: + + { + "message": "echo" + } + +## Build with gradle + +### Adding the project ID to the sample API code + +0. Edit the file `build.gradle`. + +0. For `def projectId = 'YOUR_PROJECT_ID'`, replace the value `YOUR_PROJECT_ID` +with your project ID. + +0. Edit the file `src/main/java/com/example/echo/Echo.java + +0. Replace the value `YOUR-PROJECT-ID` with your project ID. + +0. Save your changes. + +### Building the sample project + +To build the project on unix-based systems: + + ./gradlew build + +Windows users: Use `gradlew.bat` instead of `./gradlew` + +
+ more details + The project contains the standard java and war plugins and in addition to that it contains the following plugins: + https://github.com/GoogleCloudPlatform/endpoints-framework-gradle-plugin for the endpoint related tasks and + https://github.com/GoogleCloudPlatform/app-gradle-plugin for the appengine standard related tasks. + + Check the links for details about the available Plugin Goals and Parameters. +
+ +### Generating the openapi.json file + +To generate the required configuration file `openapi.json`: + + ./gradlew endpointsOpenApiDocs + +This results in a file in build/endpointsOpenApiDocs/openapi.json + +### Deploying the sample API to App Engine + +To deploy the sample API: + +0. Invoke the `gcloud` command to deploy the API configuration file: + + gcloud service-management deploy build/endpointsOpenApiDocs/openapi.json + +0. Deploy the API implementation code by invoking: + + ./gradlew appengineDeploy + + The first time you upload a sample app, you may be prompted to authorize the + deployment. Follow the prompts: when you are presented with a browser window + containing a code, copy it to the terminal window. + +
+ ERROR: (gcloud.app.deploy) The current Google Cloud project [...] does not contain an App Engine application. + If you create a fresh cloud project that doesn't contain a appengine application you may receive this Error: + + ERROR: (gcloud.app.deploy) The current Google Cloud project [...] does not contain an App Engine application. Use `gcloud app create` to initialize an App Engine application within the project. + + In that case just execute `gcloud app create`, you will be asked to select a region and the app will be created. Then run gradle appengineDeploy again. +
+ +0. Wait for the upload to finish. + +### Sending a request to the sample API + +After you deploy the API and its configuration file, you can send requests +to the API. + +To send a request to the API, from a command line, invoke the following `cURL` +command: + + curl \ + -H "Content-Type: application/json" \ + -X POST \ + -d '{"message":"echo"}' \ + https://$PROJECT_ID.appspot.com/_ah/api/echo/v1/echo + +You will get a 200 response with the following data: + + { + "message": "echo" + } diff --git a/appengine/endpoints-frameworks-v2/guice-example/build.gradle b/appengine/endpoints-frameworks-v2/guice-example/build.gradle new file mode 100644 index 00000000000..369637a8f8c --- /dev/null +++ b/appengine/endpoints-frameworks-v2/guice-example/build.gradle @@ -0,0 +1,70 @@ +// Copyright 2017 Google Inc. +// +// 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.import org.apache.tools.ant.filters.ReplaceTokens + +buildscript { + repositories { + mavenCentral() + } + + dependencies { + classpath 'com.google.cloud.tools:endpoints-framework-gradle-plugin:+' + classpath 'com.google.cloud.tools:appengine-gradle-plugin:+' + } +} + +repositories { + maven { + url 'https://maven-central.storage.googleapis.com' + } + jcenter() + mavenCentral() +} + +task wrapper(type: Wrapper) { + gradleVersion = '3.5' +} + +def projectId = 'YOUR_PROJECT_ID' + +apply plugin: 'java' +apply plugin: 'war' +apply plugin: 'com.google.cloud.tools.endpoints-framework-server' +apply plugin: 'com.google.cloud.tools.appengine' + +dependencies { + // For real projects: use concrete versions here instead of the '+' to make your build consistent + compile 'com.google.endpoints:endpoints-framework:+' + compile 'com.google.endpoints:endpoints-framework-guice:+' + compile 'com.google.endpoints:endpoints-management-control-appengine:+' + compile 'com.google.endpoints:endpoints-framework-auth:+' +} + +endpointsServer { + // Endpoints Framework Plugin server-side configuration + hostname = "${projectId}.appspot.com" + serviceClasses = ['com.example.echo.Echo'] +} + +sourceCompatibility = 1.7 // App Engine Standard uses Java 7 +targetCompatibility = 1.7 // App Engine Standard uses Java 7 + +// this replaces the ${endpoints.project.id} in appengine-web.xml and web.xml +task replaceProjectId(type: Copy) { + from 'src/main/webapp/WEB-INF/' + include '*.xml' + into 'build/exploded-backend/WEB-INF' + expand(endpoints:[project:[id:projectId]]) + filteringCharset = 'UTF-8' +} +assemble.dependsOn replaceProjectId diff --git a/appengine/endpoints-frameworks-v2/guice-example/gradle/wrapper/gradle-wrapper.jar b/appengine/endpoints-frameworks-v2/guice-example/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..28caa99c2145affb398f37c26790a5549a489839 GIT binary patch literal 54783 zcmafaW0WS*vSoGIwr!)!wr%4p+g6utqszAKsxI5MZBNhK_h#nax$n)7$jp^1Vx1G2 zC(qu2RFDP%MFj$agaiTt68tMbK*0a&2m}Q6_be-_B1k7GC&mB*r0`FQu26lR{C^cx z{>oqT|Dz}?C?_cuFbIhy@Hlls4PVE#kL z%+b)q8t~t$qWrU}o1>w6dSEU{WQ11MaYRHV`^W006GEHNkKbo3<`>slS- z^Iau?J5(A*RcG;?9caykA`<#qy1~O zV;;PYMn6SI$q}ds#zKhlt{2DkLyA|tPj@5nHw|TfoB{R9AOtjRH|~!gjc7>@`h6hQ zNQ|Ch4lR}rT_GI4eQoy|sMheUuhTnv@_rRPV^^6SNCY zJt~}LH52Y+RK{G^aZh@qG*^+5XM={Yu0CS=<}foB$I}fd5f&atxdLYMbAT-oGoKoE zEX@l(|ILgqD&rTwS4@T(du@BzN3(}du%3WCtJ*e1WJ5HWPNihA7O65R=Zp&IHPQn{ zTJ{$GYURp`Lr$UQ$ZDoj)1f(fN-I+C0)PVej&x_8WZUodh~2t5 z^<=jtVQnpoH>x5ncT0H=^`9-~oCmK=MD#4qnx+7-E-_n^0{2wjL2YV;WK(U;%aCN} zTPh334F$MTbxR7|7mEtX3alSAz|G)I+eFvQnY}XldO7I7$ z2-ZeSVckL<)N1tQ)M6@8uW;`pybJ4+Zf4&;=27ShUds^TB8DN4y^x=7xslL*1%HX_ zT(iSMx?g}!7jTEjX@&lI{{ifXnD}tWA8x4A3#o?GX9GMQHc-%WBBl|UlS|HYNH}JU z?I48Qizg+VWgSZ#zW<;tMruWI@~tW~X_GT(Me0(X0+ag8b-P6vA(1q165LJLl%zIl z?Ef?_&y7e?U@PK^nTSGu!90^0wjPY}`1@cng< z8p@n!$bcZvs3dwYo!t+cpq=9n`6Gi|V&v32g3zJV>ELG|eijj@>UQ8n)?`HPYai20W!}g}CSvAyisSPm0W|p?*Zq_r(%nCY8@}OXs2pS4# zI*)S^UFi`&zltazAxB2B_Gt7iX?Y25?B#w+-*y#dJIH(fIA<(GUhfiupc!IVAu&vF zg3#yzI2SrRpMSxpF*`0Ngul=!@E0Li|35w|ING^;2)a0%18kiwj18Ub{sSbEm38fq z1yOlHl7;{l4yv_FQZ`n><+LwoaKk|cGBRNnN;XDstie!~t5 z#ZWz9*3qvR2XkNZYI0db?t^(lG-Q8*4Jd6Q44rT71}NCQ2nryz(Btr|?2oa(J1`cn z`=-|7k;Q^9=GaCmyu(!&8QJRv=P5M#yLAL|6t%0+)fBn2AnNJg%86562VaB+9869& zfKkJa)8)BQb}^_r0pA1u)W$O`Y~Lenzyv>;CQ_qcG5Z_x^0&CP8G*;*CSy7tBVt|X zt}4Ub&av;8$mQk7?-2%zmOI4Ih72_?WgCq|eKgY~1$)6q+??Qk1DCXcQ)yCix5h#g z4+z7=Vn%$srNO52mlyjlwxO^ThKBz@(B8WGT`@!?Jhu^-9P1-ptx_hfbCseTj{&h}=7o5m0k)+Xx7D&2Vh zXAY*n|A~oM|4%rftd%$BM_6Pd7YVSA4iSzp_^N|raz6ODulPeY4tHN5j$0K9Y4=_~ z)5Wy%A)jp0c+415T7Q#6TZsvYF`adD%0w9Bl2Ip`4nc7h{42YCdZn};GMG+abcIR0 z+z0qSe?+~R5xbD^KtQ;-KtM$Q{Q~>PCzP!TWq`Wu@s-oq!GawPuO?AzaAVX9nLRvg z0P`z82q=Iw2tAw@bDiW;LQ7-vPeX(M#!~eD43{j*F<;h#Tvp?i?nMY1l-xxzoyGi8 zS7x(hY@=*uvu#GsX*~Jo*1B-TqL>Tx$t3sJ`RDiZ_cibBtDVmo3y^DgBsg-bp#dht zV(qiVs<+rrhVdh`wl^3qKC2y!TWM_HRsVoYaK2D|rkjeFPHSJ;xsP^h-+^8{chvzq z%NIHj*%uoS!;hGN?V;<@!|l{bf|HlP0RBOO(W6+vy(ox&e=g>W@<+P$S7%6hcjZ0< z><8JG)PTD4M^ix6OD5q$ZhUD>4fc!nhc4Y0eht6>Y@bU zmLTGy0vLkAK|#eZx+rXpV>6;v^fGXE^CH-tJc zmRq+7xG6o>(>s}bX=vW3D52ec1U(ZUk;BEp2^+#cz4vt zSe}XptaaZGghCACN5JJ^?JUHI1t^SVr`J&d_T$bcou}Q^hyiZ;ca^Um>*x4Nk?)|a zG2)e+ndGq9E%aKORO9KVF|T@a>AUrPhfwR%6uRQS9k!gzc(}9irHXyl5kc_2QtGAV7-T z+}cdnDY2687mXFd$5-(sHg|1daU)2Bdor`|(jh6iG{-)1q_;6?uj!3+&2fLlT~53- zMCtxe{wjPX}Ob$h2R9#lbdl0*UM_FN^C4C-sf3ZMoOAuq>-k+&K%!%EYYHMOTN~TB z8h5Ldln5sx_H3FoHrsaR`sGaGoanU7+hXf<*&v4>1G-8v;nMChKkZnVV#Q_LB{FXS ziG89d+p+9(ZVlc1+iVQy{*5{)+_JMF$Dr+MWjyO@Irs}CYizTI5puId;kL>fM6T(3 zat^8C6u0Ck1cUR%D|A<;uT&cM%DAXq87C~FJsgGMKa_FN#bq2+u%B!_dKbw7csI=V z-PtpPOv<q}F zS)14&NI3JzYKX?>aIs;lf)TfO3W;n+He)p5YGpQ;XxtY_ixQr7%nFT0Cs28c3~^`d zgzu42up|`IaAnkM;*)A~jUI%XMnD_u4rZwwdyb0VKbq@u?!7aQCP@t|O!1uJ8QmAS zPoX9{rYaK~LTk%3|5mPHhXV<}HSt4SG`E!2jk0-C6%B4IoZlIrbf92btI zCaKuXl=W0C`esGOP@Mv~A!Bm6HYEMqjC`?l1DeW&(2&E%R>yTykCk*2B`IcI{@l^| z8E%@IJt&TIDxfFhN_3ja(PmnPFEwpn{b`A z`m$!H=ek)46OXllp+}w6g&TscifgnxN^T{~JEn{A*rv$G9KmEqWt&Ab%5bQ*wbLJ+ zr==4do+}I6a37u_wA#L~9+K6jL)lya!;eMg5;r6U>@lHmLb(dOah&UuPIjc?nCMZ)6b+b4Oel?vcE5Q4$Jt71WOM$^`oPpzo_u; zu{j5ys?ENRG`ZE}RaQpN;4M`j@wA|C?oOYYa;Jja?j2?V@ zM97=sn3AoB_>P&lR zWdSgBJUvibzUJhyU2YE<2Q8t=rC`DslFOn^MQvCquhN~bFj?HMNn!4*F?dMkmM)## z^$AL9OuCUDmnhk4ZG~g@t}Im2okt9RDY9Q4dlt~Tzvhtbmp8aE8;@tupgh-_O-__) zuYH^YFO8-5eG_DE2!~ZSE1lLu9x-$?i*oBP!}0jlk4cy5^Q;{3E#^`3b~Su_bugsj zlernD@6h~-SUxz4fO+VEwbq+_`W{#bG{UOrU;H)z%W0r-mny1sm#O@gvwE72c^im)UrJnQgcB_HxILh!9fPQ);whe*(eIUjA(t{8iI(?NY<5^SGOr;vrcKpedfTu zWCTHMK16<@(tI%`NxN3xW6nKX{JW=77{~yR$t1$xwKUm7UJmOrnI4Z zajmwO&zZ8PhJ6FNRjID+@QZ8fz%%f2c{Xh*BWDIK zXrFxswPdd;(i}fLsNVb(sx-hMJ>IQ0QvH^z3= zc;TX|YE>HpO6-C5=g{+l3U6fF`AXJM6@kcoWLQXxiNiXab#!P8ozeR^oy#PfdS#aj zUDKKNx>5&v%k*OBF;-)X5Afpd60K{FTH@1|)>M!!F)jb))f&{UY-rcR>h z`~9|W#a`Yw7fD~{3`rktJC|L46-(sRaa~hM-d#KSG6@_*&+pnNYQ2JSy@BNg_Tx7< zB-vhG+{d^*zIH!;2M7O`_S{?EKffQ02;N>=2!3JqQX(M_Aj#}dCfdb?yGH%tk^_Zf zAtZ5!rnq4(WSd!_GfuPp4uDd2(8%>)Iu6z=XjRQLi2_RBg97~ zr$zf>FNkUG3~bp6#hl^3HSA2*SS-DT_QkX#QNcG2?8&Cm6Sj#}yaqEhjq1GabS)ZwBhcKc;52~Qc*Z@=jRjfqZO1%y?*D(iB&EE z-Aln~CD}?DqVGGB``Q@F-TY|Fj7)4D28@Z-@a-A4(KC*}W4*2l?E>!wviGFcB*Dc3z50hH^i0Y`j zip{Em#(a42NnOEvkU+6SfAkEzO$ z*j*3sOP4y2W@t7)nbi9Dcj|9Bw}z)VzKuAx4<&3`!gMhuW5&4%F@_!ZKBoaBHYwcn3WcL^0l zkdkY#l8~$5UazRWOJo32=kA|tKs!Y_vX=+xrA3Mwd45^vZe02+dI_r|rmO-`>l0$i zEB%YFf8ecv=Q@YPntwR)df$>p+zI@!1-aj13HMYz5$QWWp$U&Z(I?C5rYl8S=m|d!*(Y&`gzl zu00=P^fRg?$GE2+$)wr(ohep`G%yKT(qdGmR!M45W`~K4bC@YwX{J;T@dq=$9o>;L zz%NIUoFhZxHIjtR1kdw5V7u=4{!3oQc;za?0UQVj5f%uD<=^`&>TYc9;$-0p5VNob z2pSvzby?QX*3j%fJx*5BcET~k^5xT{iQin-qP*nWQ9THOA69^wDN5utzTj#~upjf}CtShX9;wdXE35EVlzWqIGJ z)io1?vG_sea+iQjU%m@q)4(=eS5zC1h|!bCE~d9gvl{7)!IScau*OTR`)!Mhr`mdX zlhmcf-Ms-t;DYx9o2z=q68Nm{ zOF;j&-eqWvD}_5X8`^t48wcrR%*&RycEe!J5nJguNo~cP6)1|!4@Jb2YL6IYdyrH8 zI$W1D+$LRa4*EC=4Cr)=0Qap5g}M^+jyvlDE}G8-wsVQYX&UXR#=~{XZLTPY`=3=N zkvaUS+4ofuBn|356>5pTPX|r)^QG(R2d$TX>Krwf&QVgVCM9zP64l%Z8B=2RYP%{E zaKc@qdtK`R({$|K`t5>0?KorZI1)6`9@|#O>v1WK@3bbLFtGM4gd98X0(-9{W{NiN zIuG0D%0l5WhXSRNbfROzH6w*YO&2Xpx5amm%+T4$qtvPDK+eUjfs$g@<`DBwNH1(33NhDKwO*I9E z$bW{D7h4@U~&K4klFtk`+Smzy>$vNph6hQsYQ1QF(- zHK>f)>|MT%=q)(U-3br5R4KIE!FeeTP`{-^wpgKJzcOqD?!&-6Yf7fd<^40T$r z{@91>s^KAH@mw(72{v#n4rzh?z_qh-AL;FAt==sT(BFv)(FXSoKd)RMA40`^)3^+Z zwdPe9j*t}}%!Fk@58lX}s`NX-7M;>k)w7j1`*~g_dAMDLsOq`@C>D(lreX%!c_OjX zTP$xDO*C|S27Hd)6?;6;Y`P3$%YFG)9y2H0Yuw;6Z2{^y2YvKP`V&OVi;L`j{L;jL zvz-omEQby(t)f?-HssRfTDYnS`=UG{>1Y)Dh(Xb>WU++>XOoF@TR;-#<1E+1AqPdk=H6)VQ32z zLdHM3uv~8{(>v|*O>k2VTW}=fw~%fuNfyf6FMaEXzdHB?tnHs6%)R(k_^``|IN|L# zV&QQG*x~n}a?;|la|TQD383!6WOfCv9V@-(g`ab3{CgpIjQ zGyCjpiIaK${m-Zd;m*k+7;?~M6)Wqb>yI*k`=@zOr%NjIs(C?BUqCq8^ zsi_)Bk)kyU`NL<6nholj+3Xs*E%vZ2H<};VoFCvMFLYwFg-gi8C%2@0gH#_lU>~8E z?>!v9-YFw6r=Z{xMI59a3J6_y8&}4UeEr?9w($B){={R9reR;r4Jgl?G)eMv=EOsc zckWsS;fuDu;l?Dgzgyhj^H>RMJs^*kzUfB#Ax}fqmj?Eb#G1W$J(4a)qfI(k=2*_Y zqr3?H*#`c8owZQ>48MUl@A(yQxuXBM2|bdy`x=bcfHc~8b9#odFy|NGMC(oMC%C+$ zi;L=xaJ%=;6Qf)kX-netDG|g#BZrnfdTm79e(Px7oy)wLHNB^EUMI7snGBJIuq*RP z@Xv@1TIRW_^S82~__wm~U(}t&|5uS))d}DzVP^x7v9q&svHy>{v$D24wjk=4SiJ7i zqf#YhQ?sQusP?MXrRx0PczL)ABq5Z%NibA3eTRvr^@n;Fsio!I2;YM^8}EP;&7WT# zqivIJ-A+dn6W9FwzQ7v&<$;P5qwe`TR5_AiRFDRGVmdG3h+?&byKRASKwXHQiegIU zvi;If(y)ozZ%=Q6)cR|q)pkV>bAocyDX#Om&LQ?^D;#XBhNC;^+80{v1k1(4X1RWKo4Onb+)A zp&OGpq39Ss9Do68%xbC+SH>N@bhr?aF^3ARMK)^mWxfuvt|?ucl0$sf){gT9_b~^# z3>QnE)-@zE%xH=ax{R1+8?7wHJFQhqx1xirV(lZN0HU=>7ODhQ5k^5BK973IumdDP z(oUtiC^Ya#Q@9^~vNuH)*L|F$!0eySLZ_2FYGn%S71MQAFrHK4i#UwxjM0gxL;pC#^nGA?B0S zjI>+f^}Ik10y+Dkm{%iS3&XUVZ;GCHpJ5Re31~x@7X68v;(n<6>>q?g=^VldiKw#@ zEOQ_*7zX;nDQmDM597=8yqlznk7 z+#rTK!TN>LKK0vPkO?^!tGYfh{PQwx2{$;;hXw+o#{4V)o@o7JnX3Pzzv6$kNc=~k zLIc7ZWf|+6KhEdwl_w5PEQknl2TTo9GE7ziZ{5ESq%({Nit}IqJ>FT2iz#C<-kH>9 zZ7#i0)@|N7p)q-r1L{;J^UC?UYp(10rKh8TRyy>yhJWXD>$&^W=lZ>SB=Othg$XEg z5FL%%z9nMPJzPhRIyIGwqaa@*F!II`tmbAv*|$^bO0Q~(jj|aJj5BP6N%o zi>Fh52P_qg$2UE^&NabtBe|(p{jB`_nxYv`c#kx>LN*OSN+N zU4?c;6AYnTgQjgGHWamUI~Jj|bO=J#gpsI+{P2#bjpt${i6FN0W?!+*Po|F(Ep~r^ znlCW6`~{P*dJn~2sE-28TWaVhPubr5OB6wFGHdSr{ylUzA%71gLT*B+enM2v-TrvO ztop}Gd0>sC_EpOG@@K2?m+wHVUHJ=ochwHJueUm~pZw7CElAsk!cgpuF&clLJlcoM z5RfmuLPJGOQ&+|Qje(!|_U>laCSIu5Go16&6C`MR%qhi#y^MTR$a|FuE7KaW!jdVu zQc6y3$b-fjA|zT|iyLgCtE)?+*{ez$14G@qDry0u%fYe=m_L9 zcpCG?q=Z0|3N5rQ75C6%&qtH`V%gd}#f)a{GqGaN!;vg5_;5m_q=-%TK(QnPrSGBM zJR)n3VvZ+adg)`v(iogiMOEgsJRqsAT%F)$7q%>N z+>ypdC#5P+#5I)8tD%Jz_C$CkQ4(v+;XO+*-@Vqfr%y4;NXBbf)IKJp+YrDNXQtxD zPjcXDE`uD{H50-$)3Jxd>X|xN$u3~#ft_j`y+MY-5bs>?@)We6Dr$y%FUB(3ui3I# z7^>}aXe=hA%0I;(8>2ca-1`OXuRv5Kv8h?&2rUu>D9D7L@V+srE z;`vC7L`JG;GbZ`e$0uDdeHVMFNI+5qBQG04|Ejy-g zBlav6v%&NUA^JNO?bO@ZQP|(AT!lFEgBu*fg)=wOA5wiaY#-n~WK#|S`TM7(g1I)Y z{MElhws)Vgzx?^BUlK$3_Zei$(_xyl<)dBB_p!esdMsYJzw(HJx!JOYS=cmMrTh5V zK48AlHI8<>h)vH(Dt}CkO2SPKUCu>*r(ZT(MEJC`EoDeyIjAiZ z4!$#Bv;#Ha|50x!E~2$H@qVM*{HX?6=U`;C_*DY9J?+_ zE_1(oZky$GE>%urwl$tN$r2Q;P6h=-(#J>KqL@4-5)GJp?Lnl!QHTV56UmG?h?t2t z8N0+xSbWmtk1G4%6cSek>wX?&<^~ckAjopL$THKk$l^NQSZr`^P^wN!3f97?2^9l& zo!!HDu5GNryHQMMV&*B02#4$-Kd86@R8@jPjIwC0qR`5yN~0wFF<)(m`Oe--meLR- zQ^9g0Oe9t;I$nX*0sl)jqI6z_x7yg_iIO2oCo`RV(;7kceK2{MG}=Z%q=5WqSafGh zp!GmTD`*RiQDP@S%N*1(9eILhgEc~3nujB!gK^;UZ?|@f%BqT7`F*;dx;_lgxCloE zv)sDk$CT1t^!Ia2yo(vQvLn$!E<}s<-iI>wtXvs#cScn-lpVpte^S&<NYtNP%9=Z+{&Er+rD=2JmitU_vutwn0S4Po2dU$b)6jiBdJ_5VEwz9fT28%;c zk9W8e_B3!WT3Yoz&l)@3uIZ7)GxE z4Xl;;y6~Y|bC|KGj+Bzc?zL66dWH|!>z2pjQuj2bzisLrIDXD?MOOKv{oZumqO&Tt z(~hW<7OR@y^~R0RadKcc}NKI%CiV=eeh%``Vo-RnrvWK(sOydLoK zU$2g-d)ye45;H0P3=L^>a&{%W>(CZNGqYdWEauKGS;tJg%qiCob8E(^&Ltqv)pJgJ z&&ALyxTw~=UZJ1wWa6FTSiq|!=(n^Uh6myUWeNhp4XN3+{UOy#Ftu8-K`^nJ>flFd zrY{FgM8K$1LqQ75sR1Gihk}T(Mj6_MzTTVM8c=aWC@_Nbl|mSZWE8KFmDj4&kDogj zSUoIBdvUaPo-Qjs?4qPLIBoTo}E0mu%O#i zjm2g)0K=|B!>PrQU6C)*{U!S_iH;eR(+_BcTepYExFxn8!O{tLGH>!>zj_IE7r)%$ z?Kj)U{L~DD5_u&9xkDs~GuDvcMA#7<3~M4F-;4 zX{_?jDjL0nedG#Aj2fZRjuBw*dG&M}z$K~y`=~0SC{f_vKrGD^_#{2q!p2xg1IciZ z;6wviQw)Z0Hz~1MKn_K-%}1{7iCGmZyCb`R?p&CxP^!0b{>qsgub#@fpls6(4F0Qt6oWd-ZU(qRseeZ6RRT3Iw%y-mKV?})8V^t>+XKZ0#Gsb%{m&C+Up z{YiPA(cio~45i}`!<+#^hh^P^Ax*|;Uv#Z_fvLAL!yjHjeiP+X&0K}j`c_F-kh6dt(*W7~Cd0 z!!{rP?PE89LfP-8j=XH)`|5V2_sAlez76p+Ax{`9SgVx3_Iv1IRK>q9QHADt#*Y!6r?w zJ5bTiaP7*l{|Znqg@Z$x7oV~vxDJT69J;^p?pH^8117H{G^OIb5#ko3+BjY7nwHaj zt0PiK=(W2l&_CZ%!Nyr& zk;xb^^2gea?J8Y4B6V6KpAUV5{4>)%zR++g|I2XK{|fQHXS$OA+0XV5hAa9vXWGvQ z8}dDIdW4G939a{NblX`04I-%Upx46uQ;Pe{nJ*K9pf?nmI~fadH1*^4-g}b(2>rzC z#1j(IH=l-#O&&7wl>AtIDv5H{5F=QBj8)rADX4*jNMqATF)3Zm41sst%ZI71^f^ed z@k4X+T)1B&GpQ(qLaBD_CLb|`4ZHuwn4wK-^(iT`l{D(B;7B=Cz+M5OEeKs_+(z2v za^=DLy4UYtJk74ad|CLLJpGCAUwdln3G6T`G}oWeH@cHs@7q zZ;{{rJ#XqSrPu5YnVZ%rkVhU*S)AM6sn6cq+}oTU@7p!q;08Ef&9K@xt*``1yTZ(v z%rc{K^2CvW;4I;wa+Z|j@gjog^LHj>_EJal#C3qQ_`di)StH~kQa)IQfO-k@l#<%^?z_se2)nkaRm+p zPBWe7uN31~FEskXR3)9XAlHgFJv&e3NX2J-cgVY#7?_b>+!ly6f_$nIfQU#xA z)62KU z9-k;5Ns8x>h4*lKw`SPB)%zGPMKSuj^&x*-(Xe}F9l#p6%3I3~#%Xiyjwj*-4 z0~Yjnt=EbfR5^w@kvUvtQg^rxvBzS5v7#6s+?%HBy3@SdU!}ZTW!kVhx|rdZMRylS zPGddO{_KC~f7)30WFCU)mud)b&HQbnKg_k(OrbtShyJUPo>I6flvXul0WOo zW2?G$1Uv2>>~5z@7{AQS`WcR|NK6bR_;sX1TdBR4HIPQ|DWOhW7ypB95P59D(C&M? zRyztK7nufK3Uj?YTb74wuIqBT@@h!Q(R7V6Hskn&_zYAT@5l$Z;abhWF*eh-9wum8 z_WpLonUYWAz1wt9i7`t!CUb`e%cm&*bV4YBo( z58L?ql-giN`#~)zhh5Di5A(0|5>v+e9az(x%FcH27o0(St?R>iBxiyBPNoJAbZVz- zS}tavhAJ0kgd+tZjT;&?Bc%%F3vsl#+)G2N?I|@T%6`h|7*kwkGqLte^qR*n0c>>{# z-gTbvExPb@9s2(0T|wq12+Oma8+`3o#BvN+W|Q7o0p`?NLu*jCe4%a&DjmuyCl!0} z)T$0ghCzsXXT$P*~yojBLuRMs-L)E+45g0MNcMtTz>~WZ3Eud|o zf=UioWFpEiNfFa|W_xpfdNm#~s<&6v75(lXw}-{(>=qfJ=7WlEcCAs3Z&jRxGctHA zZmsbixM5%p#!f2}I@{dw5xVdzM2kMSR-8{HvT~QixsE1tq#i1Sp~a*5#|QXg@VbV{ z+l52hbp+qNh+n~mP52NCG@b03k5R zC8cEEGUo2RP-wCS{xX60P~KP3;tdynQ8QG+Bh3&#P#3%$p-jg&JZP~`lZjy-ruMup zxin_e3%MS~+@&N_lp5}Miq9Jn3IW%TuVqgu%fG%ueu!E8J<+ktfppS?F!Jjabc>)f za}Xj8`o>RnXqxrq{a^B2;5Gyqcz=Hxx}X9ABK$AV{~wt6zuR!VRSui@DOl3E({%_z zg)oTn`%0kcqqzPOFmvo_sGCzBbx)~6PT^gT9~qPTAUb1!ALaXwua$Ad zN*U$e)koOD$L}5i{V;&xe4xqwp}C&HY3ai@nL%FV;VEbZrsX$}HXikZ+tp6y-s79L zADxR-ozw#3y)ed)bF32cl&ESj!S^4XVxAeOeEPf7FKw&SRz(G50>^h;7E2H>z+1oV zt^Aj6-1+U2j>#>`fjiS%D82LgZI~_o-o9-HYPu1HwnI>;xUt!d{OlCwqmM6^GNco* z*{HS`_iuLS$Q|%q`rM$pb3Jrm$H`wT^4+4E4ueEd7&{N2QcSYVU3V?;)u*R002cF3_eFPTkdWg8D0NlE3DW8Y&l zLU9lkf8tPHl}rp2GpuEgek$~~Vhi=KV?dlcPe|`3yW84AG4T| z?>>1gRzk%lb(s>@r8GOn<9X419ydKlrh;BfB~LXh?nQvf+c3Fs1c{h-jV`hlKR9C= zznFgMZ)QnZBBWp&3nQiCAWj4!wVxAN0zAT4Wfrklj?4Xq)D?F9+M^wdt}{`YHnBOp zbKaxDALj*|g~Ged`KrVnRM9=l$lNG$tOd97ux9ljHfr-X)pox68%w2U=(bcoe7TO5 zQI^7v~qkOC9lph+Umgo3Oo#A}sib7A3lAmsx47{b#ifMtPr{^E3FN@Dnx2o=3 zK0K0Zj(MT|1o^s4@8G-(#`O1a>UatC%i3UqR#H{Jp#9LOO{~JqZFQB^gNa3VYsxxP zdtyqba^lb`2!*C;yc5UR@9C(w$6Cs~x&IQ)Jv|mm?~<|Y9lLUGjBDjr+ivj;FV${& z)>i#Ph!dL&;DJbXQsWe)MV8f!(}a8LV4>AuA#*)RBRxvoWt2RP4d}d&MphE^Iit@s zQ=^7xY2XTYwqn<gekKI^&oubIG!&M(Ua%z=;PCjAK8WP*cFqgoJZzsP4M z8~$oUsx7G6u+aQmIpAc1J-dp=*ekVHLO=1t>wfADn^aA)&}=8++o`xr*lcWERK6-w zHDoIgG2LU4rZ0t-W@&_`b5B|mi&^~DTH&scMO|Iw1{g;c?D}>#m}vZrV=dchn8!2+ z+Qv8GTIZe{$2hfQAuSh6T+7fxb2uz0%n?+)-LzU-C<}5CX#k7CplPZW{u%53Y#e(1 zgo)6_A*#Y+z6NE-9Bf{3Ib1TSl+kG;W`d(aNY+)<5Vum3Zq+4a9Ms|}*jn0;WCC64Pc1Az`CY0=-k z$5a8Mp&njQt{&nuwl|_^xS}rh< z(#wu{IlD&m3s~${!pJ`S3NM_=xyK-}pyn&Oh^$|V(F+2YB!gTUyrPQIL|pi2e$ECE65#dDJO6vV9H15{cjs1lOB zC^?*8U0M?f<}yYxI}B({nHh1AN$&YvA!~An1b64q-x7xe_c+wwLED2GHOk=SAL!pI zhb^yo3%{$IVx@YHbE!U@lDE;EKLWR4BEXg&hQdUmZ;zv#9@HatIge>B;(iwog{ZTBnlla=sVbuf&Zl_nR7(b-rg z9Cs#mA_^>qksL|9ffWG?>_CfSGLl?|b9Bx;%i*&nSc>sV96|2Ns!^cD!)+3LFN#k#g)ns{t5+U&%Ms}^M73|+A zbWC=7VIOTijqqmt0>=9~FF@Ie5_RS<=8*6W`wp5_0kSict0+sfRDLtNy$cv};X8D6 zi8u-2BrJ(O(rI=>%dq+>sL4Ou_9jF3rBWAdMgne-xyMf(JuN<0Uen)`$M(<9es0W={!<7Cdyoqp$s1~=0VWo7)M2Q_`Crm z`oa}e<}MB-F0%@=Pim~>2T3HQQ{A!KB%cbH{Rwzii0h}n&xs~)G+h&<*(YX6^pV=s z=iXu02VzEU0VUl$ZK+5C>&y56V|tytXc6IdgI|zZm{UBTgU`AKia^r1B=hbN*uCZr%c0{KFd=ZsujjZ?ux22_|-_1O^t2p9#E6B~q%zEOKL{Mp4_~2@Bhs2G?54*u@?wnOT4m3FhA`7miQhSWp_ECr)&nUh}!LD^_-DaYi;4 z7EIO+2I&@VZMks~2k)A9dz3Nt13U1+_DqiN>UIGoMR685eoV{4@BJDUod46Rv~* z;2Yc>fggVa2`16!1Q-I6)rc(qUG(9A9h(~7wDsG~AKJ?4kg04b^vgkT8&TGl2H`ER zEg4PqmkO(Za!%2nxY(#BINrEm8*;tctaEwD!MzRVGRFq9V|8K8te!-YwAt+PDY*jF zj8Qw*)1!e6=cZ7LaKq`$J$yS#!_f@v8~B#@gKXuK(V?!!ulw=>1ok`z|M+w068yZK zHKL3qH71F9Z64_^6qpk#KO5V4b~A#>Qs^W2nW&;I;%nWJFD0yrM^wSl^!HdF4Nidu z%e=#jWYSo4V!xT^i7r+@Vmz3)h>yr>E}@deBd~jL^O$GbF$8L`dx(<K}aSo)AW*O~MMc&DIKo;eE; zmpQTpQE-=efHT$a5)gC6^`LBp8|2FF|H0Thz}D7p>%-kOcWv9YZQHhOW7oEA+vcuq z+jhI#em(cR7w5g_|K%pD$x2q!q-%~j#~9D=0hq{G!M!=ersQ*+ZsJtxBS$-~h`^xU zBG3a~VJcsT885b&cEJYYLzv_T_6nUStVtHnd@F+}-P9+DrI zIsn5g30?!p%oU)QM;Q(a8mNb)$UF)rnpF>WfUrZY0}QuBjQ`gDiLy1N*tGtG(fRjK zK%SKy3=(8%xCo`BtHUnF+_Xi(|M7>@3?86PPjXja2&F5(X)+>OxXQXsxyrgbS5>KO z(mN3aDm&RNW@c_THOr9mP=c;A{SH1R0X~jjXg>|^Q!8{E;9}cs#1Gb+!r)c{JU&Lu ztzQSkpTUA`h&%2M7&u+mLFZTjP)i_tpYROxc4p%VZ(G&CgP^ly3E6* zY`KA{1$@?y_E&kh1M1RSK=%&~AI`EQ{%yoYf{<@n14#UK4c5~nRmP6A+_}li5eh|- zCj3$h|BmJfR%p`C8-?5tA5Jk+MG$U5(K;UryU)s~_S2iw=bL28eq*Fc$=6v}i@mPQ z$mh)Lfs@y6>owe+Yj%$<@sd9{tp|Bugm`CG2jPN(N*gNjtq!qM>f_XcPBt0W=H-_6 zNYw%7kmtK>FEx42u^3r@nlWBssyVNJa$rNqpyxBwsVMHg0zIJHGvNR&aPe6_&!6F2 zm}BNUTQm56;Azu|VG=1e8uSfo2v4+>RV{r1B7-IMPySp8{9O96RuAGXjL`p!`rSNy zz=cxhK5IEb1E8bc>S$e*F{Q6R;?@DY9Th(x7BA-aJ^cYZm=&rb{aT0qho@fMd+q5) z3_9!_fsi-#QH{Vv3t_(}{P8kgw=JL4wcsF^9~m0}2W;O~%+3eB+8dpLA-EkEBwjbz z&d1MMgzYDQ%&yR3)DvN~4-6|_+S&1)))139O22&E4JnT#oxl`JbJCAkosbmV{tevO zm|52qAJ2i{CsFiiUm@N)Zr-r1!RxH%VA~l@mPW?|2FfOTo1v6mAC28;LZ{J!LKrzu zM`8UDfM1SRC0f_~(|uAW$ZK5DfV|UlNV(P&a)cOC_GE=_6-?P%bpsTlHsgw3IDUx% zlg7v{TuS?SHIJ2<>S5A5jSiSPNsOp~x`78tFb6-!94&v2_bf=+x%Y91J)J5m?ut{#oW zReUZ~yW+En!(CwK%dB3vV;MP1daw|2W4g5^>PKe%+#qaGtTR&}$CW=};G@rdn8g29 z|8ZLr4uhW7^E1c;0C&wLfxm%{BD9h|&$EHOjOIExebr?Iozk2>tlRQ`%?i$#ak9|O z%bX>DK;z*`XghIR63)B<4V~ihpTd?7 ze1dD>7F547l6gmZy~(B#F`=$sf<0iaxNtVFZW}ZezI35;UV&6*MH$kTLS8_|X86LE zC8NH}wIN|LF<}j+YK!2W){|D@^5YfV<|oZsj@h1VA$MFzv!K z8LGBZ(&N`oXh3-6cB3>#S)2D7A_<=(ZPz|YcOaGLD^0I-vaP@(kC$&%oYn<0_$Bcb z2N{RKWvo(7MB+ME&e(?^HS`6cJwo%8wXxUJ$2YaNri5^_dKmIT7me(L@LKT&(Tz%H}F0D{FH@c0}ar2*hV4 zOnWnJf9fb<)7>=>BkrEzaFd= zxzn|){KI|-1ONc{-$QFswx<8Z%m0<|ZaXK3G}4nYLQz9MY$uh9m<1`U8f;5X5^Mwk zj|*W!@?MpgQ7vhnhZOY{?)wX4Xb|@g(4T_H<7OBHwT9U2Z?6RQoO=r2&(AlQ9XQzp zu^kh@6gx`)^->b~Kq?{aP)>o3Bs)C*xEa0Bm=aJ|^c9GKHO2vkjbrG#Gx5t*9c#~C z^m^@qy_%8%9@nih?*ti^j^^U@k#a+DPPWLllHs7dg(ht6S!`!Lhr@z`Xps&1_U3BG zk|8)|>#RJv%j_~-r6DD1?bEhs{Zr~VIgGnep~Ws}%AZO(e(FHM!vK zW>FnpNBi>3Bdx_#2<0gu57L7;pt3awsigs|8nPhvnQ6GTC8kz9l&jU4gS@vpG_M;* zJ|)`a^b6Aa17arkbQNj8&{rh$0eVT?WRyc7$cIni6M`hg2k$Pa5}ZY>no#17!C-|% z0-k;Pt}`qdj7wV1JZnV&U#}ZFRsEHdASdomu$g!83PUR}gz;PrjbDSKU9wCww;ep^ zj~8Wtsn?xE*yx^=9;!Ubpl%ubcc_yMtgHcKiK~L~9~uQTh7VKkCy{(9uBK|5zf>V~ z2*ox7$9-0?vSD`w*1xBi>}FAo1xYvR&XhUmISY_8-CYp8D}^sSh2FgI{^GPnJUb!<{nOTy(0iZ)#rCY;+H`JYU<>l;lSM#&7(Eg6l;l6^}2|z6z5d9q}d6CwG&_ z+l#Br#TYzS3g@+w=J-zIxH8^@>I=|0RKY%>R|O6$EB!EmHSOK`AW!mQ&HOt?DTi+R zBs_;eMZL2I;nioOoKpJc&XBqE0*(bE?P?I4dMzx{*L?O`65AL4^>#}S&vR19V%Qy5 zsr)V`sO#+ER(y8U>OOX7slJ(rib;ur7sgY%tOo)Vp|j6NG7OJDQc=(jo^(+)aX^u~k!yL=7&U^A=1Sb_7jZ|ng7f{+RXEp(CNnyzZbP2U=s8g) z+$u{efG`(0oE~>CmI=^H>SG#)GwEVS*U*y+5!Ky5)59kW)|0SPBvUNBQQkwe(&xWitYBBIS^b07@gud1z97M}3~EN1OCDCHGwWvvJhnKk;r)R z0T}dbRr$nAX>~OU3Hm|3-!kfjsQI51$Sw)lCcVzI=8L~#!4c&{NC%REU(nUC=9lt@Qe^8F=Mj2W*{uDvl zj@;9v_rlzUKc*GE-6ZQKCDm2A^+x8Ev$JY%tVSi39%-6v3b#zA0?}BihxW`b<&54X zV{>-*v2yURa5mSs@Od1wvaxX1x98z>ROk143-(c*Mslu*RnPrVL07(WBQ)xuwds)Z zXfPyaXJq5^6jl~C^j1a)qB)HkMLbellgJ`Gz-pMx5R)MsNJ0>ko_wmKFq4g?r2>~u zc39@(wAL7zHg=S*PkUx5EcgfN#dwp&7~3j%116#Ly+qOlf4^gFqyEuhwU*Jby@P(Z zl%>pkezxwwXL;|^tk3TGzAoL$_?+C=q;YvtU}#C$)#--1>t|<}-L92)4KfJzWTR6l zUVAa;a3qb8$UW0}1hz}rAf1(O(HO24$eeORr5?-c(M4Avo2HRY)yfcMdjo$M*4vyQ zb!Q`&m)pD@R+pYsI>>-M^24h{be&F}v@2)A`aA36faQ9%lIePrJqV;BSKY|j!cx2Z z&zCT^Y$%c?78Xg?s50v1TCA9(*u%PlSQui-sep<1%tx@_)B}@LlcuoX>L*(D5sw7j zHPZXW#oGLlA|q+|F(03St7b~RVhCe_P(|TgHor+Iy>(%tenY?%xG4>Q*~<@6Vvu|v za4+992A9xP;76G29CRf!{{eSp;sVQ3ZATw+8=^Xb(Hw{oJ|=x3M;|qNNvjmOb%g1G zJ56aV*!ja*V^?=eiQKb97pT5R^4WP@!H^;uS9-?s4^;TRZE9htX$m+(ZeJ% z_*4;@+P{6{3gdd49$YTurMltF!paB3ykU43I5ixhs?Ufyn$aBYYv!hnKo_pPlx_5B z5KxpvmnAghu|=^-kUFR-FP0OfXR>UAcHRjO+cP;nIxyOIWWlwyusGa>aW2tZd1i9R zUK3BaH#SCz=A-G#K}LQmXJd}v8fcnN4}%yH;R1vb zHGEEmee)pe6{_Cc3{C9^Xg1?hW+S=+V>tFlF*O^Ohm0cZ#76N;>Roy)v!zTl-;;1~ zk%DgpglRdXpZ?TiV|TXa1XzzSvv}(qUm!Fb+u#Bip_{%aJ7w$YU7idRwgP}$AD6?3 zSM%1IX6?mz$2uf>T18;t?w@sKB2Voq!HiX8pAkpXPx0XjxWVD(7rsio&<(Ri_}}*S z?k^y1rlN@z=?ZENjKTK<@)ijMxr2XX7bSGN=!p~g6XTK4p|AX*gy%_)RU$-XgoDq{D&edOtM`1#ah zPHtb$2z5kNVRQFN3`U#t(ar;IH`RzNkWE5F7GHWsaHYQ%bqyKUiMw$D|6Ods{>lYhrVQ6hvI3jaqrn%5w zAnsG&H52g-7NYCcK=PgSLLH178pM`8t?Qf2Osue+_7E@!rxk8S zAzSVawk`yM{4I<(4zO}JJJObjL5V-mjEi5vrmxV7pVi(QQTAA(V1`#l_3x*zRNheC z&-9<*9`qqGH$q^qX(NDjnMIwU#I)&g9B=Sco+s-E#IUhElGfxc)lPq`kbzwJ85HLmGYR(_vcH0So3HYqa38r!7u5QcYkt3;!oAd&QM-8j9uaKA z7w_vW;^DwrLqCJ!Rvj9Ei6KQtN0UsoH;XJxSlMsf`Yj>5X$hOHk7Z@g=C531z@$TP zORK)?D!%hYoQ)_#GJk7?99V;w-X77M<-~PZ#Zh#!f9k166YNSv&EGXBsz$0aYjpL^ z+(IKJl!+G{Qb5S_*)!^gO?o#h^X=35ml0Z&il(BbGSVlDI2%6JSQnF+ zW?@s1rUI=PaU%s15i%e#c#+N-ekMssu;bpS_z&C1Hw|4Z)3ZR^pHpm83n_HJBfXzR z%eG|*4wlA@>Yvsuy*)3RdYYDHKHuJBcz<+;+IpW16$X&wp3$8SI7?Bc-u4kj*}mrL zsmKs0bmZ+=gE&GSd7JeYqRO+=h}Dq|N#iO}iMv(8kGqw?Q>rEHC2t%QqgwK840kAW zk`BEiyzvuW?FfRT2RQpTuV`4gdwfpq&Gi!uJxCp(L^)=xc~d9OO$d=4tpulmLorFK zn+(rNnF>o9JNv&u3@~L{0#^6-hWmMrt>rekPtiS^xmaqqq%=Jy(gdp8Q#a+W24|v1 z*^rtW0S6ybal%Witcgg#TCZzxRITT&*bL9MpjbyBj?6GNq>HyqBCR2|E1n{=;gS_v zs^y^*7KMO8&Q}^13fya?pLYh28lJ2r`}II$($A}x><~!N)lCul8tHqGR+nH8Fq}GW z&by+EH6X51Z#s>!Yp886?EjQ^9v1eGj{hKxwy}&RPT)=A8B@2B7Ia?&j1nHCX-Jk* z!5K)QVShYDc&5kHKPB7uWc|QBE;#%_`YrdiZX5Q4p(oV0kXbT`JT-On-b?LHO={Zr z@DI%{QQ{&?DQ^u$1=fgpPFrLUzbeA3HUQGvmXCn&uP#y25b3NS@GpcE9JZ;EcksX3 zA55t)Hnch=o~j;Gls1W42)2RJN^Q0tzuJ^JGqD|;V>vnJuGYNPK5|eVBDoTeQ>X(` zBrz%z+b0BR4u{49QAd8xt5_NSNh@*`nwuM-jf}gGh@7*>h@7+UA5MEy6i}n&6=e$y zD!ZisNS&0T#z$QgWo?60L%IHktVIHHuuKCMl(Deejkv+%ZL74`U4qL{r{dw|jLBWqd_=(ISPa+|r4rV*cEnvn&Z41dC{lx_5rd0XXAh}QQU&gmD+)aH+@`xny&p}cjE28nLTL3@)+j! zfo;l}VLy02&^A5g?qx?+dH!Ta^MFQuJrRu!1G8u6eWMSyXPP5~#TDi}RClxgIeAc* z1pPLui>rQqY#Q1K%pNU|NlLAc&=3y4(#V5X0E_+z_No60QnRBPc_gl7(8%M2fP6rs z{{ZKjwkGI=xGL&l-5H*8!$7`h7f303O5D^KZU3-ms?}#n^$T~~ahXn%PM%7p&oybS z$?J!1$&-kV=l$PI6eeJFMB=`Iir4Rb;Qt}X{7dB~Xlr9)ZtCoy|KF=%RD!iEB0t>7 z*ZT2NAWwi_em=n^erE0tBLu86y)rbin3rI+T{7We^oBO`t)e*r{p~N@URdMIF3sG^ z^+8s~2FClGk4vrh_vvX}fTJ6-5Xsb0J(dWpNa!nj-jPWz*5@|&-bn$B2y-r@nI~)B zn+p}zTI~@1T6;4e2AC1Z$g0W566jxBZ{eq!&_$&sh8)%f;>;z~&s~gxK*4!iO832) zx@uM~F=%tT7yD)iG5K2yjO%rQ#KCS&&6BZe&d+7pwky$(&7KSOozEr}h+CIeX<63u z4X^4%h<*N-j0+gm%PeczZQFH`)7kD`R_?O1Lt-qEpx0 zLP=(=rJ;iJmmZ!=P#M=gN=-ZJpBOO6(6c(aHZ(QNXC0c8Z%0=ZQLN4|fxj7{Gkx$s zDQ}sPVwdIiiYKCif4~TDu|4MKCRKCj?unewtU=NJ_zVG12)zwM8hW|RqXpMR>L&7H ze*n_U%(ZMZhB>f8B0dX= z*hXjt)qs<4JOjF3CVknPZw%0gV`1Y1>REss_liH3y}dbw<3SuYUGcQ?pQmh~NA+^Y+;VUat~1>!z=hJ}812t|fL%&6Fw4k_vaLl%5P zaF}0KrvAe`GL@YpmT|#qECE!XTQ;nsjIkQ`z{$2-uKwZ@2%kzWw}ffj5=~v0Q(2V? zAO79<4!;m$do&EO4zVRU4p)ITMVaP!{G0(g;zAMXgTk{gJ=r826SDLO>2>v>ATV;q zS`5P4Re?-@C7y1y<2Hw%LDpk z6&-~5NU<3R7l-(;5UVYfO|%IN!F@3D;*`RvRZ)7G9*m5gAmlD5WOu}MUH`S>dfWJ! z{0&B@N*{cuMxXoxgB}fx{3zJ^< z9z}XHhNqMGvg?N2zH&FBf5?M)DPN#Sg;5Og|0wru-#o*8=I!LXqyz~9i6{|yJw)0_ zi{j3jT#nPCG)D52S+165KRchAq|514-eM$YPimg2%X+16RCArIZtlDbDJO9=_XyMD zoC^b@fUv711vit4&lIo~XncD2uCrfuKH8E``e;Wk&{8k);EWqCUZY4dFLKdmDl2_o zMP+GW-dzpwsUA(^%gsgRdYf#-3OCJUsgmJ`fGQap4~PuIKu)ZT(CxOSpRyUl=$|t1 z@@9CcP9_@rSKUF|;BN%KHC+N7d4VZ(4JNDI)}~sZv2!hs#<)>M(?2^H1`Nah~_taU^n*CbZH+v)kdrHiM?!|KO#%*anDcA zed#~O%=w^jdIN>J!b>@<2;X8ubcCH!LUaV3T0*)*P6lv1xM#U>JO~Lka?P=Kai~qs z)|hDVH@#0tM}OqE%ga*c8vmF(0X!4gj}tZqMuEekF6fS&$@If4oJH9PLW&Ca2CqS! zfkAWlfh!<(6MyR-lrwS$!W1cT&?~9N)lQb(4OtXPysW0aAuCFVGK)qU3A{G5JDcRR z0l*vGOmm7i3SwqTqa#ANOHJHqtXj*J-5DUpWe*|^!LSE7MH;VKN8ppjX3R8gSfnPR za?2F6Xxunau(+jZc-<7%)%3K*{j}AElzPIow3=~#ISC_ByScS)c5RK|nL(TH%;(lK z^u*J*<(dfJ;}Uiev!~7#lDhATnmpSY)w#;Y`=iAW#6`}@HGaXSeT;jsEvDL&Rwu?g zwa+JW;0MPS06x|r$VLq6$(ka8!;gGb1K<%MqGP+vDZWZJpLjKUgN0dK?p3C{D&tcv z?8!@{Tp?UxYWG0JfVo|U^rKmRPEB&^qgnQp(hU_Mp`Hw%ZX8fw*h*4tt04)@@mcJ_ zE;fJG*eg~9`F2+PL4%?p8fN*l|`>hNJhPR@f<$JH}SDGe|xPodBc@ z>*Gnzv5JtD8GN(Z%CmDFt?t%9F3^cpug_(Pj_XoBpS6RydL6+wWw4E%2-C%D)4a@G z7Mm4d{CY9S+M^0d1mLZT+oHVm5%c>in{0}!k>iT1C7#O+0_1Gclk$8$rnAyl`57^B zo9|71ttYuJ?CCDp$oK~e9lPh*aS!gBLQ1$o0w|uluKHCle;NYURgv7Cg;E*M8+;83~Kx>BJqZ=o*mJS9Hxp=bp~uQ+Q%iUB!>h> zOs3rb^x>b}>%7ncd=$S7FEv%w)~kN!oh)w>XYRbU2#{7MtEP=KR`!!n z@c6cm$`qZ86iAb-P2zW?ffg_?Xz?EWLv+Pnv)j_^g>gIsDw>%z=48xXs ztXy*AgZ}XryXSSAq;ZyAo)P&1<{h#o+VX1pS&x;c*LB2ys@g^|Ne^e&u(F($VQFzr2N;Uxpn0XHISA zuG$StIAZ#%^;gdx$;F0uJ&fE3FfcOV5yV(?_06FH)#7uOG>hC+zoVY1>30J3Ep>V)`nJL7 zk-AP2lh7;4f1R`YHyo;x@iS6P1L=R_8g$rKjBniGG z7Wy?lA+#98cwsLqlOX_;2mj}QgJ00aae3PBZO))?g054Gt?|`89P}ud8M2P~c zY2m?A{f&}{PvB%59$#`Yk6F9}LtTVLr4`_vUk1t5EDB5ygR+ri}TnuVxHj)IP*)IkApp`A~+v|BqN+W)Eh{|~%!crx)V;Kr^+pMkH z-VRyWpnOF)zmUX=sW=EW7Sdz15#ID+-r^V11Ir+;p$0yW;Ox4TAr-xrzn_b`k?bky zeItAr-#I&+|GRSkvlRau-}`?TWtEDiE56bAOSC zXcKZ(B?@}6N2NN5qNO?(71~?1N_iSEI}#5>GtgSGfksdS;%*IxVesnmc|!B7!#As( zgkcT^N*WT)relVUBm%nwL7Ks$StYuLd{O9NFq1)*nGAwTTHGTa$A)1vhix>~^ zwI|7g-%^M18t{Wp1E^%KnR)wZ~8RVWvNJrwz|vlMs7BF=)# z!#!W^ejQa>_i{U|rv{Nps!~_x?0z#}RB!+F_*)hdG!fagq+6O|;|V>DK|}OwLHM{7 zc|Q4JDqZH(nqF#j77OTDd%tU=1^eF_*XUDD zLzIL8?i~Il6q-m+m~@v*S2Gf6MH<43mrr3PsXp3Gc@CI9CsQ(oIsNyL`y-30TZ)y2 zYC@-4t+WFJjTIFKG{Ik_q1EU8u@@uFmb&W$L!V4#wKElaN{V~n%%E8S=L#i)yK!!&}msL1A@L^Cvs!?xT_*E3Wy+?&!bM>&BX0zj}N zWsjWwc*VWfRRw=egZ{i2*C%@Q6@@{UL*b;Ww9X^`b!$qP0Sy zC~!r#ku$&SkWCvn zA%wXT{U&rse)rLT(?kEqV~XFw)Y(gt1=pD3_FfE4BEggPx@1S6tDZ0ZScD8*)IFipTitfM{x-f+_9Ia~$WY){ z?tP3Z{DseC&$!T-VRNexl=}yi$sykaFt&Eqqf_>L$NZHPzs|)+crni^~2>p+%^0$d5N?uxWfDg`lerb52rkr$|fC*BhMw(nq9tjW< zVyoq}-AbIbelzit1@;rbH?dVZ4>&;pH95<@;rcru?D+W{vzL1c+X*`pA(KcEsv0J5 z8>+;r?@uE6ZVy`ZD%&AHgeSJFy8&PgBs@pVc#tnfT3K5lV*sXjUg{__>Bb@itc03T zqY?ocs6Ce36GFD9e(^6_ri{W3S%uRcdhX){d6o=%W{9G-wuW=;LYD68tlaYm5QL(>p!s%^L(DaS;O>oUeRK;kuUa~kLY$|&( zd(+mnhx-oK_v;PQFXh%6i<6GnkRzH!%2|(d>!cUjnvoBDg#=J!3L2v*2pgtSQ*Gu z=RCC%>XTs;O!aDy!=X%QiK8w96-@&t*Yed=2*U&LS z0^$6&T~hZC?1Fp>6%{d~fV|qvj(ms2(Ua!9Dg4-@-?flR%5sI9p(hOK^Qdv5}Xb=$>(jo4>I*u7NUC zyw$-D1RDY8JH4QF@IEYTf;JSon$LXTqQLj_Eo^HoZr>5s!0W2;3#ol30_UhcLoGP$ zkgJGZqf;mXnmRac=Q{0!EA1#l)h_iV6jGE9xOGkji}=nk5xH7<(w?_Ql{_mq#X^Ps zDrl19$7P*mtYZXO;`>IfGU<6IfHEoJLRWA?c7mlA2snEJa+2G{F|z9-5Lc$X_M_6I zS7rTj8iq>V>2qDS!$9X$3AkeoqYUrRvZZlu5AXhe&-qj7DINRpJ=$nbm&yJUL zcJ@H|>CqgW{xwFY`cv)wN}Xp%GW9wd!vU)01INOK@s$_sz16F3W2^K@64nUUezH@@ zQJiU(N4T!2=C0~dhUNu;Y&_yVmEn~^nk$dh5N)a%9~XmIbR7Nc8u%miPwioLEmHR* zySN?!T9C0CcZeao2$y3m!0*@y+9t(59hZ=ALbQ%d^GQ)E#qI^ctA?{nKcx$+W2A#j zcLQb5NUIbd)gvB~QWr^1ng{>h?Ow+v4w|%dqIcC-N&%ap_Fz6b`6n}Ti zlkcCu9o78psV=AQ@NEwJpC&!OBKiLjt|$Cu)}#UDa@ZbfDL5^M1T5T#IOtMJZ4M~@ zXh*~47lNRu)o#ag&x>oab^hT7_!}++Tu>Kp?ES&$NgZ=ft z@|%3a9wO!rj!ufs27i70Pfq5L%DKY49NedjCV1fw36Mcf1LIukMiBT~H*#ef1u`|^ zS>3!r3^IrW&|73LfNdaCC%H8HKgW?VdxC6N;*dy^8U1woISrmJ&t9gk4IS(~pI+}j z@q&fnCqtR$5RhjBLdEL&X@l(~du#pHwHPS`dQ<&40f&X%>}7*O-vM#J#po6?Y!?LZ z#%8kSqO^!ie^^+#kQpbo(yAwf6w+F9{5 zxr2E+g=yfXY^^*w^#T)dy*>{ssx02%=D=Iv@JdTqIii;(pCh3`y+{r`Qlv~G#KJ6+ zr-QLYiWxU8f%SEPjUe~u6gi2Y>}jl6O(nUyc^qx33sm-56?`f42*06OBLegREfmbNUvvR#>{W&4DL|NPV+As&($WF)rTOnFv3La3jr4-Hn6zUC4{4}gS4p|j| zXte{N$&J}b9RjH;Wk(fQ8MEm5MeheCL`nuU`LK6JG^(7x%thc4+P}<4YJm2`*J22c zv@7LA`$kj)8W9K8B&?Wg?{7p1U09yEf`82HVE-#!;om=j{^PFv=Zxw2&%3cI$y#>) zTgCC!f_Z)dib)na4Hdu#m6(?wN-ysPJ}QLh6xK=aYKgsA&Fm_COZcMgg&!u7ANCJQ z1XoK%L48~Ry|l+P`}4*&`|+0JdQMOG2Y}pgI4JTwMt$ljskkbA1%8w}3<-)-qB0f3 z!I@9PD0ju48_R&(5GqUqe(T|y$)@uJsaB(vrSrDwFMP-G+sqx7fdi-dcc~=&t}{(w zTCssQmj;uFlFp-e(*|_9ORZHD~t<;{*$w zNUR8S5`2=qbMkY8gr1sJ%pa)y>%Zw3wB3ic9p(>p1~$Nh_L)^oSkM);n2a2>6QF^* zQ3Xp|`{@>v*X7L_axqvuV?75YX!0YdpSNS~reC+(uRqF2o>f6zJr|R)XmP}cltJk# zzZLEYqldM~iCG}86pT_>#t?zcyS5SSAH8u^^lOKVv=I}8A)Q{@;{~|s;l#m*LT`-M zO~*a=9+_J!`icz0&d98HYQxgOZHA9{0~hwqIr_IRoBXV7?yBg;?J^Iw_Y}mh^j;^6 z=U;jHdsQzrr{AWZm=o0JpE7uENgeA?__+QQ5)VTY0?l8w7v%A8xxaY`#{tY?#TCsa zPOV_WZM^s`Qj|afA8>@iRhDK(&Sp}70j`RyUyQ$kuX_#J_V>n2b8p4{#gt6qsS?m=-0u0 zD_Y*Q2(x9pg_p3%c8P^UFocmhWpeovzNNK;JPHra?NwY%WX^09ckLz+dUvRC>Zu(= zE0Rq{;x~uY#ED&tU6>T)#7Tw%8ai&-9Amoh5O$^)1VfT3Kefm=*Pq?2=Wn~J;4I3~ z*>@-M`i4Ha{(pDXzdDhCv5Bq2ceu#EZAI3Kh^k0FHuZM)4Q666NzE%_fqXjP{1tp~ zQ1Gz`Vb+N(D=pG$^NU8yt5)T{dAxaF{ZoyB$z@NPrf)@G1-$w5j;@B_B(;6^#kyDH zZPVPxZPVGFPoIz1wzL3+_PWFB6IuBtIwEL}Sm@{oD8^Jf8UT{5Q@3HMRF0M4D=_E` zD(p+3wNv(r!=OA#^r6zxnUQeKY+Tj~-6J`c$SGNlHTst`!>PT8oP64JwLJ zo0&FdEy@+u>gWQrXTdhK^p&z61G=JYN1H5KCKeg|W9c0j1L*oI77G&T&Z5-HqX=VZ z#!c;28ttj9QSrIsa5}SB8OhDXn$8_FWX#?SWSGHu>Z|1%HI~2`_eAKIXQ46}WVn1C zq4Vx2!Tj@NE9J(=xU22vc3x9-2hp2qjb;foS)&_3k6_Ho%25*KdYbL>qfQ#don@{s zBtLx?%fU}M{>-*8VsnKZ{M-OZKZ2E3>;ko6$FWGD*p9T!CSb=4~c)rOoo5E`K0Ic^_ULF141!8WqUJpg$IH=MuWY`+G@#?Hu#}$j zDKKwbn1(V+u}fexB}_7WjyMn97x-r)1;@-dW1ka*LV~~`ZMXb5jwOa|#_kzpH|1;~ ziM0Z(3(i51hF699k}j_R#YEPp?^MUV~lprsYT9X z&C;nR9aPs;069~kp*WuEUfXSpQ>RR&>8I-|<=)3VsPW4F^3DhBOV6Nm<{%}(LoVbz zXCz2qe&_se*qqX*hi8u%6IS!95}mLi-(R#SvKM_{jFaAOIcxIBVb0D z#mxPNiCzQf@=e5;1EQ@f4{xlXGooG1uw`hnwcHQZLq7i3=x>PAecmrXKu~j`52SO| zuM4u^mx46I<`|*yI_~W;eFi6u51dm-AEW(@z|V9K4!C*wD{)wHI{4e}Yx$lynI|S; zXE2fV%8_->;1VDQXej!4Ogi*7WK5aj-uw@PdJ{y%P__4KNhoh}7HN zTe+&l792&XU2;`=>;_P>=;%@BAP49r&lpXeMrS1>Y4#0|J+jcu^7t0z?)9^Ups(Gfh^lT~da7_I!7SQqo`ayuRhc*HoBNP@sr{-|^8? zZO2pGuK$RS-u}UK!vzE+%OG}2?9bhm2&3fGYLRQRQ|9j-Y$VA}!DbMeL`e#L+sv5= zjj4V3+jU-C*JC8#R*`7i8LXcNK6~z+3=NitB4?Lh^QC_OW$sovcgmRdCXvymBY|-@ ztoIRZB6?q}#u{onCGn>H+{4iFA}o)(%D;-LUnYogL75kPIz`7E<~wT?Er_#ySf|aC zV(OPMl&RHZ+~lEHks$k(dahPU-n%*=RWxi_LmoyHn%Xhs`}=1Z7VzX@sL658PZ~r~ z)3-wXUIRX{mgZLx#p(P9TE1W>*(hvysV0P~9&Kj~vh_DYUCXw2!u+v^jWX6)+e922 z{j!a28HTt%W<)TvR5oDpvGZ2HbW+w{5yIjn=VP345an~xUsRw6M+E0>Yj z%L(l~15e>#g<$DAx#;2NC*lZ!Jgj5+uyjAGo%6HAIU}fGaKp}2Z)gwfjLfCa@MQNm zUXQT+U=H$fAjHv#W5BUVGinxT;W*b`BL}CX-fvd}$ZO!aei6wM4lvTSq1US%r@>b| zHOqrj9@-~x$+*(lL$$zA$oA?3M4-C&!c#q~H_=hl2;2n*%pNDN!M=<)zCx^9IzRus{1_>%iAM{3Q?s zIu~?m^B-?+TrwsWeuO-)?BonmXlc;AmRzV&e%-Hz{5S3_UfzCZXlx032W zT&r`5@e2?Q5v0)Z)gs03?%Z{(bg*=^ie<&oU=0QO;nA0ON})kq=^uX4b*uT)?v6`2 zwMgyt^sjpoc_|NjcyUL18e0u`Gj#jg-i@{xeM{f;`>%s*lDfN-MdsW+>!Zi)m`c6hL;eALmV6u+0aZrzWGeL zICYR@_=fPc)$s3}jn}?$32DP;h@$A-Dh)QEg%wTMGpnZ9g|~Vmf}-KiC~PcId9XNZ zNfy2&CwYf7*;g?iVuUU64A`Gq4f)XA$s!mbc;a*a8f(A3e`wySVO-;*M7dXh*>sRtw$iRxXe?7VPx z)^wzvs)QWJUcB_?N2d^{Z9KKssXr9v`3(mV1I4$q{RMlfp4q-Bxf@St-Pw3Q*Ef!$ z!{NR<=B)=|K&A(zG8TQxik5kFerKk^W(N6`tJ(+C8ka{3yfhI~zuw$buwnXgvJB~x zC)%fCrD})mLbehXLw+LA62K1)!9-)D$dTZJ8+OY7(gHj(3BjTIp;EQ9$l+|UF^9d_ zsI|CwwV*tyG>^V5@L|uh|BTI1`Tte+6;OF3Y1agIcZcBa?(T%(8r)2gLm1+c^ zF&AsjmD{avGrXl=zeaw_TKjkqz`rgOdHi^$aKiNYam-b;L$rme%A2UCA};#Re$5-LOr|W;3ud&1mY7pTQ#SM`Vt5Cd zYEBoHXs+%h(5*H!JlUzQkBSOQ6Lk`ou!6@mc-nlq%Y${&A$i4?KLoNyyM5fPPJlIG z$G9~@>H1RG-a*Ro`uS9+1cbU)O~xfHts+ENu#IO2urHiJn7 zdbB5vQBTpglO%Jn1jYCPvBhc_(>gL#ci(@;{t_0 z*^kA(phCrIXxmdUdiv};x}upJK!~nM@Tr%%y0SG*e6pAwGTuAJc~XAGUc@zzkfKvD z=sLfn^M2BD-OKDK>-N~)U%KjZO-u;d$4`MK7+kj`hxj6tdcFmwo2XJb`r!E!oPoh6 zZ`gv)Os7!uOwUm}C%%uPs)&?AQD>f#tcdK#N11l>yi(^0r8>oA3yp1*N)sw~#f{j2 zx9ZQN5jy-(4TV^S+$^_5RhSA{Gwm$2NYhh|rKKGx$MUL!(`{ zGHkktj35?Uc-7&ovz}hFGC2bAvyV`8HfcR6$gt5_b%o3g^ZodU@`A|nv6qF_>S=;>pi4y^+co?x!?qait97Ph0;&YL(~eiz_LI zZgkKuIc=oA>rvjEHK%g&gv)lP!G3vbNsu$)giUbeI~F9DXX9J;*n~6 zilm|`+CJlNTxoHKlUk_Y@cq%}R^OaHD|Xf6HhW+A)b+r-_krCakhjl`J~x9C)MPjUhAS*_Xx&3;)AU->jXas zQ1$dhp9i!%PGH`sFM%sSm59?qR?F6q!0Xpm7dLS!X|sXY84D&6oYo$l?lGwsuOZGf zoMfrJ(SzO)45AzlfL62(QPqQu(4F3g2rgV_;QLOh&RM^XSrHWeaq1d{=n3Zl)5r_T zx{#i#OHF>Y((l=fJGf8i>}A5=TOlaCBEWq18juk4Ti?X8W)2R38SEc(1i(uBpC$2tOJQuoLTL_=fTQtnoGAIm~IQ%Z%LlwcxC zIU>S{)58khv)}|LEyCExa4{d7X}dUa2$%SoE8t21a#@GDX>%98OY3V*X-~-rb%D+j zW5h;^a;cpHC63VbBUz+C0_9*R5$rX3mry-{fORZUjj=LCrl474o9g21VWH<@UhH~J zUDt@LHO^ZE_}51;0h4%ch8&SZC46V~+HfTr2N|N`@>HbCn>Gzjla_Nn;tDm}i4SP> zDOyTlI2E$iLrt{73=O4BUtZH=#Uz*tS~>|h`d-aF29nOw+F?>nFs;tWHMt;6VG|mC zAdCH+BUESNkgA|%0@QWh7QC`txJ4_rI}+X!k4YA}*_man=5ZD2Jr)(lOBtj=z2>qX}Gvx+3nNSd%coGbmrl!6@g%xYi9--d;<>eT!UbT zM&T0n6K%yrJ>wc)`ta{{`jrJRiA2jISY~&=Jw&QzYH|T2U__imTv)`1d}c)MWM>CJ z*`Dj)xKE*w=r!5HY0GS8d0;*d3XgBBFCN@kW0-mFJhLhIBUb9l>ICMAgTb#aThHL`*qIO_6R3STm?k%hlNH9KkrA=o^1S%YhbwBSwWb1&RBJJD44Hp+DQ)7gg<0j%>3|V(LAuKB6}9-^Ii`#nd=vz(21+P^Z`Xnv?-7NX(*m|@2ll?QF?|24{l-j1kT$+7ZcDf`yM|>4LV-Y zoHwQ)gH3C8`l*qKrP!=wjsvg`sENhA2`1zPX^RrhXb>Vs2z!hfg{ont^waepLpjVFoy8I%b%d`K^XW<`R{$( z%Y^a2#eQpSW_F9s?I)ahzyrIB`W!@fLeu;D%xI(5tErs<>3H0qeo`9;{2IFm*Ni;H z++0Pw+&xlnCd@B_P_c<^bEP9%=R7nW+Z%d)vD2w!yq6XXN(uhPv09xP)oq6C7}#*P z0^3RYJcTDW{u!@s53As=5*FuFeSyTh$(%hsrOn`^zTY`8b7vZwX;<|GTobt-OXYYT zSukNSl^Vxt?LiTFg^FSw&uM!^h|#hqn8vI^ryd}=0yoAn!ENxdhY&SoeITRdIP^Un^qPcuL~zsqLYN&WuQYP4YP`HRUa6~k#ncCSuhxW&)No9T!SN1cmidtmZz+B~d9 zcmg~ZLTAH3F&HVv(?L5vHsdmcC^TI_ete8ATZ58ZI_J#L5BDtG)!!ufkZi@Z{OQDz zU_huvLVipu$0Q+xnW8XS6&Jy`T-Qtnk@GxXGA0oA1~aJJq83_jRLya;=2ezx5=kfS zSCszy8?)h?eH#36E^mkzni zv@~A1RQFbhoj8NUpQ3L>Ekv-$jUHK$JqDnKaNYF%D_?H&Aa^uZmuDHp^fxisktTTF zIIM3g7sblgWYS;IE)7IA0@~gLujedyZmqf@+M$8d=H^51D^ib!bZVV$DaQ|cO5iAL zE0TntRCNIbFMl^Y>}p;PWG-V=dJ2(^&^Q%v>B+B^rfl29oriKr5}XwdS~tB@We zyft}3>ELdiuoE!{W5x9-WQm(d-8<oH@dv z(XOT5=w&oH4Wc)hh~5?0Ux!EW3FCtp!0?y`i19N2{_yxmX!nm;S-c`(9ss!SQwa5O zb=rf86e<473$#X*8|3eMu~A;XLV*Q;hC5VCuyjdX?%B<~0ey-WA)M%jILQuoDWDcw z1if+CS>bj#;@uhjmx1rAqK&VF6cI|_N|Q+;`Fccfa7Jb&lQadksu|jo zw(q(?f;p~JVVmlBpQ1J4T~cR_cNeW4lJ(jxLh5&7KIwmUZX9ILJm8&6rL5u0Hc`w~LnJB|qQSIGsC@8$&;*E8qb!tTP+r5^(egeo^JT>F87 z=P)MS_%cgUL=UF?S(MGtv7j+J7-3J{wLt~5n`;G5G)`l_-$TpVxZitgx72Qr_jyna zOTUlQ!{oBZjQ$oKNdv2|Q*7#5W`IQvi?W=bdAukme8ZKYtK0`C!&ns>xt}z75|?dH z`5m?wusf04BL|;pIE|m#eMpqkIyV(>4_@dfq=TD#$p~}bp(+3RV$kg~?GpIJp-UDy znpr{dx3SG&p2tSm$5~9-xL!#eIl1K7yupa^RGfU%)Etg-^>a+SPoD1sIb9%~v$71J z6SA&313{-4`->=sbkojm;bBo4!71eH^#)@j^tYz0M6CFVFx42pypEQ}*IR=r@D^I+ z6O#%Kh%>3hC3-}QeP#*D`G{9b6r0^FDEjV2u6RqCEYlAigaAMn|Nofu{(AKyU1WD+PxIuG`w(cYcqHzG}H?tD^`aH=|Ol72C{GEaivVl zqE?l+#$2$NI|uvpdPvnngfpHfe-0BdVgLTNC#E@Y=@|$s_{yjYNl@`a%_V)wh`_=( z0@8-&p!tHgy={vZ=Cd%x)~w4j){=Nqgnov=^3@dv0qbt>B8}EHKS$bdw!v-{&+y_; zc_Ef;=7N$%8B1vIj8xfmnKi#Hqebs>rLV)pzxo1|g1Kmq-Jy3AY>I7sm)^m|D-Y z(mwkH?~eG9j$!`$?Ip97ZlQV%g^D?+2bZ@b4f#kw zf9RDy$x))hIJ7S*v7oTyGO&I3WX6;wNlA*bf-*+%_$<)X9H;59NPEYByAejlcLQ+) zQ2Vv|Y8U`&HkmcI9j+6MlDWwnQGTpbr$;?D4c}9_~^5_V{Zan5~y@^OpO0cFt zfKm5X_CaC0(v*eqa68B~%@&>4EZ{vlTJ?>*+c_d6Zc+0-3oP#$S*A#^4Di4VGqo+C zw>3iYS6}}^4f3eQZ~^HG|985TvbDuOtgf{x554^{W8fVi(PI*TL_7_8PceW9xt>k@o;W{W z8C4^wMt6=xadX!&I7KGz-N`#G3AB$?7~a0mYrS)w5jgD4RV}>9&`3h0cI)3(jux-e z+PscNwjPfgj)Au9GzDQdp}80)1WVHxVmr5bI^z7zhDGdHLoHzKziwvW_uvXYAh`@R ze?m8f=QKRTP}pE3KMS(4)s>7OQheE;@7{ zow783vfzmCTWSKG&K7E8-Ke(WL4fYOhk1+yi2T7${rRMK<92f7V`3U@oGo%v#;Vco zikFU#eT0-`1Mge*^siY}28zM^<=+=qVxl~l(#;y=Lk$QfSIn}k7sDBKHecHhuGBa( z>a%0EpM2+Msd95(v8k!$rIgW0qSPzE64Q7!H8h(RsyTj~oby<0z=^UELFGO{KHL&& zO`>!`SS%!%7^(*=R-Ls$hMwEl!*D$|)xj`>x(GBqMVMeEZg{uOh7qdAvTV*AoC5bs zn4BK{*xG~c-HuAo)ni0&-K&{uYDN))PWU^u;3!nMY~{DL{nyi^XGjt`UM$s*wbT=I zGHve+Afjrkc>`+?@H-c7@VD@|qN0dX{biV+keKd4gS^Dp@BR6%&6=dG$nAp)Za!KnLO0LhS8wj||^M|61DQ&zKKi0P@^;+h$JU+Z!(OmSf@mO@X(A@iSm7F{*15b9f zxp~0rQQ11Xuzz}7=d$u}(}W_z5+?s`68_HT_Cb`7U|^>b`;j*BNseHDD_fE4P*iy_o)k;TqsOvp< z)EGQx)ycApkQ;K%maA)#c#m$;B2swX11;^;{Kgplya{{myJIzjR5UZ?)K zR3+8U6iug}g-W0La~b!5ffBY;>sP3hrCwdl`EVD}>aOkNPhkg{M9fPnM$BrBOvqNH z=3yzcM5QI1sAWqt>gXE0lg! zYV$>we+W>Cvylog^ZNyxwmPu3Jhr#aF_g@xFZPSPUH-%na{ibj`a zgQ>%A=Bn42s1t%zpng4KY?_V*H+bBg#l3W=0!eu9&`DD)_(|Ac~MZGwip`reT6VppQJCzLFk^9xf^u|4BWPA`aKAvB zFy42LenUHNdrX$s%yGf?8Hi*_=0d*P64Wk%jNs!$Rzja|PA4jVKykWP0YiS1gNE*#xeqWW&^@ChwUHkI3fZ0aH= zTQCb1OkngV8H9RgXwV_}ll_~C7{h7-wJlQb;kP9;n0#G=JwY}|yN5zTHsOwCB)VAB1)lBz)Bi8|SbdM`#?%>S{qD zaDT&h4TK26=9-OV(MM*t!M#fX<6_pbxMtlpnH93fSg?^D86bEN-HZLs=mdX-8kYZc zW@&Os2+tMnzJ|J2MDIOpTSDcO>z9tq?R~f>+*P2op-9>Qn=O#{0ina5Nr!ZsxqYY(9f>!R7-Hd&RY@JnosgJb>&m&9?@-5qt&|djw;sxjL{Aljky;cd?Uv{${i9^U?m zaba!e20Y;Y)(tYbqU8b@m{LWH1_qXo$c&>GD}vQqVfTw4F=@FN$U=QG5$b1cJdQHO zAP#eSkNqCzf<9wZ2!kGDNXYR??InL=Ld!a(P;~ka$zRM)8c1-=zYp7TAk(vHYJ|Qv zvyd%=BNtDxN>N)1?+tSS+dS+6EIcV;JHjlNoDPA1>8vz=NHOfbl)(uZsOCV1cfw#7 z@3dpa49-bEG{#)~0G=9_y0~6#9H<6+N?D`y$w+LQ9K7t%GvXcl4V;3Z&_F@H2b+_Q zG7j)+D~@7oC~fMH6r6V~Qj216IH?x=C|-v)-N$Kt0-C>>WTOxAR$`$X#6X*Ft~FOV+9vZ8gEY4bpgpXyRODSa=I1`M1eNZx z%-;5XOg`+Q2n=qM0{9PQF0<8a(GH@7jlzIp7wMFQ_(nar#g-7}UBOm7Jn9_ETi7lK z0;4?HWSj9iX(1=NV)RllS~CeA?re+5j@@8)SYE^wy@q5=ighQbYT?Z;${NI8j)8D- zNPvGhZUcd?m@#pd)%batngdIc=iz=FdH5|n8&*Ml%VN2;QARXK>}7#k-|JUUUv8!? zLUT?9AGq!#dcrF3_^zl2+F=CUAz@$b@6l7Dq%nCA&hwOKS76p+9~#Qy=5>WHci*@B z%ja7dzv0e#tyNL_oyj;vMdLK{)FlYD0-zV+<*R^4)ho7Eie_EUWNAoW*?>XoxTcl4 z#ZDEG`Y-~SG^yX?uTVWyoP@r{MZ+h-)uNaJ#)e+_0J+Np~bY&M&qmeU=a z7a{(fyQ-T}@)FmD31Pwm^lp8&{fnqIo_K=X_B#avUWn9daz-%)-puH7w(eHnCn$GD zKQ0GGVyw#eCZYmMAV|x#W*jM8DG)kZFfE95^(|O^J9@RHopybKm`Bo7u+P~|!PT<< zIIXo=Z7tawB6W+(hm>ciO$0(x=x)Yyt{?+TB?BGK7~jV49`U=6>4Cj!-xp_hf}>z- zMz_cG_%rz7YuIm1-y4B2a)Qm05hf$lCxd<-7SV*GFY_aq?Ha>bW1nzAd0>UI)AbM) zC-Ffk)oMROzC$-%QWBV2&m^zvV$E_**6Enn7pS-y&gUShc0g$@shSGu_kmj(lXM%z zcN4}smA$LCLYkvG0ZBR2e5|bnIJAy}dCmf>B(lB&+jrk<2@XYVyPB|1%E=rJ*`q76 zQ>Cz&2I@k-;-G8|6l`Hjg$Wvgu2PVAAO3}6U`wAt{loCAC0*0g5@@2+q_jXS9pT$U zZ{LC&FFDL9@k?FjKr#dwc}yO!?+RZktJXQn{ZWgmH0Il++(NJQCZXqa+YiSs_q`lH zNbi~u6K-Xh#_@(Z>p+3$FO%$%)=q`;_{-1qnOW6AtP@Go;kD#3*BPd(Wq+J4-IlsZ z_Ujy4qJN_p3v4>w9KlaT4xK3U`K!d*3?vMS8ID-Wkx+_M!ZJd+9O1 z8FKZ)2A~hC>z?kZJL4|5T6g$!6W2`@C7ChJ16Yeh0;3J7L)dv9Ka$ zeQ*GFS1iRWnZjvm#p{zWdAJkqG>jS_O!fed$Mt> zhvcor7OmE&nzE1e1sG&3yb4Lvu4MQHOF*L!-!5Nq9%$t40M|S~X4HYV=f9m)x$q++ zb|A?^AFq6c{|ukyMj&vWNdfi@6TfI<%ITHWQVqHQ`o{W^`Vr^qn>hcgI}R$J2&X*v zp?R#eawl5axqGz)=xlec-D7pg?{IbP>T0QuDl3@k4F3=8lo|AgrsGvT9fioB1X z6<^NKt_=n8lbi>G3vIYP3^VU22jjfx*k+NW(7kCKruYnFY5**v>6oBTrN1-AfoHzI zGdp}B5>>@A2V7x()}sjYf;>sqBl?Z1Ju&%eh|KMA_numi3eRhFXZ{Rj6V<}>F#J0L zz4txO(qCNE4hHEa(=nbq6zoS&NS+BEC-fK*gqaR53#ZGAG)533_ye3T-k_=-@d;Va zF)OKHa?72XP+ZiO5P^pVns4>I0xgUMJdxG12Uz2c zU*Ops@xMr5*L1Z`iUS0B`;dMas`^)a%JAQL>OZ9W{=EXM`qc+V741oEv42veTDdQB znM`?#Bf*F>m}K0wIBb(l7I%@-PSREb8pVQGKFTC+qW^=YlyvrZP<}pGN`e=2m|q?X z6d8X4`_1Vnj!nynDqBO^UCK+W%(d&kqHX_EixzKNVsR!5C1&+AQftW4=FG%?`CQ!V67fM(zr`6+N4 zVqX|jThdxJJ?VI4qM;|JpEahPr)bN&$W63UZ)MXKGC6P750&dRYTnvFp2EHRb}i8Y z2yMyTsjkwyp3*#RwD>jyH<5vd#$N%(>-L6jv-OU-{prPF-($Gc>MkeOYBlhq$C*ko z;ASc`QUYTm-ia?8NwS6p(6#r+nV~_1C1_BX1)P(5o!HHkmi4R+tWmb zBXKI%*M=I;AF1R|+>{wBZg=#i0|mfG<@@YQ^Nk}&eAF`4a(LIp=)qT4G6`;d`rUY- zWirq2gT@h8SA@YNjx3W^S``X*90EQUM@JuO!$FM}ugy+MwXRtAV2 zMRevB!{h|S5;!ucoJJX`7C|1BIyae1@0xSj=9MHur%05SsYdRp1ZhliMt{vZ0j73z z9BTG^s;4Q6*8n)bvsqkBq|SoPlr~LS7e*7}wFpeJY>r33ZDN0tH7P2=bBoGncjc_ZmXA4)GHOELF6Y z02d=q)sE{EFEIXg1X9DJZ|uzVtSYDvko*a!C~VzgM@A1y9b+dBP!O$l9BF&STg(v{ z(VypBH9xe1w=3?@*F>QWuf_SJJ@~7Rktqhai1OvGCElQgh*kPi0xUs*ZXa1yj2^@~ z$QcXQ8gB5!-Il|33sGm@j+ExAeq;R@l3pR7ypkbh)5~xuBlx*}7v^5Hm#)9DV2w)! zttF%o^#Q+hWQ&cFoG1;=DcU+iA+4*~rLI~DJEh=gP@4VNUd{e)I7$;Dy&R7*O>~pN z*cOW2c??GiieaVA`As)DnswJ~1|2E| zTWJD>6IF9^9})2=bUXy80Ii@CqKdD(Pj`fKA#7zoPKZcu`ND|?yL?%E84QnFVm^aW zy5M9tX+o|F1nS4>AAoN;G0Ig3>2H9?JX*XVk=dE6lI>JZ%ZrLRQMJr$ictAp3nvb4 zP23vnK>{oOIVVF$Od?YM-j?Q?k6639q95Bi(9U^#^oz<-i%a@wAYRj&SpE?grY#S~5BCgV+Evv!^c&tSfv`GclDRx~X|KLYtm}mn1s6_)iJve&^(B#R za6}^7#N42`#yR76_N7-63BHQlz+98~h$PwxH3+?WG@2*BAt{xH>lq{D>8}zf=hOW9 zirjHD$RS+1Ehzny0}>G#9wSwEBjU4fg#~;#d0cJ&u zyJQX5a^k&OPa&`Uc|*Pm3!NoJ9Jxb$@VskFop)l(TsdrM&T%R|nIBC5vSYLHWWl$5 zpFX%NjLS)~E1H0oXi|=6INn9#mFDD}hAL-olEO;HgAQs^4e?Piv}RHam+5t~;v&cKw6(EHuKQ&2OQIV76e(Hqdr{BFSmBu{^CVnM5>r_}y5v;(F)2qCpgGZ_x( z&UA6yKCUH@HWaJjYs__$w0od=SB3);J^2-|D@mU1?eDT}U?5(gi;8nZ%XRQ(nFH0# z_${HPhE9N+&{gUU%_WgjRA~LSI)vmPzq0j0Eol^~HWeN!AjgQ=d->}2=we;5?E0=5 zjXU$o>=Bk!$64nAEhjK2(o~r1GrP!+M&Y?n*XZJIvh;Bn$IKEv^cA}MbIiNSg<2Fn zKiL9>HUV-BTykbQ-E=?}Gi805X)EIPdD3+fwqp`VPL3p7y-0BdX%2oCj;Nn}gxE3# z{$))OB%)Zf(WTaER6CRO{abBdv{gYc(LO;2pk-l}7SJQ>H6yV&?UiIxFBZnCBbz}e z4Vg5m!pWFSTH+gLXYMHp`#h+=9aIfGsqU{~H)SUGaAQ|*e5{=BE@R6}37VOzg0jG|UdJ9?$U;&p9um^_b?+dtpd$0eo#qW=|dxWCqzqY*8H_#pu=WC$~Qeb4$ z4u)d1yeS1`Br@yH0}rqf=2j2>vA>HJ$p?CjtnDW2gH)7=*AEZi1G;=vNzdeT&inLZ z&s9$5FVCLOuXK^9DGlGeQIH|>7ecsW$jsRe4o#J$$&2#M=%uA0v(xlGE^4Iya=lfP zx6u{~0gdc2Y-y(|SWq)`m9%meSgabjPfNX94Be%#GqetE-0Yp`|7n0mxY9kcDtwzM zpG2w?Sw~%v<=wmzqGsKG+>$C1y3d5UrNa)|A{%8)`8=z!HIsP117^4zw}0Fgb-lrE zaMyRTIg5hvcT9cTm&%_fbXBz9TCwozX)4i~+1e;#zhOwCPfHZRmqQdu2|EpH#vl&x<*fdf`tvTSeu&=iG-`MLeOzu_c9 zpdJ`Vp}8t<$f5KA_FeRhE#4<+GP%-x@QIt`k6mgQLEPDQ#DDNV1Qd)Y6n0+544qbYFn_hddWTgkGoUhy75a65*EVCGUVmX=!_r9f|#<^IF@dqiYMlgIZNbJ3ZkN8^O z!ATJR{9-3qm>{dACt#;53}B}#*Dsy|dmD2j1IOQy15S^TmhTim4H^Rj74hVM)0K13 z4vLN9wE0>goH~aD^IDiYfzc`i76j^9N|lW6;nfqxCTa=eyvQca(Ow$o>V@3|<5LwNia0`+~QW+JYjFz_nM=R+OOjQ4e@q^}!i@Ss=g3gFa~S5B~1TJgej zm&_RO8GZUK;5s{e;3I4~0@7U|G^$rQlo(8o__49xT<8^yrY2j(g^wQc24oBiLxU-P zLUF)@DL^lLl^cfQ2{pv1^>O_|Zlnl|K54+~TDaoSLP(`;cN}ztIPa%>( ztpseD_?N@>zxC_^o6-MS%YOT%f;}W8B+!9-hZF$k{|YAHOy9}O(va5P$iT?V*747( z_|mjgqr+q8)FZM|v^A`=%s-^?As}bnCT#$s0ziOoV!;1j0iyx|Y6pM@0ulrqKgIC@ zqHiyXtf-P8t)!e7Koak-mpMaqxc}Hlr35&B{M4W2hp_DbT_!6iCn+YXs6;0#_7dU8 z6@V`PuL9WY_otEqIJdDk`5WhtKl#rU09Bwrl{Ucnk1PJI>iB4_I z4*ZSz*j*#>7*NR>KnwkFBKuiz0Z;BP0EBF89DmpZ*vjgeSp%{zf0_fltedI7p>Zw% zZw7F@{)r1XQvoFW`~q48Ao^fwqi6UZnZcKUgEm|a2!Li10MwV|FMwQtxX3>N0^S?0 zZh}sZrT{r+GlQRkCodV=Q$yDw0shRm0KW#Jzc8c%+UFk_{+N!vgqxP5U(N==3<3_u zzrbx^{39Hoz9#lY4h}K^A8;e<|F|!_gg2N!O0fepB_iw}2?9SECIOGqFKP==qPBE$ z0LZ_HnOPbM8W;c=Wc94|O#T}IXtDdU7NEfu01f`v&JjoOO9F9wJ%9U3N$@bSx)9^ueKL;8Jhzd|sz}~Ar6>j2xfK~-`Jb>ZnkG}V7+?@k8hY|qVBH#c3 z{i%=we!(x=MDjnq?$>zfrI|tq+4+5v1S&p40=t zU_$t(+5sLB)_=nLb?x%q7@Ac8HwXyu?EttVe=6P*zeJOi=JC0A9ksRIvXE?`r)|@GqvyFJWH_xBrBlxA`a7KSvo}V!o6O{)t)P^iP<7 zY@z*cBjZbf-k+!`&cA{B-{pE=R{y2u=uaXB_unP@qj~Cv4rNHA)0ury^AovHl z$CpemW#E1?nfm<(({G8wz2tl;=Jk^kJ@7X;|4G{GCDlt+ke^f>;lDxk4;mpanO>?d z{AA+#_!~@rbO*s-YB9W|dYSe9lZrOxx2XW*i|wD4`(Bc~OdS46A|Lp9J)PPpKC#o1bH}L;CYv<*Ud70MmldLM|f0O-slJ#=^`6s4k-QO_()f|6cjec3r zm$C1kn9QyJ8}pyuQ7_|(Kan}x|Bn3o(Z#?0f)_EapFD7#f8%*M?fg@Z{U5LKmvNV$ zG;3Y|H>LY;QJDYK`9Cq2KL<^I#9V$B#_s \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save ( ) { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/appengine/endpoints-frameworks-v2/guice-example/gradlew.bat b/appengine/endpoints-frameworks-v2/guice-example/gradlew.bat new file mode 100644 index 00000000000..e95643d6a2c --- /dev/null +++ b/appengine/endpoints-frameworks-v2/guice-example/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/appengine/endpoints-frameworks-v2/guice-example/pom.xml b/appengine/endpoints-frameworks-v2/guice-example/pom.xml new file mode 100644 index 00000000000..ef8ae97fae8 --- /dev/null +++ b/appengine/endpoints-frameworks-v2/guice-example/pom.xml @@ -0,0 +1,118 @@ + + + 4.0.0 + war + 1.0-SNAPSHOT + + com.example.echo + echo + + + appengine-doc-samples + com.google.cloud + 1.0.0 + ../.. + + + + UTF-8 + + 2.0.7 + 1.0.4 + + YOUR_PROJECT_ID + 1.7 + 1.7 + 1.3.1 + + + + + + com.google.endpoints + endpoints-framework + ${endpoints.framework.version} + + + com.google.endpoints + endpoints-framework-guice + 2.0.8 + + + com.google.endpoints + endpoints-management-control-appengine-all + 1.0.4 + + + com.google.appengine + appengine-api-1.0-sdk + 1.9.54 + + + javax.servlet + servlet-api + 2.5 + provided + + + javax.inject + javax.inject + 1 + + + + + + ${project.build.directory}/${project.build.finalName}/WEB-INF/classes + + + com.google.cloud.tools + appengine-maven-plugin + ${appengine.maven.plugin.version} + + + + + + com.google.cloud.tools + endpoints-framework-maven-plugin + 1.0.1 + + + ${endpoints.project.id}.appspot.com + + com.example.echo.Echo + + + + + org.codehaus.mojo + versions-maven-plugin + 2.3 + + + compile + + display-dependency-updates + display-plugin-updates + + + + + + + diff --git a/appengine/endpoints-frameworks-v2/guice-example/src/main/java/com/example/echo/Echo.java b/appengine/endpoints-frameworks-v2/guice-example/src/main/java/com/example/echo/Echo.java new file mode 100644 index 00000000000..5804e86dfca --- /dev/null +++ b/appengine/endpoints-frameworks-v2/guice-example/src/main/java/com/example/echo/Echo.java @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2016 Google Inc. + * + * 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 com.example.echo; + +import com.google.api.server.spi.auth.EspAuthenticator; +import com.google.api.server.spi.auth.common.User; +import com.google.api.server.spi.config.AnnotationBoolean; +import com.google.api.server.spi.config.Api; +import com.google.api.server.spi.config.ApiIssuer; +import com.google.api.server.spi.config.ApiIssuerAudience; +import com.google.api.server.spi.config.ApiMethod; +import com.google.api.server.spi.config.ApiNamespace; +import com.google.api.server.spi.config.Named; +import com.google.api.server.spi.config.Nullable; +import com.google.api.server.spi.response.UnauthorizedException; + +/** The Echo API which Endpoints will be exposing. */ +// [START echo_api_annotation] +@Api( + name = "echo", + version = "v1", + namespace = + @ApiNamespace( + ownerDomain = "echo.example.com", + ownerName = "echo.example.com", + packagePath = "" + ), + // [START_EXCLUDE] + issuers = { + @ApiIssuer( + name = "firebase", + issuer = "https://securetoken.google.com/YOUR-PROJECT-ID", + jwksUri = "https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com") + } + // [END_EXCLUDE] + ) +// [END echo_api_annotation] +public class Echo { + /** + * Echoes the received message back. If n is a non-negative integer, the message is copied that + * many times in the returned message. + * + * Note that name is specified and will override the default name of "{class name}.{method + * name}". For example, the default is "echo.echo". + * + * Note that httpMethod is not specified. This will default to a reasonable HTTP method + * depending on the API method name. In this case, the HTTP method will default to POST. + */ + // [START echo_method] + @ApiMethod(name = "echo") + public Message echo(Message message, @Named("n") @Nullable Integer n) { + return doEcho(message, n); + } + // [END echo_method] + + /** + * Echoes the received message back. If n is a non-negative integer, the message is copied that + * many times in the returned message. + * + * Note that name is specified and will override the default name of "{class name}.{method + * name}". For example, the default is "echo.echo". + * + * Note that httpMethod is not specified. This will default to a reasonable HTTP method + * depending on the API method name. In this case, the HTTP method will default to POST. + */ + // [START echo_path] + @ApiMethod(name = "echo_path_parameter", path = "echo/{n}") + public Message echoPathParameter(Message message, @Named("n") int n) { + return doEcho(message, n); + } + // [END echo_path] + + /** + * Echoes the received message back. If n is a non-negative integer, the message is copied that + * many times in the returned message. + * + * Note that name is specified and will override the default name of "{class name}.{method + * name}". For example, the default is "echo.echo". + * + * Note that httpMethod is not specified. This will default to a reasonable HTTP method + * depending on the API method name. In this case, the HTTP method will default to POST. + */ + // [START echo_api_key] + @ApiMethod(name = "echo_api_key", path = "echo_api_key", apiKeyRequired = AnnotationBoolean.TRUE) + public Message echoApiKey(Message message, @Named("n") @Nullable Integer n) { + return doEcho(message, n); + } + // [END echo_api_key] + + private Message doEcho(Message message, Integer n) { + if (n != null && n >= 0) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < n; i++) { + if (i > 0) { + sb.append(" "); + } + sb.append(message.getMessage()); + } + message.setMessage(sb.toString()); + } + return message; + } + + /** + * Gets the authenticated user's email. If the user is not authenticated, this will return an HTTP + * 401. + * + * Note that name is not specified. This will default to "{class name}.{method name}". For + * example, the default is "echo.getUserEmail". + * + * Note that httpMethod is not required here. Without httpMethod, this will default to GET due + * to the API method name. httpMethod is added here for example purposes. + */ + // [START google_id_token_auth] + @ApiMethod( + httpMethod = ApiMethod.HttpMethod.GET, + authenticators = {EspAuthenticator.class}, + audiences = {"YOUR_OAUTH_CLIENT_ID"}, + clientIds = {"YOUR_OAUTH_CLIENT_ID"} + ) + public Email getUserEmail(User user) throws UnauthorizedException { + if (user == null) { + throw new UnauthorizedException("Invalid credentials"); + } + + Email response = new Email(); + response.setEmail(user.getEmail()); + return response; + } + // [END google_id_token_auth] + + /** + * Gets the authenticated user's email. If the user is not authenticated, this will return an HTTP + * 401. + * + * Note that name is not specified. This will default to "{class name}.{method name}". For + * example, the default is "echo.getUserEmail". + * + * Note that httpMethod is not required here. Without httpMethod, this will default to GET due + * to the API method name. httpMethod is added here for example purposes. + */ + // [START firebase_auth] + @ApiMethod( + path = "firebase_user", + httpMethod = ApiMethod.HttpMethod.GET, + authenticators = {EspAuthenticator.class}, + issuerAudiences = {@ApiIssuerAudience(name = "firebase", audiences = {"YOUR-PROJECT-ID"})} + ) + public Email getUserEmailFirebase(User user) throws UnauthorizedException { + if (user == null) { + throw new UnauthorizedException("Invalid credentials"); + } + + Email response = new Email(); + response.setEmail(user.getEmail()); + return response; + } + // [END firebase_auth] +} diff --git a/appengine/endpoints-frameworks-v2/guice-example/src/main/java/com/example/echo/EchoEndpointModule.java b/appengine/endpoints-frameworks-v2/guice-example/src/main/java/com/example/echo/EchoEndpointModule.java new file mode 100644 index 00000000000..798648a1781 --- /dev/null +++ b/appengine/endpoints-frameworks-v2/guice-example/src/main/java/com/example/echo/EchoEndpointModule.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2017 Google Inc. + * + * 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 com.example.echo; + +import com.google.api.server.spi.guice.EndpointsModule; +import com.google.common.collect.ImmutableList; + +// [START endpoints_module] +public class EchoEndpointModule extends EndpointsModule { + @Override + public void configureServlets() { + bind(Echo.class).toInstance(new Echo()); + configureEndpoints("/_ah/api/*", ImmutableList.of(Echo.class)); + } +} +// [END endpoints_module] diff --git a/appengine/endpoints-frameworks-v2/guice-example/src/main/java/com/example/echo/EchoGuiceListener.java b/appengine/endpoints-frameworks-v2/guice-example/src/main/java/com/example/echo/EchoGuiceListener.java new file mode 100644 index 00000000000..b007f059606 --- /dev/null +++ b/appengine/endpoints-frameworks-v2/guice-example/src/main/java/com/example/echo/EchoGuiceListener.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2017 Google Inc. + * + * 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 com.example.echo; + +//import com.google.api.server.spi.guice.GuiceServletContextListener; +import com.google.inject.Guice; +import com.google.inject.Injector; +import com.google.inject.servlet.GuiceServletContextListener; + +// [START injector] +public class EchoGuiceListener extends GuiceServletContextListener { + @Override + protected Injector getInjector() { + return Guice.createInjector(new EchoEndpointModule()); + } +} +// [END injector] diff --git a/appengine/endpoints-frameworks-v2/guice-example/src/main/java/com/example/echo/Email.java b/appengine/endpoints-frameworks-v2/guice-example/src/main/java/com/example/echo/Email.java new file mode 100644 index 00000000000..e7725a9d9cc --- /dev/null +++ b/appengine/endpoints-frameworks-v2/guice-example/src/main/java/com/example/echo/Email.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2016 Google Inc. + * + * 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 com.example.echo; + +/** The email bean that will be used in the getUserEmail response. */ +public class Email { + private String email; + + public String getEmail() { + return this.email; + } + + public void setEmail(String email) { + this.email = email; + } +} diff --git a/appengine/endpoints-frameworks-v2/guice-example/src/main/java/com/example/echo/Message.java b/appengine/endpoints-frameworks-v2/guice-example/src/main/java/com/example/echo/Message.java new file mode 100644 index 00000000000..64c043c8857 --- /dev/null +++ b/appengine/endpoints-frameworks-v2/guice-example/src/main/java/com/example/echo/Message.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2016 Google Inc. + * + * 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 com.example.echo; + +/** The message bean that will be used in the echo request and response. */ +public class Message { + + private String message; + + public String getMessage() { + return this.message; + } + + public void setMessage(String message) { + this.message = message; + } +} diff --git a/appengine/endpoints-frameworks-v2/guice-example/src/main/main74.iml b/appengine/endpoints-frameworks-v2/guice-example/src/main/main74.iml new file mode 100644 index 00000000000..e44df5c20e5 --- /dev/null +++ b/appengine/endpoints-frameworks-v2/guice-example/src/main/main74.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/appengine/endpoints-frameworks-v2/guice-example/src/main/webapp/WEB-INF/appengine-web.xml b/appengine/endpoints-frameworks-v2/guice-example/src/main/webapp/WEB-INF/appengine-web.xml new file mode 100644 index 00000000000..5a482456b7a --- /dev/null +++ b/appengine/endpoints-frameworks-v2/guice-example/src/main/webapp/WEB-INF/appengine-web.xml @@ -0,0 +1,33 @@ + + + + ${endpoints.project.id} + 1 + true + + + 2 + + + + + + + + + + diff --git a/appengine/endpoints-frameworks-v2/guice-example/src/main/webapp/WEB-INF/logging.properties b/appengine/endpoints-frameworks-v2/guice-example/src/main/webapp/WEB-INF/logging.properties new file mode 100644 index 00000000000..6279d0fef33 --- /dev/null +++ b/appengine/endpoints-frameworks-v2/guice-example/src/main/webapp/WEB-INF/logging.properties @@ -0,0 +1,25 @@ +# Copyright 2016 Google Inc. +# +# 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. + +# A default java.util.logging configuration. +# (All App Engine logging is through java.util.logging by default). +# +# To use this configuration, copy it into your application's WEB-INF +# folder and add the following to your appengine-web.xml: +# +# +# +# +# + +# Set the default logging level for all loggers to WARNING +.level = WARNING diff --git a/appengine/endpoints-frameworks-v2/guice-example/src/main/webapp/WEB-INF/web.xml b/appengine/endpoints-frameworks-v2/guice-example/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000000..08b68ffe06d --- /dev/null +++ b/appengine/endpoints-frameworks-v2/guice-example/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,67 @@ + + + + + + + guiceFilter + com.google.inject.servlet.GuiceFilter + + + + guiceFilter + /_ah/api/* + + + + com.example.echo.EchoGuiceListener + + + + index.html + + + + + endpoints-api-configuration + com.google.api.control.ServiceManagementConfigFilter + + + + + endpoints-api-controller + com.google.api.control.extensions.appengine.GoogleAppEngineControlFilter + + endpoints.projectId + ${endpoints.project.id} + + + endpoints.serviceName + ${endpoints.project.id}.appspot.com + + + + + endpoints-api-configuration + EndpointsServlet + + + + endpoints-api-controller + EndpointsServlet + + From 2746f9cb5700794537053a555b8169b1f1064eca Mon Sep 17 00:00:00 2001 From: Frank Natividad Date: Sat, 2 Sep 2017 04:46:01 -0700 Subject: [PATCH 02/17] Fix - to _ --- appengine-java8/endpoints-v2-backend/pom.xml | 2 +- appengine/endpoints-frameworks-v2/backend/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/appengine-java8/endpoints-v2-backend/pom.xml b/appengine-java8/endpoints-v2-backend/pom.xml index 994565b9aad..b2f73058262 100644 --- a/appengine-java8/endpoints-v2-backend/pom.xml +++ b/appengine-java8/endpoints-v2-backend/pom.xml @@ -34,7 +34,7 @@ 2.0.7 1.0.4 - YOUR-PROJECT-ID + YOUR_PROJECT_ID 1.8 1.8 1.3.1 diff --git a/appengine/endpoints-frameworks-v2/backend/pom.xml b/appengine/endpoints-frameworks-v2/backend/pom.xml index 60577923b85..42ec255cb74 100644 --- a/appengine/endpoints-frameworks-v2/backend/pom.xml +++ b/appengine/endpoints-frameworks-v2/backend/pom.xml @@ -34,7 +34,7 @@ 2.0.7 1.0.4 - YOUR-PROJECT-ID + YOUR_PROJECT_ID 1.7 1.7 1.3.1 From e8672098b9f1ebd80e5f20495e083fbab97a1036 Mon Sep 17 00:00:00 2001 From: Frank Natividad Date: Sat, 2 Sep 2017 04:52:36 -0700 Subject: [PATCH 03/17] Remove unneeded comment --- .../src/main/java/com/example/echo/EchoGuiceListener.java | 1 - 1 file changed, 1 deletion(-) diff --git a/appengine/endpoints-frameworks-v2/guice-example/src/main/java/com/example/echo/EchoGuiceListener.java b/appengine/endpoints-frameworks-v2/guice-example/src/main/java/com/example/echo/EchoGuiceListener.java index b007f059606..7de3ed6546e 100644 --- a/appengine/endpoints-frameworks-v2/guice-example/src/main/java/com/example/echo/EchoGuiceListener.java +++ b/appengine/endpoints-frameworks-v2/guice-example/src/main/java/com/example/echo/EchoGuiceListener.java @@ -16,7 +16,6 @@ package com.example.echo; -//import com.google.api.server.spi.guice.GuiceServletContextListener; import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.servlet.GuiceServletContextListener; From 8f07a370b9f53f371609a498a51a47b85dc5c38d Mon Sep 17 00:00:00 2001 From: Frank Natividad Date: Sat, 2 Sep 2017 16:07:29 -0700 Subject: [PATCH 04/17] Fixing token replacement and cleaning up Guice --- .../src/main/webapp/WEB-INF/appengine-web.xml | 2 -- .../endpoints-frameworks-v2/guice-example/pom.xml | 14 ++++++++++++++ .../java/com/example/echo/EchoEndpointModule.java | 1 + .../src/main/webapp/WEB-INF/appengine-web.xml | 2 -- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/appengine/endpoints-frameworks-v2/backend/src/main/webapp/WEB-INF/appengine-web.xml b/appengine/endpoints-frameworks-v2/backend/src/main/webapp/WEB-INF/appengine-web.xml index 5a482456b7a..beabaaa425a 100644 --- a/appengine/endpoints-frameworks-v2/backend/src/main/webapp/WEB-INF/appengine-web.xml +++ b/appengine/endpoints-frameworks-v2/backend/src/main/webapp/WEB-INF/appengine-web.xml @@ -15,8 +15,6 @@ limitations under the License. --> - ${endpoints.project.id} - 1 true diff --git a/appengine/endpoints-frameworks-v2/guice-example/pom.xml b/appengine/endpoints-frameworks-v2/guice-example/pom.xml index ef8ae97fae8..6c6028bf7f7 100644 --- a/appengine/endpoints-frameworks-v2/guice-example/pom.xml +++ b/appengine/endpoints-frameworks-v2/guice-example/pom.xml @@ -99,6 +99,20 @@ + + org.apache.maven.plugins + maven-war-plugin + 2.6 + + + + ${basedir}/src/main/webapp/WEB-INF + true + WEB-INF + + + + org.codehaus.mojo versions-maven-plugin diff --git a/appengine/endpoints-frameworks-v2/guice-example/src/main/java/com/example/echo/EchoEndpointModule.java b/appengine/endpoints-frameworks-v2/guice-example/src/main/java/com/example/echo/EchoEndpointModule.java index 798648a1781..ed40f5b1117 100644 --- a/appengine/endpoints-frameworks-v2/guice-example/src/main/java/com/example/echo/EchoEndpointModule.java +++ b/appengine/endpoints-frameworks-v2/guice-example/src/main/java/com/example/echo/EchoEndpointModule.java @@ -25,6 +25,7 @@ public class EchoEndpointModule extends EndpointsModule { public void configureServlets() { bind(Echo.class).toInstance(new Echo()); configureEndpoints("/_ah/api/*", ImmutableList.of(Echo.class)); + super.configureServlets(); } } // [END endpoints_module] diff --git a/appengine/endpoints-frameworks-v2/guice-example/src/main/webapp/WEB-INF/appengine-web.xml b/appengine/endpoints-frameworks-v2/guice-example/src/main/webapp/WEB-INF/appengine-web.xml index 5a482456b7a..beabaaa425a 100644 --- a/appengine/endpoints-frameworks-v2/guice-example/src/main/webapp/WEB-INF/appengine-web.xml +++ b/appengine/endpoints-frameworks-v2/guice-example/src/main/webapp/WEB-INF/appengine-web.xml @@ -15,8 +15,6 @@ limitations under the License. --> - ${endpoints.project.id} - 1 true From d06c86d7763744885124b31f46d210d4eb1f830c Mon Sep 17 00:00:00 2001 From: Frank Natividad Date: Sat, 2 Sep 2017 16:09:39 -0700 Subject: [PATCH 05/17] Updating README --- appengine/endpoints-frameworks-v2/guice-example/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appengine/endpoints-frameworks-v2/guice-example/README.md b/appengine/endpoints-frameworks-v2/guice-example/README.md index b35818ec1ad..c4b4701c390 100644 --- a/appengine/endpoints-frameworks-v2/guice-example/README.md +++ b/appengine/endpoints-frameworks-v2/guice-example/README.md @@ -33,7 +33,7 @@ To build the project: To generate the required configuration file `openapi.json`: - mvn endpoints-framework:openApiDoc + mvn endpoints-framework:openApiDocs ### Deploying the sample API to App Engine @@ -41,7 +41,7 @@ To deploy the sample API: 0. Invoke the `gcloud` command to deploy the API configuration file: - gcloud service-management deploy openapi.json + gcloud service-management deploy target/openapi-docs/openapi.json 0. Deploy the API implementation code by invoking: From 30df589f4ebf9ec2a1a786f16992c1fcd15d851d Mon Sep 17 00:00:00 2001 From: Frank Natividad Date: Sat, 2 Sep 2017 16:26:46 -0700 Subject: [PATCH 06/17] Update build.gradle --- appengine/endpoints-frameworks-v2/guice-example/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appengine/endpoints-frameworks-v2/guice-example/build.gradle b/appengine/endpoints-frameworks-v2/guice-example/build.gradle index 369637a8f8c..ce3950c474e 100644 --- a/appengine/endpoints-frameworks-v2/guice-example/build.gradle +++ b/appengine/endpoints-frameworks-v2/guice-example/build.gradle @@ -63,7 +63,7 @@ targetCompatibility = 1.7 // App Engine Standard uses Java 7 task replaceProjectId(type: Copy) { from 'src/main/webapp/WEB-INF/' include '*.xml' - into 'build/exploded-backend/WEB-INF' + into 'build/exploded-guice-example/WEB-INF' expand(endpoints:[project:[id:projectId]]) filteringCharset = 'UTF-8' } From 06a2bb0ec7c17442f60f10ca1bd5bab4e7fca550 Mon Sep 17 00:00:00 2001 From: Frank Natividad Date: Sat, 2 Sep 2017 16:31:15 -0700 Subject: [PATCH 07/17] Fix pom.xml and README --- .../endpoints-frameworks-v2/backend/README.md | 2 +- appengine/endpoints-frameworks-v2/backend/pom.xml | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/appengine/endpoints-frameworks-v2/backend/README.md b/appengine/endpoints-frameworks-v2/backend/README.md index 4f60f254d42..fe4ed67cbcb 100644 --- a/appengine/endpoints-frameworks-v2/backend/README.md +++ b/appengine/endpoints-frameworks-v2/backend/README.md @@ -41,7 +41,7 @@ To deploy the sample API: 0. Invoke the `gcloud` command to deploy the API configuration file: - gcloud service-management deploy openapi.json + gcloud service-management deploy target/openapi-docs/openapi.json 0. Deploy the API implementation code by invoking: diff --git a/appengine/endpoints-frameworks-v2/backend/pom.xml b/appengine/endpoints-frameworks-v2/backend/pom.xml index 42ec255cb74..e919e18312a 100644 --- a/appengine/endpoints-frameworks-v2/backend/pom.xml +++ b/appengine/endpoints-frameworks-v2/backend/pom.xml @@ -91,6 +91,20 @@ ${endpoints.project.id}.appspot.com + + org.apache.maven.plugins + maven-war-plugin + 2.6 + + + + ${basedir}/src/main/webapp/WEB-INF + true + WEB-INF + + + + org.codehaus.mojo versions-maven-plugin From 663dc8fa76cd717d6af6ed24238bf7ab83fcdefe Mon Sep 17 00:00:00 2001 From: Frank Natividad Date: Sat, 2 Sep 2017 16:33:00 -0700 Subject: [PATCH 08/17] Fix README.md --- appengine-java8/endpoints-v2-backend/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appengine-java8/endpoints-v2-backend/README.md b/appengine-java8/endpoints-v2-backend/README.md index 4f60f254d42..fe4ed67cbcb 100644 --- a/appengine-java8/endpoints-v2-backend/README.md +++ b/appengine-java8/endpoints-v2-backend/README.md @@ -41,7 +41,7 @@ To deploy the sample API: 0. Invoke the `gcloud` command to deploy the API configuration file: - gcloud service-management deploy openapi.json + gcloud service-management deploy target/openapi-docs/openapi.json 0. Deploy the API implementation code by invoking: From 667e397049479b2e89e036d20ac651095ca1bb04 Mon Sep 17 00:00:00 2001 From: Frank Natividad Date: Sat, 2 Sep 2017 16:37:04 -0700 Subject: [PATCH 09/17] Fix errors --- appengine-java8/endpoints-v2-guice/README.md | 2 +- appengine-java8/endpoints-v2-guice/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/appengine-java8/endpoints-v2-guice/README.md b/appengine-java8/endpoints-v2-guice/README.md index b35818ec1ad..3209a5539a0 100644 --- a/appengine-java8/endpoints-v2-guice/README.md +++ b/appengine-java8/endpoints-v2-guice/README.md @@ -41,7 +41,7 @@ To deploy the sample API: 0. Invoke the `gcloud` command to deploy the API configuration file: - gcloud service-management deploy openapi.json + gcloud service-management deploy target/openapi-docs/openapi.json 0. Deploy the API implementation code by invoking: diff --git a/appengine-java8/endpoints-v2-guice/build.gradle b/appengine-java8/endpoints-v2-guice/build.gradle index fd412eff529..389869551e1 100644 --- a/appengine-java8/endpoints-v2-guice/build.gradle +++ b/appengine-java8/endpoints-v2-guice/build.gradle @@ -63,7 +63,7 @@ targetCompatibility = 1.8 // App Engine Standard uses Java 8 task replaceProjectId(type: Copy) { from 'src/main/webapp/WEB-INF/' include '*.xml' - into 'build/exploded-backend/WEB-INF' + into 'build/exploded-guice-example/WEB-INF' expand(endpoints:[project:[id:projectId]]) filteringCharset = 'UTF-8' } From 7b65908aa59a9747621fc235791a32187b806e78 Mon Sep 17 00:00:00 2001 From: Frank Natividad Date: Sat, 2 Sep 2017 16:59:32 -0700 Subject: [PATCH 10/17] Adding tests for endpoints-backend --- .../endpoints-v2-backend/build.gradle | 11 ++++ .../endpoints-v2-backend/jenkins.sh | 61 +++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100755 appengine-java8/endpoints-v2-backend/jenkins.sh diff --git a/appengine-java8/endpoints-v2-backend/build.gradle b/appengine-java8/endpoints-v2-backend/build.gradle index 2e169b5cb8e..c361d7da1b9 100644 --- a/appengine-java8/endpoints-v2-backend/build.gradle +++ b/appengine-java8/endpoints-v2-backend/build.gradle @@ -54,6 +54,17 @@ endpointsServer { hostname = "${projectId}.appspot.com" } +appengine { // App Engine tasks configuration + deploy { // deploy configuration + version = findProperty("appengine.deploy.version") + + def promoteProp = findProperty("appengine.deploy.promote") + if (promoteProp != null) { + promote = new Boolean(promoteProp) + } + } +} + sourceCompatibility = 1.8 targetCompatibility = 1.8 diff --git a/appengine-java8/endpoints-v2-backend/jenkins.sh b/appengine-java8/endpoints-v2-backend/jenkins.sh new file mode 100755 index 00000000000..ba77cc0251b --- /dev/null +++ b/appengine-java8/endpoints-v2-backend/jenkins.sh @@ -0,0 +1,61 @@ +#!/usr/bin/env bash + +# Copyright 2017 Google Inc. +# +# 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. + +# Fail on non-zero return and print command to stdout +set -xe + +# Jenkins Test Script +function TestEndpoints () { + # Test getGreeting Endpoint (hello world!) + curl -H "Content-Type: application/json" \ + -X POST \ + -d "{'message':'hello ${3} version-${2}'}" \ + "https://${2}-dot-${1}.appspot.com/_ah/api/echo/v1/echo" | \ + tee "$ERROR_OUTPUT_DIR/response.json" | \ + grep "hello ${3} version-${2}" +} + +# Jenkins provides values for GOOGLE_PROJECT_ID and GOOGLE_VERSION_ID +# Update Greetings.java +UNIQUE_MAVEN_STRING="maven" +sed -i'.bak' -e "s/YOUR_PROJECT_ID/${GOOGLE_PROJECT_ID}/g" pom.xml + +# Test with Maven +mvn clean appengine:deploy \ + -Dapp.deploy.version="${GOOGLE_VERSION_ID}" \ + -Dapp.deploy.promote=false + +# End-2-End tests +TestEndpoints "${GOOGLE_PROJECT_ID}" "${GOOGLE_VERSION_ID}" "${UNIQUE_MAVEN_STRING}" + +# Clean +mvn clean + +# Test with Gradle +# Modify Greetings.java for Gradle +UNIQUE_GRADLE_STRING="gradle" +sed -i'.bak' -e "s/YOUR_PROJECT_ID/${GOOGLE_PROJECT_ID}/g" build.gradle + +# Deploy Gradle +gradle -Pappengine.deploy.promote=false \ + -Pappengine.deploy.version="${GOOGLE_VERSION_ID}" \ + appengineDeploy + +# End-2-End tests +TestEndpoints "${GOOGLE_PROJECT_ID}" "${GOOGLE_VERSION_ID}" "${UNIQUE_GRADLE_STRING}" + +# Clean +gradle clean From f5a7038195c00d8c5734e4af599b915bde88e291 Mon Sep 17 00:00:00 2001 From: Frank Natividad Date: Sat, 2 Sep 2017 17:02:37 -0700 Subject: [PATCH 11/17] tests --- appengine-java8/endpoints-v2-backend/jenkins.sh | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/appengine-java8/endpoints-v2-backend/jenkins.sh b/appengine-java8/endpoints-v2-backend/jenkins.sh index ba77cc0251b..2c9b79c6214 100755 --- a/appengine-java8/endpoints-v2-backend/jenkins.sh +++ b/appengine-java8/endpoints-v2-backend/jenkins.sh @@ -33,8 +33,12 @@ function TestEndpoints () { UNIQUE_MAVEN_STRING="maven" sed -i'.bak' -e "s/YOUR_PROJECT_ID/${GOOGLE_PROJECT_ID}/g" pom.xml +mvn clean endpoints-framework:openApiDocs + +gcloud service-management deploy target/openapi-docs/openapi.json + # Test with Maven -mvn clean appengine:deploy \ +mvn appengine:deploy \ -Dapp.deploy.version="${GOOGLE_VERSION_ID}" \ -Dapp.deploy.promote=false @@ -49,10 +53,14 @@ mvn clean UNIQUE_GRADLE_STRING="gradle" sed -i'.bak' -e "s/YOUR_PROJECT_ID/${GOOGLE_PROJECT_ID}/g" build.gradle +gradle clean endpointsOpenApiDocs + +gcloud service-management deploy build/endpointsOpenApiDocs/openapi.json + # Deploy Gradle gradle -Pappengine.deploy.promote=false \ - -Pappengine.deploy.version="${GOOGLE_VERSION_ID}" \ - appengineDeploy + -Pappengine.deploy.version="${GOOGLE_VERSION_ID}" \ + appengineDeploy # End-2-End tests TestEndpoints "${GOOGLE_PROJECT_ID}" "${GOOGLE_VERSION_ID}" "${UNIQUE_GRADLE_STRING}" From 249f0b439a0584c2eb5b88d44ef0bdfc2e0e15fe Mon Sep 17 00:00:00 2001 From: Frank Natividad Date: Sat, 2 Sep 2017 17:06:13 -0700 Subject: [PATCH 12/17] fix build.gradle --- appengine-java8/endpoints-v2-guice/build.gradle | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/appengine-java8/endpoints-v2-guice/build.gradle b/appengine-java8/endpoints-v2-guice/build.gradle index 389869551e1..b9b24757509 100644 --- a/appengine-java8/endpoints-v2-guice/build.gradle +++ b/appengine-java8/endpoints-v2-guice/build.gradle @@ -56,6 +56,17 @@ endpointsServer { serviceClasses = ['com.example.echo.Echo'] } +appengine { // App Engine tasks configuration + deploy { // deploy configuration + version = findProperty("appengine.deploy.version") + + def promoteProp = findProperty("appengine.deploy.promote") + if (promoteProp != null) { + promote = new Boolean(promoteProp) + } + } +} + sourceCompatibility = 1.8 // App Engine Standard uses Java 8 targetCompatibility = 1.8 // App Engine Standard uses Java 8 @@ -63,7 +74,7 @@ targetCompatibility = 1.8 // App Engine Standard uses Java 8 task replaceProjectId(type: Copy) { from 'src/main/webapp/WEB-INF/' include '*.xml' - into 'build/exploded-guice-example/WEB-INF' + into 'build/exploded-endpoints-v2-guice/WEB-INF' expand(endpoints:[project:[id:projectId]]) filteringCharset = 'UTF-8' } From 441a9a33f6bcc1b195d9a2b4cb4c186d35ffb787 Mon Sep 17 00:00:00 2001 From: Frank Natividad Date: Sat, 2 Sep 2017 17:08:49 -0700 Subject: [PATCH 13/17] Add jenkins tests to endpoints backend and guice --- .../backend/build.gradle | 11 +++ .../backend/jenkins.sh | 69 +++++++++++++++ .../build.gradle | 81 ++++++++++++++++++ .../guice-example-hello-greetings/jenkins.sh | 83 +++++++++++++++++++ .../guice-example/build.gradle | 11 +++ .../guice-example/jenkins.sh | 69 +++++++++++++++ 6 files changed, 324 insertions(+) create mode 100755 appengine/endpoints-frameworks-v2/backend/jenkins.sh create mode 100644 appengine/endpoints-frameworks-v2/guice-example-hello-greetings/build.gradle create mode 100755 appengine/endpoints-frameworks-v2/guice-example-hello-greetings/jenkins.sh create mode 100755 appengine/endpoints-frameworks-v2/guice-example/jenkins.sh diff --git a/appengine/endpoints-frameworks-v2/backend/build.gradle b/appengine/endpoints-frameworks-v2/backend/build.gradle index a5e8422b486..cef30ec9807 100644 --- a/appengine/endpoints-frameworks-v2/backend/build.gradle +++ b/appengine/endpoints-frameworks-v2/backend/build.gradle @@ -54,6 +54,17 @@ endpointsServer { hostname = "${projectId}.appspot.com" } +appengine { // App Engine tasks configuration + deploy { // deploy configuration + version = findProperty("appengine.deploy.version") + + def promoteProp = findProperty("appengine.deploy.promote") + if (promoteProp != null) { + promote = new Boolean(promoteProp) + } + } +} + sourceCompatibility = 1.7 // App Engine Standard uses Java 7 targetCompatibility = 1.7 // App Engine Standard uses Java 7 diff --git a/appengine/endpoints-frameworks-v2/backend/jenkins.sh b/appengine/endpoints-frameworks-v2/backend/jenkins.sh new file mode 100755 index 00000000000..2c9b79c6214 --- /dev/null +++ b/appengine/endpoints-frameworks-v2/backend/jenkins.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash + +# Copyright 2017 Google Inc. +# +# 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. + +# Fail on non-zero return and print command to stdout +set -xe + +# Jenkins Test Script +function TestEndpoints () { + # Test getGreeting Endpoint (hello world!) + curl -H "Content-Type: application/json" \ + -X POST \ + -d "{'message':'hello ${3} version-${2}'}" \ + "https://${2}-dot-${1}.appspot.com/_ah/api/echo/v1/echo" | \ + tee "$ERROR_OUTPUT_DIR/response.json" | \ + grep "hello ${3} version-${2}" +} + +# Jenkins provides values for GOOGLE_PROJECT_ID and GOOGLE_VERSION_ID +# Update Greetings.java +UNIQUE_MAVEN_STRING="maven" +sed -i'.bak' -e "s/YOUR_PROJECT_ID/${GOOGLE_PROJECT_ID}/g" pom.xml + +mvn clean endpoints-framework:openApiDocs + +gcloud service-management deploy target/openapi-docs/openapi.json + +# Test with Maven +mvn appengine:deploy \ + -Dapp.deploy.version="${GOOGLE_VERSION_ID}" \ + -Dapp.deploy.promote=false + +# End-2-End tests +TestEndpoints "${GOOGLE_PROJECT_ID}" "${GOOGLE_VERSION_ID}" "${UNIQUE_MAVEN_STRING}" + +# Clean +mvn clean + +# Test with Gradle +# Modify Greetings.java for Gradle +UNIQUE_GRADLE_STRING="gradle" +sed -i'.bak' -e "s/YOUR_PROJECT_ID/${GOOGLE_PROJECT_ID}/g" build.gradle + +gradle clean endpointsOpenApiDocs + +gcloud service-management deploy build/endpointsOpenApiDocs/openapi.json + +# Deploy Gradle +gradle -Pappengine.deploy.promote=false \ + -Pappengine.deploy.version="${GOOGLE_VERSION_ID}" \ + appengineDeploy + +# End-2-End tests +TestEndpoints "${GOOGLE_PROJECT_ID}" "${GOOGLE_VERSION_ID}" "${UNIQUE_GRADLE_STRING}" + +# Clean +gradle clean diff --git a/appengine/endpoints-frameworks-v2/guice-example-hello-greetings/build.gradle b/appengine/endpoints-frameworks-v2/guice-example-hello-greetings/build.gradle new file mode 100644 index 00000000000..694bd569cdc --- /dev/null +++ b/appengine/endpoints-frameworks-v2/guice-example-hello-greetings/build.gradle @@ -0,0 +1,81 @@ +// Copyright 2017 Google Inc. +// +// 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. + +// [START buildscript] +buildscript { // Configuration for building + repositories { + mavenCentral() + jcenter() // Bintray's repository - a fast Maven Central mirror & more + } + dependencies { + // App Engine Gradle plugin + classpath 'com.google.cloud.tools:appengine-gradle-plugin:+' + + // Endpoints Frameworks Gradle plugin + classpath 'com.google.cloud.tools:endpoints-framework-gradle-plugin:+' + } +} +// [END buildscript] + +repositories { // repositories for Jar's you access in your code + mavenCentral() + jcenter() +} + +apply plugin: 'java' // standard Java tasks +apply plugin: 'war' // standard Web Archive plugin + +// [START apply_appengine] +apply plugin: 'com.google.cloud.tools.appengine' // App Engine tasks +// [END apply_appengine] + +// [START apply_endpoints-framework-server] +apply plugin: 'com.google.cloud.tools.endpoints-framework-server' +// [END apply_endpoints-framework-server] + +dependencies { + providedCompile group: 'javax.servlet', name: 'servlet-api', version:'2.5' + compile 'jstl:jstl:1.2' + compile group: 'javax.inject', name: 'javax.inject', version: '1' + compile group: 'com.google.appengine', name: 'appengine-api-1.0-sdk', version: '+' + + // [START endpoints-tools] + compile group: 'com.google.endpoints', name: 'endpoints-framework', version: '+' + compile group: 'com.google.endpoints', name: 'endpoints-framework-guice', version: '+' + // [END endpoints-tools] +} + +appengine { // App Engine tasks configuration + deploy { // deploy configuration + version = findProperty("appengine.deploy.version") + + def promoteProp = findProperty("appengine.deploy.promote") + if (promoteProp != null) { + promote = new Boolean(promoteProp) + } + } +} + +// [START endpoints-server] +endpointsServer { + // Endpoints Framework Plugin server-side configuration + hostname = "YOUR-PROJECT-ID.appspot.com" +} +// [END endpoints-server] + +group = 'com.example.helloendpoints' // Generated output GroupId +version = '1' // Version in generated output + +sourceCompatibility = 1.7 // App Engine Standard uses Java 7 +targetCompatibility = 1.7 // App Engine Standard uses Java 7 diff --git a/appengine/endpoints-frameworks-v2/guice-example-hello-greetings/jenkins.sh b/appengine/endpoints-frameworks-v2/guice-example-hello-greetings/jenkins.sh new file mode 100755 index 00000000000..c7928c1f080 --- /dev/null +++ b/appengine/endpoints-frameworks-v2/guice-example-hello-greetings/jenkins.sh @@ -0,0 +1,83 @@ +#!/usr/bin/env bash + +# Copyright 2017 Google Inc. +# +# 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. + +# Fail on non-zero return and print command to stdout +set -xe + +# Jenkins Test Script +function TestEndpoints () { + # Test getGreeting Endpoint (hello world!) + curl -X GET \ + "https://${2}-dot-${1}.appspot.com/_ah/api/helloworld/v1/hellogreeting/0" | \ + tee "$ERROR_OUTPUT_DIR/response.json" | \ + grep "hello ${3} version-${2}" + + # Test getGreeting Endpoint (goodbye world!) + curl -X GET \ + "https://${2}-dot-${1}.appspot.com/_ah/api/helloworld/v1/hellogreeting/1" | \ + tee "$ERROR_OUTPUT_DIR/response.json" | \ + grep "goodbye world!" + + # Test listGreeting Endpoint (hello world! and goodbye world!) + curl -X GET \ + "https://${2}-dot-${1}.appspot.com/_ah/api/helloworld/v1/hellogreeting" | \ + tee "$ERROR_OUTPUT_DIR/response.json" | \ + grep "hello world!\|goodbye world!" + + # Test multiply Endpoint (This is a greeting.) + curl -X POST \ + -H "Content-Type: application/json" \ + --data "{'message':'This is a greeting from instance ${2}'}." \ + "https://${2}-dot-${1}.appspot.com/_ah/api/helloworld/v1/hellogreeting/1" | \ + tee "$ERROR_OUTPUT_DIR/response.json" | \ + grep "This is a greeting from instance ${2}." +} + +# Jenkins provides values for GOOGLE_PROJECT_ID and GOOGLE_VERSION_ID +# Update Greetings.java +UNIQUE_MAVEN_STRING="maven" +sed -i'.bak' \ + -e "s/hello world!/hello ${UNIQUE_MAVEN_STRING} version-${GOOGLE_VERSION_ID}!/g" \ + src/main/java/com/example/helloendpoints/Greetings.java + +# Test with Maven +mvn clean appengine:deploy \ + -Dapp.deploy.version="${GOOGLE_VERSION_ID}" \ + -Dapp.deploy.promote=false + +# End-2-End tests +TestEndpoints "${GOOGLE_PROJECT_ID}" "${GOOGLE_VERSION_ID}" "${UNIQUE_MAVEN_STRING}" + +# Clean +mvn clean + +# Test with Gradle +# Modify Greetings.java for Gradle +UNIQUE_GRADLE_STRING="gradle" +sed -i'.bak' \ + -e "s/hello ${UNIQUE_MAVEN_STRING} version-${GOOGLE_VERSION_ID}!/hello ${UNIQUE_GRADLE_STRING} version-${GOOGLE_VERSION_ID}!/g" \ + src/main/java/com/example/helloendpoints/Greetings.java + +# Deploy Gradle +gradle -Pappengine.deploy.promote=false \ + -Pappengine.deploy.version="${GOOGLE_VERSION_ID}" \ + appengineDeploy + +# End-2-End tests +TestEndpoints "${GOOGLE_PROJECT_ID}" "${GOOGLE_VERSION_ID}" "${UNIQUE_GRADLE_STRING}" + +# Clean +gradle clean diff --git a/appengine/endpoints-frameworks-v2/guice-example/build.gradle b/appengine/endpoints-frameworks-v2/guice-example/build.gradle index ce3950c474e..e01cd76faba 100644 --- a/appengine/endpoints-frameworks-v2/guice-example/build.gradle +++ b/appengine/endpoints-frameworks-v2/guice-example/build.gradle @@ -56,6 +56,17 @@ endpointsServer { serviceClasses = ['com.example.echo.Echo'] } +appengine { // App Engine tasks configuration + deploy { // deploy configuration + version = findProperty("appengine.deploy.version") + + def promoteProp = findProperty("appengine.deploy.promote") + if (promoteProp != null) { + promote = new Boolean(promoteProp) + } + } +} + sourceCompatibility = 1.7 // App Engine Standard uses Java 7 targetCompatibility = 1.7 // App Engine Standard uses Java 7 diff --git a/appengine/endpoints-frameworks-v2/guice-example/jenkins.sh b/appengine/endpoints-frameworks-v2/guice-example/jenkins.sh new file mode 100755 index 00000000000..2c9b79c6214 --- /dev/null +++ b/appengine/endpoints-frameworks-v2/guice-example/jenkins.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash + +# Copyright 2017 Google Inc. +# +# 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. + +# Fail on non-zero return and print command to stdout +set -xe + +# Jenkins Test Script +function TestEndpoints () { + # Test getGreeting Endpoint (hello world!) + curl -H "Content-Type: application/json" \ + -X POST \ + -d "{'message':'hello ${3} version-${2}'}" \ + "https://${2}-dot-${1}.appspot.com/_ah/api/echo/v1/echo" | \ + tee "$ERROR_OUTPUT_DIR/response.json" | \ + grep "hello ${3} version-${2}" +} + +# Jenkins provides values for GOOGLE_PROJECT_ID and GOOGLE_VERSION_ID +# Update Greetings.java +UNIQUE_MAVEN_STRING="maven" +sed -i'.bak' -e "s/YOUR_PROJECT_ID/${GOOGLE_PROJECT_ID}/g" pom.xml + +mvn clean endpoints-framework:openApiDocs + +gcloud service-management deploy target/openapi-docs/openapi.json + +# Test with Maven +mvn appengine:deploy \ + -Dapp.deploy.version="${GOOGLE_VERSION_ID}" \ + -Dapp.deploy.promote=false + +# End-2-End tests +TestEndpoints "${GOOGLE_PROJECT_ID}" "${GOOGLE_VERSION_ID}" "${UNIQUE_MAVEN_STRING}" + +# Clean +mvn clean + +# Test with Gradle +# Modify Greetings.java for Gradle +UNIQUE_GRADLE_STRING="gradle" +sed -i'.bak' -e "s/YOUR_PROJECT_ID/${GOOGLE_PROJECT_ID}/g" build.gradle + +gradle clean endpointsOpenApiDocs + +gcloud service-management deploy build/endpointsOpenApiDocs/openapi.json + +# Deploy Gradle +gradle -Pappengine.deploy.promote=false \ + -Pappengine.deploy.version="${GOOGLE_VERSION_ID}" \ + appengineDeploy + +# End-2-End tests +TestEndpoints "${GOOGLE_PROJECT_ID}" "${GOOGLE_VERSION_ID}" "${UNIQUE_GRADLE_STRING}" + +# Clean +gradle clean From 2a97e2041d37c6414db9fdef9acae697857e1099 Mon Sep 17 00:00:00 2001 From: Frank Natividad Date: Tue, 5 Sep 2017 16:51:38 -0700 Subject: [PATCH 14/17] 2016 -> 2017 --- .../src/main/java/com/example/echo/Echo.java | 2 +- .../src/main/java/com/example/echo/Email.java | 2 +- .../src/main/java/com/example/echo/Message.java | 2 +- .../src/main/webapp/WEB-INF/appengine-web.xml | 2 +- .../src/main/webapp/WEB-INF/logging.properties | 4 ++-- .../endpoints-v2-guice/src/main/webapp/WEB-INF/web.xml | 2 +- .../guice-example/src/main/java/com/example/echo/Echo.java | 2 +- .../guice-example/src/main/java/com/example/echo/Email.java | 2 +- .../guice-example/src/main/java/com/example/echo/Message.java | 2 +- .../guice-example/src/main/webapp/WEB-INF/appengine-web.xml | 2 +- .../guice-example/src/main/webapp/WEB-INF/logging.properties | 4 ++-- .../guice-example/src/main/webapp/WEB-INF/web.xml | 2 +- 12 files changed, 14 insertions(+), 14 deletions(-) diff --git a/appengine-java8/endpoints-v2-guice/src/main/java/com/example/echo/Echo.java b/appengine-java8/endpoints-v2-guice/src/main/java/com/example/echo/Echo.java index 5804e86dfca..217922887e1 100644 --- a/appengine-java8/endpoints-v2-guice/src/main/java/com/example/echo/Echo.java +++ b/appengine-java8/endpoints-v2-guice/src/main/java/com/example/echo/Echo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 Google Inc. + * Copyright (c) 2017 Google Inc. * * 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 diff --git a/appengine-java8/endpoints-v2-guice/src/main/java/com/example/echo/Email.java b/appengine-java8/endpoints-v2-guice/src/main/java/com/example/echo/Email.java index e7725a9d9cc..2ecd4cf6a45 100644 --- a/appengine-java8/endpoints-v2-guice/src/main/java/com/example/echo/Email.java +++ b/appengine-java8/endpoints-v2-guice/src/main/java/com/example/echo/Email.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 Google Inc. + * Copyright (c) 2017 Google Inc. * * 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 diff --git a/appengine-java8/endpoints-v2-guice/src/main/java/com/example/echo/Message.java b/appengine-java8/endpoints-v2-guice/src/main/java/com/example/echo/Message.java index 64c043c8857..d5ddb79d430 100644 --- a/appengine-java8/endpoints-v2-guice/src/main/java/com/example/echo/Message.java +++ b/appengine-java8/endpoints-v2-guice/src/main/java/com/example/echo/Message.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 Google Inc. + * Copyright (c) 2017 Google Inc. * * 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 diff --git a/appengine-java8/endpoints-v2-guice/src/main/webapp/WEB-INF/appengine-web.xml b/appengine-java8/endpoints-v2-guice/src/main/webapp/WEB-INF/appengine-web.xml index 320f4fa09af..3ac31f198c8 100644 --- a/appengine-java8/endpoints-v2-guice/src/main/webapp/WEB-INF/appengine-web.xml +++ b/appengine-java8/endpoints-v2-guice/src/main/webapp/WEB-INF/appengine-web.xml @@ -1,6 +1,6 @@