From 84042e8b3e0d31dc46f4b344e8231df1001349b8 Mon Sep 17 00:00:00 2001 From: Naman Srivastava Date: Sat, 5 Apr 2025 18:36:11 +0530 Subject: [PATCH 01/16] Services and information --- microservices-self-registration/README.md | 68 +++++ .../contextservice/.gitattributes | 2 + .../contextservice/.gitignore | 33 +++ .../.mvn/wrapper/maven-wrapper.properties | 19 ++ .../contextservice/mvnw | 259 ++++++++++++++++++ .../contextservice/mvnw.cmd | 149 ++++++++++ .../contextservice/pom.xml | 78 ++++++ .../ContextserviceApplication.java | 17 ++ .../contextservice/MyCustomHealthCheck.java | 36 +++ .../client/GreetingServiceClient.java | 11 + .../controller/ContextController.java | 23 ++ .../src/main/resources/application.yml | 25 ++ .../ContextserviceApplicationTests.java | 13 + .../eurekaserver/.gitattributes | 2 + .../eurekaserver/.gitignore | 33 +++ .../.mvn/wrapper/maven-wrapper.properties | 19 ++ .../eurekaserver/mvnw | 259 ++++++++++++++++++ .../eurekaserver/mvnw.cmd | 149 ++++++++++ .../eurekaserver/pom.xml | 66 +++++ .../eurekaserver/EurekaserverApplication.java | 15 + .../src/main/resources/application.yml | 10 + .../EurekaserverApplicationTests.java | 13 + .../greetingservice/.gitattributes | 2 + .../greetingservice/.gitignore | 33 +++ .../.mvn/wrapper/maven-wrapper.properties | 19 ++ .../greetingservice/mvnw | 259 ++++++++++++++++++ .../greetingservice/mvnw.cmd | 149 ++++++++++ .../greetingservice/pom.xml | 73 +++++ .../greetingservice/GreetingsController.java | 13 + .../GreetingserviceApplication.java | 15 + .../greetingservice/MyCustomHealthCheck.java | 36 +++ .../src/main/resources/application.yml | 22 ++ .../GreetingserviceApplicationTests.java | 13 + microservices-self-registration/pom.xml | 42 +++ 34 files changed, 1975 insertions(+) create mode 100644 microservices-self-registration/README.md create mode 100644 microservices-self-registration/contextservice/.gitattributes create mode 100644 microservices-self-registration/contextservice/.gitignore create mode 100644 microservices-self-registration/contextservice/.mvn/wrapper/maven-wrapper.properties create mode 100644 microservices-self-registration/contextservice/mvnw create mode 100644 microservices-self-registration/contextservice/mvnw.cmd create mode 100644 microservices-self-registration/contextservice/pom.xml create mode 100644 microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/ContextserviceApplication.java create mode 100644 microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/MyCustomHealthCheck.java create mode 100644 microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/client/GreetingServiceClient.java create mode 100644 microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/controller/ContextController.java create mode 100644 microservices-self-registration/contextservice/src/main/resources/application.yml create mode 100644 microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/ContextserviceApplicationTests.java create mode 100644 microservices-self-registration/eurekaserver/.gitattributes create mode 100644 microservices-self-registration/eurekaserver/.gitignore create mode 100644 microservices-self-registration/eurekaserver/.mvn/wrapper/maven-wrapper.properties create mode 100644 microservices-self-registration/eurekaserver/mvnw create mode 100644 microservices-self-registration/eurekaserver/mvnw.cmd create mode 100644 microservices-self-registration/eurekaserver/pom.xml create mode 100644 microservices-self-registration/eurekaserver/src/main/java/com/learning/eurekaserver/EurekaserverApplication.java create mode 100644 microservices-self-registration/eurekaserver/src/main/resources/application.yml create mode 100644 microservices-self-registration/eurekaserver/src/test/java/com/learning/eurekaserver/EurekaserverApplicationTests.java create mode 100644 microservices-self-registration/greetingservice/.gitattributes create mode 100644 microservices-self-registration/greetingservice/.gitignore create mode 100644 microservices-self-registration/greetingservice/.mvn/wrapper/maven-wrapper.properties create mode 100644 microservices-self-registration/greetingservice/mvnw create mode 100644 microservices-self-registration/greetingservice/mvnw.cmd create mode 100644 microservices-self-registration/greetingservice/pom.xml create mode 100644 microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/GreetingsController.java create mode 100644 microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/GreetingserviceApplication.java create mode 100644 microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/MyCustomHealthCheck.java create mode 100644 microservices-self-registration/greetingservice/src/main/resources/application.yml create mode 100644 microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/GreetingserviceApplicationTests.java create mode 100644 microservices-self-registration/pom.xml diff --git a/microservices-self-registration/README.md b/microservices-self-registration/README.md new file mode 100644 index 000000000000..bdbab678eb9a --- /dev/null +++ b/microservices-self-registration/README.md @@ -0,0 +1,68 @@ +--- +title: "Microservices Self-Registration Pattern in Java with Spring Boot and Eureka" +shortTitle: Microservices Pattern - Self-Registration +description: "Dynamically register and discover Java microservices using Spring Boot and Eureka for resilient, scalable communication." +category: Service Discovery +language: en +tag: + - Microservices + - Self-Registration + - Service Discovery + - Eureka + - Spring Boot + - Spring Cloud + - Java + - Dynamic Configuration + - Resilience +--- + +## Intent of Microservices Self-Registration Pattern + +The intent of the Self-Registration pattern is to enable microservices to automatically announce their presence and location to a central registry (like Eureka) upon startup, simplifying service discovery and allowing other services to find and communicate with them without manual configuration or hardcoded addresses. This promotes dynamic and resilient microservices architectures. + +## Example + +In this example we have implemented two microservices with utmost simplicity, Greeting Service and Context Service, to provide greeting and contextual information respectively. + +## When to use Microservices Self-Registration Pattern + + - **Dynamic Environments:** When your microservices are frequently deployed, scaled up or down, or their network locations (IP addresses and ports) change often. This is common in cloud-based or containerized environments (like Docker and Kubernetes). + - **Large Number of Services:** As the number of microservices in your system grows, manually managing their configurations and dependencies becomes complex and error-prone. Self-registration automates this process. + - **Need for Automatic Service** Discovery: When services need to find and communicate with each other without hardcoding network locations. This allows for greater flexibility and reduces coupling. + - **Implementing Load Balancing:** Service registries like Eureka often integrate with load balancers, enabling them to automatically distribute traffic across available instances of a service that have registered themselves. + - **Improving System Resilience:** If a service instance fails, the registry will eventually be updated (through heartbeats or health checks), and other services can discover and communicate with the remaining healthy instances. + - **DevOps Automation:** This pattern aligns well with DevOps practices, allowing for more automated deployment and management of microservices. + +## Real-World Applications of Self-Registration pattern + + - E-Commerce platforms have numerous independent services for product catalogs, order processing, payments, shipping, etc. Self-registration allows these services to dynamically discover and communicate with each other as the system scales during peak loads or as new features are deployed. + - Streaming services rely on many microservices for user authentication, content delivery networks (CDNs), recommendation engines, billing systems, etc. Self-registration helps these services adapt to varying user demands and infrastructure changes. + - Social media These platforms use microservices for managing user profiles, timelines, messaging, advertising, and more. Self-registration enables these services to scale independently and handle the massive traffic they experience. + +## Advantages + + - Microservices can dynamically locate and communicate with each other without needing to know their specific network addresses beforehand. This is crucial in dynamic environments where IP addresses and ports can change frequently. + - Reduces the need for manual configuration of service locations in each microservice. Services don't need to be updated every time another service's location changes. + - Scaling microservices up or down becomes easier. New instances automatically register themselves with the service registry, making them immediately discoverable by other services without manual intervention. + - If a service instance fails, it will eventually stop sending heartbeats to the registry and will be removed. Consumers can then discover and connect to other healthy instances, improving the system's overall resilience. + - Services are less tightly coupled as they don't have direct dependencies on the physical locations of other services. This makes deployments and updates more flexible. + - Service registries often integrate with load balancers. When a new service instance registers, the load balancer can automatically include it in the pool of available instances, distributing traffic effectively. + - Microservices can be deployed across different environments (development, testing, production) without significant changes to their discovery mechanism, as long as they are configured to connect to the appropriate service registry for that environment. + +## Trade-offs + + - Introducing a service registry adds another component to your system that needs to be set up, managed, and monitored. This increases the overall complexity of the infrastructure. + - The service registry itself becomes a critical component. If the service registry becomes unavailable, it can disrupt communication between microservices. High availability for the service registry is therefore essential. + - Microservices need to communicate with the service registry for registration, sending heartbeats, and querying for other services. This can lead to increased network traffic. + - There might be a slight delay between when a microservice instance starts and when it becomes fully registered and discoverable in the service registry. This needs to be considered, especially during scaling events. + - You need to consider how your microservices will behave if they fail to register with the service registry upon startup. Robust error handling and retry mechanisms are often necessary. + - Microservices need to include and configure client libraries (like the Eureka Discovery Client) to interact with the service registry. This adds a dependency to your application code. + - In distributed service registries, ensuring consistency of the registry data across all nodes can be a challenge. Different registries might have different consistency models (e.g., eventual consistency). + +## References + + - Microservices Patterns: https://microservices.io/ + - Eureka Documentation: https://github.com/Netflix/eureka | https://spring.io/projects/spring-cloud-netflix + - Spring Boot Documentation: https://spring.io/projects/spring-boot + - Spring Cloud OpenFeignDocumentation: https://spring.io/projects/spring-cloud-openfeign + - Spring Boot Actuator Documentation: https://www.baeldung.com/spring-boot-actuators \ No newline at end of file diff --git a/microservices-self-registration/contextservice/.gitattributes b/microservices-self-registration/contextservice/.gitattributes new file mode 100644 index 000000000000..3b41682ac579 --- /dev/null +++ b/microservices-self-registration/contextservice/.gitattributes @@ -0,0 +1,2 @@ +/mvnw text eol=lf +*.cmd text eol=crlf diff --git a/microservices-self-registration/contextservice/.gitignore b/microservices-self-registration/contextservice/.gitignore new file mode 100644 index 000000000000..549e00a2a96f --- /dev/null +++ b/microservices-self-registration/contextservice/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/microservices-self-registration/contextservice/.mvn/wrapper/maven-wrapper.properties b/microservices-self-registration/contextservice/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 000000000000..d58dfb70bab5 --- /dev/null +++ b/microservices-self-registration/contextservice/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,19 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +wrapperVersion=3.3.2 +distributionType=only-script +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip diff --git a/microservices-self-registration/contextservice/mvnw b/microservices-self-registration/contextservice/mvnw new file mode 100644 index 000000000000..19529ddf8c6e --- /dev/null +++ b/microservices-self-registration/contextservice/mvnw @@ -0,0 +1,259 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Apache Maven Wrapper startup batch script, version 3.3.2 +# +# Optional ENV vars +# ----------------- +# JAVA_HOME - location of a JDK home dir, required when download maven via java source +# MVNW_REPOURL - repo url base for downloading maven distribution +# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output +# ---------------------------------------------------------------------------- + +set -euf +[ "${MVNW_VERBOSE-}" != debug ] || set -x + +# OS specific support. +native_path() { printf %s\\n "$1"; } +case "$(uname)" in +CYGWIN* | MINGW*) + [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" + native_path() { cygpath --path --windows "$1"; } + ;; +esac + +# set JAVACMD and JAVACCMD +set_java_home() { + # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched + 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" + JAVACCMD="$JAVA_HOME/jre/sh/javac" + else + JAVACMD="$JAVA_HOME/bin/java" + JAVACCMD="$JAVA_HOME/bin/javac" + + if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then + echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 + echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 + return 1 + fi + fi + else + JAVACMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v java + )" || : + JAVACCMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v javac + )" || : + + if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then + echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 + return 1 + fi + fi +} + +# hash string like Java String::hashCode +hash_string() { + str="${1:-}" h=0 + while [ -n "$str" ]; do + char="${str%"${str#?}"}" + h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) + str="${str#?}" + done + printf %x\\n $h +} + +verbose() { :; } +[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } + +die() { + printf %s\\n "$1" >&2 + exit 1 +} + +trim() { + # MWRAPPER-139: + # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. + # Needed for removing poorly interpreted newline sequences when running in more + # exotic environments such as mingw bash on Windows. + printf "%s" "${1}" | tr -d '[:space:]' +} + +# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties +while IFS="=" read -r key value; do + case "${key-}" in + distributionUrl) distributionUrl=$(trim "${value-}") ;; + distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; + esac +done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties" +[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties" + +case "${distributionUrl##*/}" in +maven-mvnd-*bin.*) + MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ + case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in + *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; + :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; + :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; + :Linux*x86_64*) distributionPlatform=linux-amd64 ;; + *) + echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 + distributionPlatform=linux-amd64 + ;; + esac + distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" + ;; +maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; +*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; +esac + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" +distributionUrlName="${distributionUrl##*/}" +distributionUrlNameMain="${distributionUrlName%.*}" +distributionUrlNameMain="${distributionUrlNameMain%-bin}" +MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" +MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" + +exec_maven() { + unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : + exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" +} + +if [ -d "$MAVEN_HOME" ]; then + verbose "found existing MAVEN_HOME at $MAVEN_HOME" + exec_maven "$@" +fi + +case "${distributionUrl-}" in +*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; +*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; +esac + +# prepare tmp dir +if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then + clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } + trap clean HUP INT TERM EXIT +else + die "cannot create temp dir" +fi + +mkdir -p -- "${MAVEN_HOME%/*}" + +# Download and Install Apache Maven +verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +verbose "Downloading from: $distributionUrl" +verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +# select .zip or .tar.gz +if ! command -v unzip >/dev/null; then + distributionUrl="${distributionUrl%.zip}.tar.gz" + distributionUrlName="${distributionUrl##*/}" +fi + +# verbose opt +__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' +[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v + +# normalize http auth +case "${MVNW_PASSWORD:+has-password}" in +'') MVNW_USERNAME='' MVNW_PASSWORD='' ;; +has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; +esac + +if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then + verbose "Found wget ... using wget" + wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" +elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then + verbose "Found curl ... using curl" + curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" +elif set_java_home; then + verbose "Falling back to use Java to download" + javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" + targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" + cat >"$javaSource" <<-END + public class Downloader extends java.net.Authenticator + { + protected java.net.PasswordAuthentication getPasswordAuthentication() + { + return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); + } + public static void main( String[] args ) throws Exception + { + setDefault( new Downloader() ); + java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); + } + } + END + # For Cygwin/MinGW, switch paths to Windows format before running javac and java + verbose " - Compiling Downloader.java ..." + "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" + verbose " - Running Downloader.java ..." + "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" +fi + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +if [ -n "${distributionSha256Sum-}" ]; then + distributionSha256Result=false + if [ "$MVN_CMD" = mvnd.sh ]; then + echo "Checksum validation is not supported for maven-mvnd." >&2 + echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + elif command -v sha256sum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then + distributionSha256Result=true + fi + elif command -v shasum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then + distributionSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 + echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + fi + if [ $distributionSha256Result = false ]; then + echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 + echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 + exit 1 + fi +fi + +# unzip and move +if command -v unzip >/dev/null; then + unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" +else + tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" +fi +printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url" +mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" + +clean || : +exec_maven "$@" diff --git a/microservices-self-registration/contextservice/mvnw.cmd b/microservices-self-registration/contextservice/mvnw.cmd new file mode 100644 index 000000000000..249bdf382222 --- /dev/null +++ b/microservices-self-registration/contextservice/mvnw.cmd @@ -0,0 +1,149 @@ +<# : batch portion +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.3.2 +@REM +@REM Optional ENV vars +@REM MVNW_REPOURL - repo url base for downloading maven distribution +@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output +@REM ---------------------------------------------------------------------------- + +@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) +@SET __MVNW_CMD__= +@SET __MVNW_ERROR__= +@SET __MVNW_PSMODULEP_SAVE=%PSModulePath% +@SET PSModulePath= +@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( + IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) +) +@SET PSModulePath=%__MVNW_PSMODULEP_SAVE% +@SET __MVNW_PSMODULEP_SAVE= +@SET __MVNW_ARG0_NAME__= +@SET MVNW_USERNAME= +@SET MVNW_PASSWORD= +@IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*) +@echo Cannot start maven from wrapper >&2 && exit /b 1 +@GOTO :EOF +: end batch / begin powershell #> + +$ErrorActionPreference = "Stop" +if ($env:MVNW_VERBOSE -eq "true") { + $VerbosePreference = "Continue" +} + +# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties +$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl +if (!$distributionUrl) { + Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" +} + +switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { + "maven-mvnd-*" { + $USE_MVND = $true + $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" + $MVN_CMD = "mvnd.cmd" + break + } + default { + $USE_MVND = $false + $MVN_CMD = $script -replace '^mvnw','mvn' + break + } +} + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +if ($env:MVNW_REPOURL) { + $MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" } + $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')" +} +$distributionUrlName = $distributionUrl -replace '^.*/','' +$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' +$MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain" +if ($env:MAVEN_USER_HOME) { + $MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain" +} +$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' +$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" + +if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { + Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" + Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" + exit $? +} + +if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { + Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" +} + +# prepare tmp dir +$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile +$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" +$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null +trap { + if ($TMP_DOWNLOAD_DIR.Exists) { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } + } +} + +New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null + +# Download and Install Apache Maven +Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +Write-Verbose "Downloading from: $distributionUrl" +Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +$webclient = New-Object System.Net.WebClient +if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { + $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) +} +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 +$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum +if ($distributionSha256Sum) { + if ($USE_MVND) { + Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." + } + Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash + if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { + Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." + } +} + +# unzip and move +Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null +Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null +try { + Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null +} catch { + if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { + Write-Error "fail to move MAVEN_HOME" + } +} finally { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } +} + +Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" diff --git a/microservices-self-registration/contextservice/pom.xml b/microservices-self-registration/contextservice/pom.xml new file mode 100644 index 000000000000..ce28170859c9 --- /dev/null +++ b/microservices-self-registration/contextservice/pom.xml @@ -0,0 +1,78 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.4.4 + + + com.learning + contextservice + 0.0.1-SNAPSHOT + contextservice + contextservice + + + + + + + + + + + + + + + 17 + 2024.0.1 + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.cloud + spring-cloud-starter-openfeign + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/ContextserviceApplication.java b/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/ContextserviceApplication.java new file mode 100644 index 000000000000..eb22d094ffce --- /dev/null +++ b/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/ContextserviceApplication.java @@ -0,0 +1,17 @@ +package com.learning.contextservice; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.cloud.openfeign.EnableFeignClients; + +@SpringBootApplication +@EnableDiscoveryClient +@EnableFeignClients +public class ContextserviceApplication { + + public static void main(String[] args) { + SpringApplication.run(ContextserviceApplication.class, args); + } + +} diff --git a/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/MyCustomHealthCheck.java b/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/MyCustomHealthCheck.java new file mode 100644 index 000000000000..83b50458a428 --- /dev/null +++ b/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/MyCustomHealthCheck.java @@ -0,0 +1,36 @@ +package com.learning.contextservice; + +import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.health.HealthIndicator; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +@Component("myCustomHealthCheck") +public class MyCustomHealthCheck implements HealthIndicator { + + private volatile boolean isHealthy = true; + + @Scheduled(fixedRate = 5000) // Run every 5 seconds + public void updateHealthStatus() { + // Perform checks here to determine the current health + // For example, check database connectivity, external service availability, etc. + boolean currentHealth = performHealthCheck(); + isHealthy = currentHealth; + System.out.println("Updated health status: " + isHealthy); // For logging + } + + private boolean performHealthCheck() { + // Replace this with your actual health check logic + // For demonstration, let's toggle the status every few runs + return System.currentTimeMillis() % 10000 < 5000; // Simulate fluctuating health + } + + @Override + public Health health() { + if (isHealthy) { + return Health.up().withDetail("message", "Service is running and scheduled checks are OK").build(); + } else { + return Health.down().withDetail("error", "Scheduled health checks failed").build(); + } + } +} diff --git a/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/client/GreetingServiceClient.java b/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/client/GreetingServiceClient.java new file mode 100644 index 000000000000..a0321da4b627 --- /dev/null +++ b/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/client/GreetingServiceClient.java @@ -0,0 +1,11 @@ +package com.learning.contextservice.client; + +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; + +@FeignClient(name="greetingservice") +public interface GreetingServiceClient { + + @GetMapping("/greeting") + String getGreeting(); +} diff --git a/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/controller/ContextController.java b/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/controller/ContextController.java new file mode 100644 index 000000000000..de84a01b1ea6 --- /dev/null +++ b/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/controller/ContextController.java @@ -0,0 +1,23 @@ +package com.learning.contextservice.controller; + +import com.learning.contextservice.client.GreetingServiceClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class ContextController { + + @Autowired + private GreetingServiceClient greetingServiceClient; + + @Value("${user.region}") + private String userRegion; + + @GetMapping("/context") + public String getContext() { + String greeting = greetingServiceClient.getGreeting(); + return "The Greeting Service says: "+greeting+" from "+userRegion; + } +} diff --git a/microservices-self-registration/contextservice/src/main/resources/application.yml b/microservices-self-registration/contextservice/src/main/resources/application.yml new file mode 100644 index 000000000000..dfef73bbbeec --- /dev/null +++ b/microservices-self-registration/contextservice/src/main/resources/application.yml @@ -0,0 +1,25 @@ +server: + port: 8082 + +spring: + application: + name: contextservice + +eureka: + client: + service-url.defaultZone: http://localhost:8761/eureka + +user: + region: Chennai, Tamil Nadu, India + +management: + endpoint: + health: + show-details: always + web: + exposure: + include: health + +logging: + file: + name: application.log diff --git a/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/ContextserviceApplicationTests.java b/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/ContextserviceApplicationTests.java new file mode 100644 index 000000000000..92acfc686dcb --- /dev/null +++ b/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/ContextserviceApplicationTests.java @@ -0,0 +1,13 @@ +package com.learning.contextservice; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class ContextserviceApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/microservices-self-registration/eurekaserver/.gitattributes b/microservices-self-registration/eurekaserver/.gitattributes new file mode 100644 index 000000000000..3b41682ac579 --- /dev/null +++ b/microservices-self-registration/eurekaserver/.gitattributes @@ -0,0 +1,2 @@ +/mvnw text eol=lf +*.cmd text eol=crlf diff --git a/microservices-self-registration/eurekaserver/.gitignore b/microservices-self-registration/eurekaserver/.gitignore new file mode 100644 index 000000000000..549e00a2a96f --- /dev/null +++ b/microservices-self-registration/eurekaserver/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/microservices-self-registration/eurekaserver/.mvn/wrapper/maven-wrapper.properties b/microservices-self-registration/eurekaserver/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 000000000000..d58dfb70bab5 --- /dev/null +++ b/microservices-self-registration/eurekaserver/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,19 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +wrapperVersion=3.3.2 +distributionType=only-script +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip diff --git a/microservices-self-registration/eurekaserver/mvnw b/microservices-self-registration/eurekaserver/mvnw new file mode 100644 index 000000000000..19529ddf8c6e --- /dev/null +++ b/microservices-self-registration/eurekaserver/mvnw @@ -0,0 +1,259 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Apache Maven Wrapper startup batch script, version 3.3.2 +# +# Optional ENV vars +# ----------------- +# JAVA_HOME - location of a JDK home dir, required when download maven via java source +# MVNW_REPOURL - repo url base for downloading maven distribution +# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output +# ---------------------------------------------------------------------------- + +set -euf +[ "${MVNW_VERBOSE-}" != debug ] || set -x + +# OS specific support. +native_path() { printf %s\\n "$1"; } +case "$(uname)" in +CYGWIN* | MINGW*) + [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" + native_path() { cygpath --path --windows "$1"; } + ;; +esac + +# set JAVACMD and JAVACCMD +set_java_home() { + # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched + 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" + JAVACCMD="$JAVA_HOME/jre/sh/javac" + else + JAVACMD="$JAVA_HOME/bin/java" + JAVACCMD="$JAVA_HOME/bin/javac" + + if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then + echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 + echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 + return 1 + fi + fi + else + JAVACMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v java + )" || : + JAVACCMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v javac + )" || : + + if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then + echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 + return 1 + fi + fi +} + +# hash string like Java String::hashCode +hash_string() { + str="${1:-}" h=0 + while [ -n "$str" ]; do + char="${str%"${str#?}"}" + h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) + str="${str#?}" + done + printf %x\\n $h +} + +verbose() { :; } +[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } + +die() { + printf %s\\n "$1" >&2 + exit 1 +} + +trim() { + # MWRAPPER-139: + # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. + # Needed for removing poorly interpreted newline sequences when running in more + # exotic environments such as mingw bash on Windows. + printf "%s" "${1}" | tr -d '[:space:]' +} + +# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties +while IFS="=" read -r key value; do + case "${key-}" in + distributionUrl) distributionUrl=$(trim "${value-}") ;; + distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; + esac +done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties" +[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties" + +case "${distributionUrl##*/}" in +maven-mvnd-*bin.*) + MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ + case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in + *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; + :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; + :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; + :Linux*x86_64*) distributionPlatform=linux-amd64 ;; + *) + echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 + distributionPlatform=linux-amd64 + ;; + esac + distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" + ;; +maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; +*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; +esac + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" +distributionUrlName="${distributionUrl##*/}" +distributionUrlNameMain="${distributionUrlName%.*}" +distributionUrlNameMain="${distributionUrlNameMain%-bin}" +MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" +MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" + +exec_maven() { + unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : + exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" +} + +if [ -d "$MAVEN_HOME" ]; then + verbose "found existing MAVEN_HOME at $MAVEN_HOME" + exec_maven "$@" +fi + +case "${distributionUrl-}" in +*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; +*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; +esac + +# prepare tmp dir +if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then + clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } + trap clean HUP INT TERM EXIT +else + die "cannot create temp dir" +fi + +mkdir -p -- "${MAVEN_HOME%/*}" + +# Download and Install Apache Maven +verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +verbose "Downloading from: $distributionUrl" +verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +# select .zip or .tar.gz +if ! command -v unzip >/dev/null; then + distributionUrl="${distributionUrl%.zip}.tar.gz" + distributionUrlName="${distributionUrl##*/}" +fi + +# verbose opt +__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' +[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v + +# normalize http auth +case "${MVNW_PASSWORD:+has-password}" in +'') MVNW_USERNAME='' MVNW_PASSWORD='' ;; +has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; +esac + +if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then + verbose "Found wget ... using wget" + wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" +elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then + verbose "Found curl ... using curl" + curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" +elif set_java_home; then + verbose "Falling back to use Java to download" + javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" + targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" + cat >"$javaSource" <<-END + public class Downloader extends java.net.Authenticator + { + protected java.net.PasswordAuthentication getPasswordAuthentication() + { + return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); + } + public static void main( String[] args ) throws Exception + { + setDefault( new Downloader() ); + java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); + } + } + END + # For Cygwin/MinGW, switch paths to Windows format before running javac and java + verbose " - Compiling Downloader.java ..." + "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" + verbose " - Running Downloader.java ..." + "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" +fi + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +if [ -n "${distributionSha256Sum-}" ]; then + distributionSha256Result=false + if [ "$MVN_CMD" = mvnd.sh ]; then + echo "Checksum validation is not supported for maven-mvnd." >&2 + echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + elif command -v sha256sum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then + distributionSha256Result=true + fi + elif command -v shasum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then + distributionSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 + echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + fi + if [ $distributionSha256Result = false ]; then + echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 + echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 + exit 1 + fi +fi + +# unzip and move +if command -v unzip >/dev/null; then + unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" +else + tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" +fi +printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url" +mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" + +clean || : +exec_maven "$@" diff --git a/microservices-self-registration/eurekaserver/mvnw.cmd b/microservices-self-registration/eurekaserver/mvnw.cmd new file mode 100644 index 000000000000..249bdf382222 --- /dev/null +++ b/microservices-self-registration/eurekaserver/mvnw.cmd @@ -0,0 +1,149 @@ +<# : batch portion +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.3.2 +@REM +@REM Optional ENV vars +@REM MVNW_REPOURL - repo url base for downloading maven distribution +@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output +@REM ---------------------------------------------------------------------------- + +@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) +@SET __MVNW_CMD__= +@SET __MVNW_ERROR__= +@SET __MVNW_PSMODULEP_SAVE=%PSModulePath% +@SET PSModulePath= +@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( + IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) +) +@SET PSModulePath=%__MVNW_PSMODULEP_SAVE% +@SET __MVNW_PSMODULEP_SAVE= +@SET __MVNW_ARG0_NAME__= +@SET MVNW_USERNAME= +@SET MVNW_PASSWORD= +@IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*) +@echo Cannot start maven from wrapper >&2 && exit /b 1 +@GOTO :EOF +: end batch / begin powershell #> + +$ErrorActionPreference = "Stop" +if ($env:MVNW_VERBOSE -eq "true") { + $VerbosePreference = "Continue" +} + +# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties +$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl +if (!$distributionUrl) { + Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" +} + +switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { + "maven-mvnd-*" { + $USE_MVND = $true + $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" + $MVN_CMD = "mvnd.cmd" + break + } + default { + $USE_MVND = $false + $MVN_CMD = $script -replace '^mvnw','mvn' + break + } +} + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +if ($env:MVNW_REPOURL) { + $MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" } + $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')" +} +$distributionUrlName = $distributionUrl -replace '^.*/','' +$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' +$MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain" +if ($env:MAVEN_USER_HOME) { + $MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain" +} +$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' +$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" + +if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { + Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" + Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" + exit $? +} + +if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { + Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" +} + +# prepare tmp dir +$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile +$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" +$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null +trap { + if ($TMP_DOWNLOAD_DIR.Exists) { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } + } +} + +New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null + +# Download and Install Apache Maven +Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +Write-Verbose "Downloading from: $distributionUrl" +Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +$webclient = New-Object System.Net.WebClient +if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { + $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) +} +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 +$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum +if ($distributionSha256Sum) { + if ($USE_MVND) { + Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." + } + Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash + if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { + Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." + } +} + +# unzip and move +Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null +Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null +try { + Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null +} catch { + if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { + Write-Error "fail to move MAVEN_HOME" + } +} finally { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } +} + +Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" diff --git a/microservices-self-registration/eurekaserver/pom.xml b/microservices-self-registration/eurekaserver/pom.xml new file mode 100644 index 000000000000..952ca7b28bae --- /dev/null +++ b/microservices-self-registration/eurekaserver/pom.xml @@ -0,0 +1,66 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.4.4 + + + com.learning + eurekaserver + 0.0.1-SNAPSHOT + eurekaserver + eurekaserver + + + + + + + + + + + + + + + 17 + 2024.0.1 + + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-server + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/microservices-self-registration/eurekaserver/src/main/java/com/learning/eurekaserver/EurekaserverApplication.java b/microservices-self-registration/eurekaserver/src/main/java/com/learning/eurekaserver/EurekaserverApplication.java new file mode 100644 index 000000000000..80b3d904ff4c --- /dev/null +++ b/microservices-self-registration/eurekaserver/src/main/java/com/learning/eurekaserver/EurekaserverApplication.java @@ -0,0 +1,15 @@ +package com.learning.eurekaserver; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; + +@SpringBootApplication +@EnableEurekaServer +public class EurekaserverApplication { + + public static void main(String[] args) { + SpringApplication.run(EurekaserverApplication.class, args); + } + +} diff --git a/microservices-self-registration/eurekaserver/src/main/resources/application.yml b/microservices-self-registration/eurekaserver/src/main/resources/application.yml new file mode 100644 index 000000000000..51f8a815d251 --- /dev/null +++ b/microservices-self-registration/eurekaserver/src/main/resources/application.yml @@ -0,0 +1,10 @@ +server: + port: 8761 + +eureka: + client: + register-with-eureka: false + fetch-registry: false + server: + enable-self-preservation: true + diff --git a/microservices-self-registration/eurekaserver/src/test/java/com/learning/eurekaserver/EurekaserverApplicationTests.java b/microservices-self-registration/eurekaserver/src/test/java/com/learning/eurekaserver/EurekaserverApplicationTests.java new file mode 100644 index 000000000000..acb8cc911159 --- /dev/null +++ b/microservices-self-registration/eurekaserver/src/test/java/com/learning/eurekaserver/EurekaserverApplicationTests.java @@ -0,0 +1,13 @@ +package com.learning.eurekaserver; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class EurekaserverApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/microservices-self-registration/greetingservice/.gitattributes b/microservices-self-registration/greetingservice/.gitattributes new file mode 100644 index 000000000000..3b41682ac579 --- /dev/null +++ b/microservices-self-registration/greetingservice/.gitattributes @@ -0,0 +1,2 @@ +/mvnw text eol=lf +*.cmd text eol=crlf diff --git a/microservices-self-registration/greetingservice/.gitignore b/microservices-self-registration/greetingservice/.gitignore new file mode 100644 index 000000000000..549e00a2a96f --- /dev/null +++ b/microservices-self-registration/greetingservice/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/microservices-self-registration/greetingservice/.mvn/wrapper/maven-wrapper.properties b/microservices-self-registration/greetingservice/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 000000000000..d58dfb70bab5 --- /dev/null +++ b/microservices-self-registration/greetingservice/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,19 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +wrapperVersion=3.3.2 +distributionType=only-script +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip diff --git a/microservices-self-registration/greetingservice/mvnw b/microservices-self-registration/greetingservice/mvnw new file mode 100644 index 000000000000..19529ddf8c6e --- /dev/null +++ b/microservices-self-registration/greetingservice/mvnw @@ -0,0 +1,259 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Apache Maven Wrapper startup batch script, version 3.3.2 +# +# Optional ENV vars +# ----------------- +# JAVA_HOME - location of a JDK home dir, required when download maven via java source +# MVNW_REPOURL - repo url base for downloading maven distribution +# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output +# ---------------------------------------------------------------------------- + +set -euf +[ "${MVNW_VERBOSE-}" != debug ] || set -x + +# OS specific support. +native_path() { printf %s\\n "$1"; } +case "$(uname)" in +CYGWIN* | MINGW*) + [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" + native_path() { cygpath --path --windows "$1"; } + ;; +esac + +# set JAVACMD and JAVACCMD +set_java_home() { + # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched + 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" + JAVACCMD="$JAVA_HOME/jre/sh/javac" + else + JAVACMD="$JAVA_HOME/bin/java" + JAVACCMD="$JAVA_HOME/bin/javac" + + if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then + echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 + echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 + return 1 + fi + fi + else + JAVACMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v java + )" || : + JAVACCMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v javac + )" || : + + if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then + echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 + return 1 + fi + fi +} + +# hash string like Java String::hashCode +hash_string() { + str="${1:-}" h=0 + while [ -n "$str" ]; do + char="${str%"${str#?}"}" + h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) + str="${str#?}" + done + printf %x\\n $h +} + +verbose() { :; } +[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } + +die() { + printf %s\\n "$1" >&2 + exit 1 +} + +trim() { + # MWRAPPER-139: + # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. + # Needed for removing poorly interpreted newline sequences when running in more + # exotic environments such as mingw bash on Windows. + printf "%s" "${1}" | tr -d '[:space:]' +} + +# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties +while IFS="=" read -r key value; do + case "${key-}" in + distributionUrl) distributionUrl=$(trim "${value-}") ;; + distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; + esac +done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties" +[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties" + +case "${distributionUrl##*/}" in +maven-mvnd-*bin.*) + MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ + case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in + *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; + :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; + :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; + :Linux*x86_64*) distributionPlatform=linux-amd64 ;; + *) + echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 + distributionPlatform=linux-amd64 + ;; + esac + distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" + ;; +maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; +*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; +esac + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" +distributionUrlName="${distributionUrl##*/}" +distributionUrlNameMain="${distributionUrlName%.*}" +distributionUrlNameMain="${distributionUrlNameMain%-bin}" +MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" +MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" + +exec_maven() { + unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : + exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" +} + +if [ -d "$MAVEN_HOME" ]; then + verbose "found existing MAVEN_HOME at $MAVEN_HOME" + exec_maven "$@" +fi + +case "${distributionUrl-}" in +*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; +*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; +esac + +# prepare tmp dir +if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then + clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } + trap clean HUP INT TERM EXIT +else + die "cannot create temp dir" +fi + +mkdir -p -- "${MAVEN_HOME%/*}" + +# Download and Install Apache Maven +verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +verbose "Downloading from: $distributionUrl" +verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +# select .zip or .tar.gz +if ! command -v unzip >/dev/null; then + distributionUrl="${distributionUrl%.zip}.tar.gz" + distributionUrlName="${distributionUrl##*/}" +fi + +# verbose opt +__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' +[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v + +# normalize http auth +case "${MVNW_PASSWORD:+has-password}" in +'') MVNW_USERNAME='' MVNW_PASSWORD='' ;; +has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; +esac + +if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then + verbose "Found wget ... using wget" + wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" +elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then + verbose "Found curl ... using curl" + curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" +elif set_java_home; then + verbose "Falling back to use Java to download" + javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" + targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" + cat >"$javaSource" <<-END + public class Downloader extends java.net.Authenticator + { + protected java.net.PasswordAuthentication getPasswordAuthentication() + { + return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); + } + public static void main( String[] args ) throws Exception + { + setDefault( new Downloader() ); + java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); + } + } + END + # For Cygwin/MinGW, switch paths to Windows format before running javac and java + verbose " - Compiling Downloader.java ..." + "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" + verbose " - Running Downloader.java ..." + "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" +fi + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +if [ -n "${distributionSha256Sum-}" ]; then + distributionSha256Result=false + if [ "$MVN_CMD" = mvnd.sh ]; then + echo "Checksum validation is not supported for maven-mvnd." >&2 + echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + elif command -v sha256sum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then + distributionSha256Result=true + fi + elif command -v shasum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then + distributionSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 + echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + fi + if [ $distributionSha256Result = false ]; then + echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 + echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 + exit 1 + fi +fi + +# unzip and move +if command -v unzip >/dev/null; then + unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" +else + tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" +fi +printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url" +mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" + +clean || : +exec_maven "$@" diff --git a/microservices-self-registration/greetingservice/mvnw.cmd b/microservices-self-registration/greetingservice/mvnw.cmd new file mode 100644 index 000000000000..249bdf382222 --- /dev/null +++ b/microservices-self-registration/greetingservice/mvnw.cmd @@ -0,0 +1,149 @@ +<# : batch portion +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.3.2 +@REM +@REM Optional ENV vars +@REM MVNW_REPOURL - repo url base for downloading maven distribution +@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output +@REM ---------------------------------------------------------------------------- + +@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) +@SET __MVNW_CMD__= +@SET __MVNW_ERROR__= +@SET __MVNW_PSMODULEP_SAVE=%PSModulePath% +@SET PSModulePath= +@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( + IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) +) +@SET PSModulePath=%__MVNW_PSMODULEP_SAVE% +@SET __MVNW_PSMODULEP_SAVE= +@SET __MVNW_ARG0_NAME__= +@SET MVNW_USERNAME= +@SET MVNW_PASSWORD= +@IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*) +@echo Cannot start maven from wrapper >&2 && exit /b 1 +@GOTO :EOF +: end batch / begin powershell #> + +$ErrorActionPreference = "Stop" +if ($env:MVNW_VERBOSE -eq "true") { + $VerbosePreference = "Continue" +} + +# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties +$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl +if (!$distributionUrl) { + Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" +} + +switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { + "maven-mvnd-*" { + $USE_MVND = $true + $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" + $MVN_CMD = "mvnd.cmd" + break + } + default { + $USE_MVND = $false + $MVN_CMD = $script -replace '^mvnw','mvn' + break + } +} + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +if ($env:MVNW_REPOURL) { + $MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" } + $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')" +} +$distributionUrlName = $distributionUrl -replace '^.*/','' +$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' +$MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain" +if ($env:MAVEN_USER_HOME) { + $MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain" +} +$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' +$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" + +if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { + Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" + Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" + exit $? +} + +if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { + Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" +} + +# prepare tmp dir +$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile +$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" +$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null +trap { + if ($TMP_DOWNLOAD_DIR.Exists) { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } + } +} + +New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null + +# Download and Install Apache Maven +Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +Write-Verbose "Downloading from: $distributionUrl" +Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +$webclient = New-Object System.Net.WebClient +if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { + $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) +} +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 +$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum +if ($distributionSha256Sum) { + if ($USE_MVND) { + Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." + } + Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash + if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { + Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." + } +} + +# unzip and move +Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null +Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null +try { + Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null +} catch { + if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { + Write-Error "fail to move MAVEN_HOME" + } +} finally { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } +} + +Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" diff --git a/microservices-self-registration/greetingservice/pom.xml b/microservices-self-registration/greetingservice/pom.xml new file mode 100644 index 000000000000..32d402d1ab7c --- /dev/null +++ b/microservices-self-registration/greetingservice/pom.xml @@ -0,0 +1,73 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.4.4 + + + com.learning + greetingservice + 0.0.1-SNAPSHOT + greetingservice + greetingservice + + + + + + + + + + + + + + + 17 + 2024.0.1 + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/GreetingsController.java b/microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/GreetingsController.java new file mode 100644 index 000000000000..9c6f31312715 --- /dev/null +++ b/microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/GreetingsController.java @@ -0,0 +1,13 @@ +package com.learning.greetingservice; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class GreetingsController { + + @GetMapping("/greeting") + public String getGreeting(){ + return "Hello"; + } +} diff --git a/microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/GreetingserviceApplication.java b/microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/GreetingserviceApplication.java new file mode 100644 index 000000000000..6868c2624f16 --- /dev/null +++ b/microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/GreetingserviceApplication.java @@ -0,0 +1,15 @@ +package com.learning.greetingservice; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; + +@SpringBootApplication +@EnableDiscoveryClient +public class GreetingserviceApplication { + + public static void main(String[] args) { + SpringApplication.run(GreetingserviceApplication.class, args); + } + +} diff --git a/microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/MyCustomHealthCheck.java b/microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/MyCustomHealthCheck.java new file mode 100644 index 000000000000..754fc0599169 --- /dev/null +++ b/microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/MyCustomHealthCheck.java @@ -0,0 +1,36 @@ +package com.learning.greetingservice; + +import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.health.HealthIndicator; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +@Component("myCustomHealthCheck") +public class MyCustomHealthCheck implements HealthIndicator { + + private volatile boolean isHealthy = true; + + @Scheduled(fixedRate = 5000) // Run every 5 seconds + public void updateHealthStatus() { + // Perform checks here to determine the current health + // For example, check database connectivity, external service availability, etc. + boolean currentHealth = performHealthCheck(); + isHealthy = currentHealth; + System.out.println("Updated health status: " + isHealthy); // For logging + } + + private boolean performHealthCheck() { + // Replace this with your actual health check logic + // For demonstration, let's toggle the status every few runs + return System.currentTimeMillis() % 10000 < 5000; // Simulate fluctuating health + } + + @Override + public Health health() { + if (isHealthy) { + return Health.up().withDetail("message", "Service is running and scheduled checks are OK").build(); + } else { + return Health.down().withDetail("error", "Scheduled health checks failed").build(); + } + } +} diff --git a/microservices-self-registration/greetingservice/src/main/resources/application.yml b/microservices-self-registration/greetingservice/src/main/resources/application.yml new file mode 100644 index 000000000000..adcfac884c2b --- /dev/null +++ b/microservices-self-registration/greetingservice/src/main/resources/application.yml @@ -0,0 +1,22 @@ +server: + port: 8081 + +spring: + application: + name: greetingservice +eureka: + client: + service-url.defaultZone: http://localhost:8761/eureka + +management: + endpoint: + health: + show-details: always + web: + exposure: + include: health + +logging: + file: + name: application.log + diff --git a/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/GreetingserviceApplicationTests.java b/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/GreetingserviceApplicationTests.java new file mode 100644 index 000000000000..586ae35fcb73 --- /dev/null +++ b/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/GreetingserviceApplicationTests.java @@ -0,0 +1,13 @@ +package com.learning.greetingservice; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class GreetingserviceApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/microservices-self-registration/pom.xml b/microservices-self-registration/pom.xml new file mode 100644 index 000000000000..36d1727f4d7e --- /dev/null +++ b/microservices-self-registration/pom.xml @@ -0,0 +1,42 @@ + + + + + java-design-patterns + com.iluwatar + 1.26.0-SNAPSHOT + + 4.0.0 + microservices-aggregrator + pom + + eurekaserver + greetingservice + contextservice + + \ No newline at end of file From 6ad64ff3a9118e042c94077e1e4a32f0e4e39e27 Mon Sep 17 00:00:00 2001 From: Naman Srivastava Date: Sun, 6 Apr 2025 12:17:22 +0530 Subject: [PATCH 02/16] README.md updated --- microservices-self-registration/README.md | 172 +++++++++++++++++++++- 1 file changed, 170 insertions(+), 2 deletions(-) diff --git a/microservices-self-registration/README.md b/microservices-self-registration/README.md index bdbab678eb9a..bfc837817c57 100644 --- a/microservices-self-registration/README.md +++ b/microservices-self-registration/README.md @@ -20,9 +20,177 @@ tag: The intent of the Self-Registration pattern is to enable microservices to automatically announce their presence and location to a central registry (like Eureka) upon startup, simplifying service discovery and allowing other services to find and communicate with them without manual configuration or hardcoded addresses. This promotes dynamic and resilient microservices architectures. -## Example +## What's in the Project -In this example we have implemented two microservices with utmost simplicity, Greeting Service and Context Service, to provide greeting and contextual information respectively. +This project demonstrates the Microservices Self-Registration pattern using Java, Spring Boot (version 3.4.4), and Eureka for service discovery. It consists of three main components: a Eureka Server and two simple microservices, a Greeting Service and a Context Service, which discover and communicate with each other. + +### Project Structure +* **`eureka-server`:** The central service registry where microservices register themselves. +* **`greeting-service`:** A simple microservice that provides a greeting. +* **`context-service`:** A microservice that consumes the greeting from the Greeting Service and adds context. + + The **Eureka Server** acts as the discovery service. Microservices register themselves with the Eureka Server, providing their network location. + + package com.example.eurekaserver; + + import org.springframework.boot.SpringApplication; + import org.springframework.boot.autoconfigure.SpringBootApplication; + import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; + + @SpringBootApplication + @EnableEurekaServer + public class EurekaServerApplication { + + public static void main(String[] args) { + SpringApplication.run(EurekaServerApplication.class, args); + } + } + + The **Greeting Service** is a simple microservice that exposes an endpoint to retrieve a greeting. + + package com.example.greetingservice; + + import org.springframework.boot.SpringApplication; + import org.springframework.boot.autoconfigure.SpringBootApplication; + import org.springframework.cloud.client.discovery.EnableDiscoveryClient; + + @SpringBootApplication + @EnableDiscoveryClient + public class GreetingServiceApplication { + + public static void main(String[] args) { + SpringApplication.run(GreetingServiceApplication.class, args); + } + } + + Greeting Controller + + package com.example.greetingservice.controller; + + import org.springframework.web.bind.annotation.GetMapping; + import org.springframework.web.bind.annotation.RestController; + + @RestController + public class GreetingController { + + @GetMapping("/greeting") + public String getGreeting() { + return "Hello"; + } + } + +The **Context Service** consumes the greeting from the Greeting Service using OpenFeign and adds contextual information. + + package com.example.contextservice; + + import org.springframework.boot.SpringApplication; + import org.springframework.boot.autoconfigure.SpringBootApplication; + import org.springframework.cloud.client.discovery.EnableDiscoveryClient; + import org.springframework.cloud.openfeign.EnableFeignClients; + + @SpringBootApplication + @EnableDiscoveryClient + @EnableFeignClients + public class ContextServiceApplication { + + public static void main(String[] args) { + SpringApplication.run(ContextServiceApplication.class, args); + } + } + + Feign Client : Spring Cloud OpenFeign is a declarative HTTP client that makes it easier to consume RESTful web services in your Spring Cloud applications. Instead of writing the boilerplate code for making HTTP requests, you simply declare interface with annotations that describe the web service you want to consume. + + package com.example.contextservice.client; + + import org.springframework.cloud.openfeign.FeignClient; + import org.springframework.web.bind.annotation.GetMapping; + + @FeignClient(name = "greeting-service") + public interface GreetingServiceClient { + + @GetMapping("/greeting") + String getGreeting(); + } + + Context Controller + + package com.example.contextservice.controller; + + import com.example.contextservice.client.GreetingServiceClient; + import org.springframework.beans.factory.annotation.Autowired; + import org.springframework.beans.factory.annotation.Value; + import org.springframework.web.bind.annotation.GetMapping; + import org.springframework.web.bind.annotation.RestController; + + @RestController + public class ContextController { + + @Autowired + private GreetingServiceClient greetingServiceClient; + + @Value("${user.region}") + private String userRegion; + + @GetMapping("/context") + public String getContext() { + String greeting = greetingServiceClient.getGreeting(); + return "The Greeting Service says: " + greeting + " from " + userRegion + "!"; + } + } + + 1. Both the Greeting Service and the Context Service register themselves with the Eureka Server upon startup using the _@EnableDiscoveryClient_ annotation. + 2. The Context Service, annotated with _@EnableFeignClients_, uses the GreetingServiceClient interface with _@FeignClient(name = "greeting-service")_ to declare its intent to communicate with the service named "greeting-service" in Eureka. + 3. When the /context endpoint of the Context Service is accessed, it calls the _getGreeting()_ method of the GreetingServiceClient. + 4. OpenFeign, leveraging the service discovery information from Eureka, resolves the network location of an available instance of the Greeting Service and makes an HTTP GET request to its /greeting endpoint. + 5. The Greeting Service responds with "Hello", and the Context Service then adds the configured user.region to the response. + + This project utilizes Spring Boot Actuator, which is included as a dependency, to provide health check endpoints for each microservice. These endpoints (e.g., /actuator/health) can be used by Eureka Server to monitor the health of the registered instances. + +## Steps to use for this Project + +Prerequisites: + - Java Development Kit (JDK): Make sure you have a compatible JDK installed (ideally Java 17 or later, as Spring Boot 3.x requires it). + - Maven or Gradle: You'll need either Maven (if you chose Maven during Spring Initializr setup) or Gradle (if you chose Gradle) installed on your system. + - An IDE (Optional but Recommended): IntelliJ IDEA, Eclipse, or Spring Tool Suite (STS) can make it easier to work with the project. + - Web Browser: You'll need a web browser to access the Eureka dashboard and the microservice endpoints. + +Step : + - You'll need to build each microservice individually. Navigate to the root directory of each project in your terminal or command prompt and run the appropriate build command: + _cd eurekaserver + mvn clean install + cd ../greetingservice + mvn clean install + cd ../contextservice + mvn clean install_ +Step : + - Navigate to the root directory of your eurekaserver project in your terminal or command prompt + _mvn spring-boot:run_ + - Wait for the Eureka Server application to start. You should see logs in the console indicating that it has started on port 8761 (as configured). + - Open your web browser and go to http://localhost:8761/. You should see the Eureka Server dashboard. Initially, the list of registered instances will be empty. +Step : + - Run the Greeting Service + - Open a new terminal or command prompt. + - Navigate to the root directory of your greetingservice project. + - Run the Spring Boot application: _mvn spring-boot:run_ + - Wait for the Greeting Service to start. You should see logs indicating that it has registered with the Eureka Server. + - Go back to your Eureka Server dashboard in the browser (http://localhost:8761/). You should now see GREETINGSERVICE listed under the "Instances currently registered with Eureka". Its status should be "UP". +Step : + - Run the Context Service + - Open a new terminal or command prompt. + - Navigate to the root directory of your contextservice project. + - Run the Spring Boot application: _mvn spring-boot:run_ + - Wait for the Context Service to start. You should see logs indicating that it has registered with the Eureka Server. + - Go back to your Eureka Server dashboard in the browser (http://localhost:8761/). You should now see CONTEXTSERVICE listed under the "Instances currently registered with Eureka". Its status should be "UP". +STEP : + - Test the Greeting Service Directly: Open your web browser and go to http://localhost:8081/greeting. You should see the output: Hello. + - Test the Context Service (which calls the Greeting Service): Open your web browser and go to http://localhost:8082/context. You should see the output: The Greeting Service says: Hello from Chennai, Tamil Nadu, India!. This confirms that the Context Service successfully discovered and called the Greeting Service through Eureka. + +Optional: Check Health Endpoints + +You can also verify the health status of each service using Spring Boot Actuator: + - Greeting Service Health: http://localhost:8081/actuator/health (should return {"status":"UP"}) + - Context Service Health: http://localhost:8082/actuator/health (should return {"status":"UP"}) + - Eureka Server Health: http://localhost:8761/actuator/health (should return {"status":"UP"}) ## When to use Microservices Self-Registration Pattern From afc7862fffccc86bb7913ddeb5754a0b3a5a4e4a Mon Sep 17 00:00:00 2001 From: Naman Srivastava Date: Mon, 7 Apr 2025 12:53:35 +0530 Subject: [PATCH 03/16] unit tests added for controllers --- .../application.log.2025-04-05.0.gz | Bin 0 -> 1977 bytes .../contextservice/pom.xml | 6 ++- .../contextservice/ContextControllerTest.java | 41 ++++++++++++++++++ .../application.log.2025-04-05.0.gz | Bin 0 -> 1893 bytes .../greetingservice/pom.xml | 5 +++ .../GreetingControllerTest.java | 24 ++++++++++ 6 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 microservices-self-registration/contextservice/application.log.2025-04-05.0.gz create mode 100644 microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/ContextControllerTest.java create mode 100644 microservices-self-registration/greetingservice/application.log.2025-04-05.0.gz create mode 100644 microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/GreetingControllerTest.java diff --git a/microservices-self-registration/contextservice/application.log.2025-04-05.0.gz b/microservices-self-registration/contextservice/application.log.2025-04-05.0.gz new file mode 100644 index 0000000000000000000000000000000000000000..6ceb03b833a731820dda00c3b027f16241335466 GIT binary patch literal 1977 zcmV;q2S)fGiwFP!00000|IJx#Z`(K${=UHehr!|w>Ea^RlKd6}{g8FiY!=-laGc8> zlHx#1w9Si5>PX6N_SfH#k{sKS?yNN3v>$4lq{L@to_S`-1g)Uswc1{*Gxqy~pg-t@ zq}yu$t<@QXEr9cjkCzbi!Y}~O^WZL$!muw!GqvOq`wVvr%Ef1hNJ1hq+?qU2(}YLV za4BH@ZvfYZD#OJL>Q`sl&i_W26oMA4xS7M%`AGre-O1qoGGzj;Wu_u_|8HF8#Z2>= z@KS0FQ$pV_c%)?UX69y35d>XO0bIcA z@A~tPKLnM|?|eJwUr3;l;Y$Xol2e{A(99gdlqQLF`GiIfU?lhuvnkCIQ!X38PsPYj zRjAt}^ji&4OQK1X$Sfws0-__CGIGWQQ#`u1KMK^pFe*MGZmAxD#~%Ve2wAt=_gH_@ z_ri9Edi`#z?@i;W-;FzdKxwNQWykklfO0}sge@j4j#*5MT%cRY*nQlx$u&N}ltq~j zAy>HJG~s_BfgE*HsSNa6eWdQ(n6xtN2rUR3L!&8;=8WL3xSyctNW}=|mx!r~uk+>G zIaj;`?sBl7|0FD@V#WpA$$twlVFs9+9KhYNdqv^L_kN4`Bs{8v*lU_42obXc^MsVf zle_L&Oj-)iz zUvvc{1<08Q$spMj|+B7mG~rQGt{6#$*UE`%9Uy#xg3VuxvdOlZXa?f$t`~t_;Bt397l7fSprjxY0Q=^k*S@= zP{m--3HlJYInbaOat~*0;$U6Dr=SF0zFOGO$5~|GO#Ue|92cMwS~SleaTaYobZ9Fx zjbl5*^G&6i5$&v>D!O3SLJ}2gO>%V@CYi=Ia5uR5 zZ&yKbSY?Q{)3Rt&S!&?*8h7LSI}QiwB(VyR7-};yWy(C_1h#~ly#b(WbX8(?K82!p ze#9?R#q@j=p2(7<4qfB^d4F_R!;tf+e905KDYH`be?0aLF>SW`sLa+gZ-{2(+`<$J z{su5SQ(;4F;r+ps#AQZhZ|y6b(}mAG|IHAc6~c-quqRPnbBm)C!&J$It5Su6Xx9{0 zVeJyX-L&m#fOR~#&~%FNTnj&XFKAUBw=9^WZzvSyIbzQ6%LJ<>urDmiuxt$wrC=-c z9ujeBs})wKunuIW>B-fp{~Fw8)f};$UQ(@35|xuuoUny$Te399R?!Aut}tVi{ecn( z3+{N?u7ljP(l@IJ`C!@EZXRgS$%Zem!J~^5{9ZfkcX~%*7XjtX3x}!2@;HmWHQsmNWBk_lq7vs}^jIU2ee?K3d=D>^8a^DMP-(0;G z<|eGBD{!aM5=AtpVuq=|v`ent*w77~x{ydAi&6YT67~Y5F>V)Yc!!-YiYcC_Ga+oa?76#5 z{8q2>HnB@O{ryQZ`u!Zn!z+tNFn0`p7yRt`M*;D>ed6OTUwwIokwcQ>v0Igweh2aH zP!0WG-xBRk#`nwk`sZSV6_*U+53QBXZQ)zs=3#y207& zd1hj{62D6M(5Oh?2=#Sk`sDKV;+q@vXIAij>*xrfKUHvR;YJO=xq4Q;o7?-HDfGV8 zyEJtF+qgZL>dJaq&(9Q%?A2zuY%8l4%w0LdtXKrPSViELa#JdE@h3LL{*&3eP+M2a zEBG3Ny8EBnzO%?RsI6#gyG4Tb{(VFq6R-4gqi~(=#^`^=z~XAq`@W)D;De4g4&m;S z>I`UyBxrDD`FdctwYnZ$Z~w~odf>i>!7(chgAD>dyD)f5^PXzD<#SFKIo-AT#~=O+ L2JUbJ&>;W-l4org.springframework.cloud spring-cloud-starter-openfeign - + + org.springframework.boot + spring-boot-starter-test + test + org.springframework.boot spring-boot-starter-test diff --git a/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/ContextControllerTest.java b/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/ContextControllerTest.java new file mode 100644 index 000000000000..75c303ecec75 --- /dev/null +++ b/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/ContextControllerTest.java @@ -0,0 +1,41 @@ +package com.learning.contextservice; + +import com.learning.contextservice.client.GreetingServiceClient; +import com.learning.contextservice.controller.ContextController; +import com.netflix.discovery.converters.Auto; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.cloud.openfeign.FeignAutoConfiguration; +import org.springframework.context.annotation.Import; +import org.springframework.http.MediaType; +import org.springframework.test.context.bean.override.mockito.MockitoBean; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; + +@WebMvcTest(ContextController.class) +public class ContextControllerTest { + + @Autowired + private MockMvc mockMvc; + + @MockitoBean + private GreetingServiceClient greetingServiceClient; + + @Value("${user.region}") + private String userRegion; + + @Test + void shouldReturnContextGreeting() throws Exception{ + Mockito.when(greetingServiceClient.getGreeting()).thenReturn("Mocked Hello"); + + mockMvc.perform(MockMvcRequestBuilders.get("/context") + .accept(MediaType.TEXT_PLAIN)) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().string("The Greeting Service says: Mocked Hello from Chennai, Tamil Nadu, India")); + } +} diff --git a/microservices-self-registration/greetingservice/application.log.2025-04-05.0.gz b/microservices-self-registration/greetingservice/application.log.2025-04-05.0.gz new file mode 100644 index 0000000000000000000000000000000000000000..93d6a2e62ac144ee4c35e079906a0fdd82f04492 GIT binary patch literal 1893 zcmV-r2b%aFiwFP!00000|IJx#Z`(Ey{$8N};V^7yhefPp`5owo%yF{}T^iWVf*~me zTB2<(GO3Z2-R#%zNJ)<4SVfg4P1_H)DN=my?z!iVOv7)qJiqDrtx3@BH@bblNji;~fgsnDso(Gq6#hBq@u9;f#h<$|1CFSBHL?j_|a(wscVVWj9qJ~QW z<-b0R4OMm$d}em0?S$XyibBJOH8%@5J2@(Vyguq*eMp&rvCLG&uKvMkUd%L~3ooU{ zFeUWWl1EAwZ`Ph>$;?x1&b3i)hpQb!t`O9mnX4$FS~CsWf@CpFZ$Qu`6~F~N!L~oY ze9_n&faVhh;8X&Q3|}!wm7MW}foA3aW;98x*QYeP1|uPWn9XRGm~vVlekewM*ay2s zntrD)Y)LeU5}Cy$lESc0hUiG9j2tt;6pzOCM*;g+M#Vb>F4Yb2_-zokLmKtEUb8t3 zywLBoylF(I9&JwJcEH%Q9n<|V+pXH(wJ@h-P1thE;+Vz6$R+xfOx(u>n~re-Qx;}E zgnZ$K(}e$rBy#*sr83aSLoRjTVgHwz#37=t{*1rkRMTipTl% zyQx>a11@v4AHNltp_p^Qc67iZOqc=Y9`@n#(7mGY}vL7V}0K>kOV1t~$kA`w>GlLYq*)Z(>hKO<`rP+_B zf6K#M1tPgj@qLIM1+CZW!BX!-+$P=nHQ z;$f!PHHF_MlQYO?qvWIPj+izRh7hS?qykv8T>`r}9G!j%u+7dtzLzxql_pd~ObzI4 z#*lCqREhU;KF9R!moXk#NrLU!z%@jfQV2D@gIq18GIHdHi-na{v#^UC zm$`NO5*Ozlz;U#9mL)Kg3Ky?fB2)VqFi*gs7xV#e^Gbta7&3ff35TMLtDpp4zFJs; zj@DY|6VLJ}3JoG&HiI|g?6 z4=Skj8SY>m;0h;}!9`WrTDAF+foO98G0lmR5GsW~`8=uIMEIlh{H73Se>z zZ^o=*J)_UI+htT}>zn6||lF=@dh{DFNuehVNIQ zsedS}p%-O0zF_!eij@=CCl+N`!TJbOur>M*$+)tG3ky|PiL&;Y!PS8cy6p-&VmZa6 z+VtalA4+k=mbQt>(il5O8-KaRv{Cj4N*ye@<7Tr8^Ap#Ge6Z|vw~vPCX2X}*@6lxn zL8lpZTb*vVgNX9pa<^B&eo|%v`}#(eDG%>p@H4Oa#gTDTCJx+|;arhij%}s?@n|@- zUCVel`txKk%%K+v=Drv7K0kXj)ODy$*Wk`~C5&i6#T*r2Wv7hY*uV`9-N@x8B5$`N z(mN;*0B_IF4zP%_6_=TQTefU_52$EcoyKSfzqg<7-cRwv7?=Lq`#LahbWJC zlchZ1o?9WZE^`p^jAT((0BP5#GT$9Rz=Q1z&LYK7pZp534ZGc^zFbCfd}cD1f{-*i z9b_{yCD!m7`(ad8JZon{*qGTfc}RNg_TEdn4(W7iP-pbV2}}lOfae>*+!_6K^Jg#U zHAv9zl7IyMSKmls_>k*(CRgQE+N*eXs3HrVz!dF{>pI_-+{ad7N`2%tI>|>yKG?cN zyK}vU+zR$wsf9s53`sYr!Tdb5Tf7}FG84B;2NFEcPG|gTFnbv8^NRU)s^|Oz8@org.springframework.cloud spring-cloud-starter-netflix-eureka-client + + org.springframework.boot + spring-boot-starter-test + test + org.springframework.boot spring-boot-starter-actuator diff --git a/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/GreetingControllerTest.java b/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/GreetingControllerTest.java new file mode 100644 index 000000000000..042d1fe8e67a --- /dev/null +++ b/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/GreetingControllerTest.java @@ -0,0 +1,24 @@ +package com.learning.greetingservice; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; + +@WebMvcTest(GreetingsController.class) +public class GreetingControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Test + void shouldReturnGreeting() throws Exception{ + mockMvc.perform(MockMvcRequestBuilders.get("/greeting") + .accept(MediaType.TEXT_PLAIN)) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().string("Hello")); + } +} From 13bc41f6ac56d9652e81b3e84b1c404f01e50d80 Mon Sep 17 00:00:00 2001 From: Naman Srivastava Date: Wed, 9 Apr 2025 22:14:28 +0530 Subject: [PATCH 04/16] pom.xml, clean up, java version update and slf4j logging added --- .../application.log.2025-04-07.0.gz | Bin 0 -> 27133 bytes .../contextservice/pom.xml | 27 ++++++------------ .../contextservice/MyCustomHealthCheck.java | 17 +++++++---- .../eurekaserver/pom.xml | 16 ++--------- .../application.log.2025-04-07.0.gz | Bin 0 -> 6769 bytes .../greetingservice/pom.xml | 24 ++++++---------- .../greetingservice/MyCustomHealthCheck.java | 10 +++++-- 7 files changed, 38 insertions(+), 56 deletions(-) create mode 100644 microservices-self-registration/contextservice/application.log.2025-04-07.0.gz create mode 100644 microservices-self-registration/greetingservice/application.log.2025-04-07.0.gz diff --git a/microservices-self-registration/contextservice/application.log.2025-04-07.0.gz b/microservices-self-registration/contextservice/application.log.2025-04-07.0.gz new file mode 100644 index 0000000000000000000000000000000000000000..eb2a63ce194e624f9992c81acd0a5778b2eae58c GIT binary patch literal 27133 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 BD#8E& literal 0 HcmV?d00001 diff --git a/microservices-self-registration/contextservice/pom.xml b/microservices-self-registration/contextservice/pom.xml index 4a92e7be6fcd..09990492f191 100644 --- a/microservices-self-registration/contextservice/pom.xml +++ b/microservices-self-registration/contextservice/pom.xml @@ -13,21 +13,9 @@ 0.0.1-SNAPSHOT contextservice contextservice - - - - - - - - - - - - - + - 17 + 21 2024.0.1 @@ -35,6 +23,12 @@ org.springframework.boot spring-boot-starter-web + + org.projectlombok + lombok + 1.18.38 + provided + org.springframework.cloud spring-cloud-starter-netflix-eureka-client @@ -52,11 +46,6 @@ spring-boot-starter-test test - - org.springframework.boot - spring-boot-starter-test - test - diff --git a/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/MyCustomHealthCheck.java b/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/MyCustomHealthCheck.java index 83b50458a428..d62955c775db 100644 --- a/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/MyCustomHealthCheck.java +++ b/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/MyCustomHealthCheck.java @@ -1,5 +1,7 @@ package com.learning.contextservice; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.boot.actuate.health.Health; import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.scheduling.annotation.Scheduled; @@ -8,28 +10,31 @@ @Component("myCustomHealthCheck") public class MyCustomHealthCheck implements HealthIndicator { + private static final Logger log = LoggerFactory.getLogger(MyCustomHealthCheck.class); + private volatile boolean isHealthy = true; @Scheduled(fixedRate = 5000) // Run every 5 seconds public void updateHealthStatus() { // Perform checks here to determine the current health // For example, check database connectivity, external service availability, etc. - boolean currentHealth = performHealthCheck(); - isHealthy = currentHealth; - System.out.println("Updated health status: " + isHealthy); // For logging + isHealthy = performHealthCheck(); + log.info("Update health status : {}", isHealthy); } private boolean performHealthCheck() { - // Replace this with your actual health check logic - // For demonstration, let's toggle the status every few runs - return System.currentTimeMillis() % 10000 < 5000; // Simulate fluctuating health + boolean current = System.currentTimeMillis() % 10000 < 5000; // Simulate fluctuating health + log.debug("Performing health check, current status: {}", current); + return current; // Simulate fluctuating health } @Override public Health health() { if (isHealthy) { + log.info("Health check successful, service is UP"); return Health.up().withDetail("message", "Service is running and scheduled checks are OK").build(); } else { + log.warn("Health check failed, service is DOWN"); return Health.down().withDetail("error", "Scheduled health checks failed").build(); } } diff --git a/microservices-self-registration/eurekaserver/pom.xml b/microservices-self-registration/eurekaserver/pom.xml index 952ca7b28bae..c074569dde58 100644 --- a/microservices-self-registration/eurekaserver/pom.xml +++ b/microservices-self-registration/eurekaserver/pom.xml @@ -13,21 +13,9 @@ 0.0.1-SNAPSHOT eurekaserver eurekaserver - - - - - - - - - - - - - + - 17 + 21 2024.0.1 diff --git a/microservices-self-registration/greetingservice/application.log.2025-04-07.0.gz b/microservices-self-registration/greetingservice/application.log.2025-04-07.0.gz new file mode 100644 index 0000000000000000000000000000000000000000..40c96f70285370fd6948c3cdcce328eff94f1331 GIT binary patch literal 6769 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 literal 0 HcmV?d00001 diff --git a/microservices-self-registration/greetingservice/pom.xml b/microservices-self-registration/greetingservice/pom.xml index 9f88f4012a46..c3390b920676 100644 --- a/microservices-self-registration/greetingservice/pom.xml +++ b/microservices-self-registration/greetingservice/pom.xml @@ -13,21 +13,9 @@ 0.0.1-SNAPSHOT greetingservice greetingservice - - - - - - - - - - - - - + - 17 + 21 2024.0.1 @@ -35,7 +23,13 @@ org.springframework.boot spring-boot-starter-web - + + org.projectlombok + lombok + 1.18.38 + provided + + org.springframework.cloud spring-cloud-starter-netflix-eureka-client diff --git a/microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/MyCustomHealthCheck.java b/microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/MyCustomHealthCheck.java index 754fc0599169..8c87127cba27 100644 --- a/microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/MyCustomHealthCheck.java +++ b/microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/MyCustomHealthCheck.java @@ -1,11 +1,13 @@ package com.learning.greetingservice; +import lombok.extern.slf4j.Slf4j; import org.springframework.boot.actuate.health.Health; import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Component("myCustomHealthCheck") +@Slf4j public class MyCustomHealthCheck implements HealthIndicator { private volatile boolean isHealthy = true; @@ -16,20 +18,24 @@ public void updateHealthStatus() { // For example, check database connectivity, external service availability, etc. boolean currentHealth = performHealthCheck(); isHealthy = currentHealth; - System.out.println("Updated health status: " + isHealthy); // For logging + log.info("Updated health status : {}", isHealthy); } private boolean performHealthCheck() { // Replace this with your actual health check logic // For demonstration, let's toggle the status every few runs - return System.currentTimeMillis() % 10000 < 5000; // Simulate fluctuating health + boolean current = System.currentTimeMillis() % 10000 < 5000; + log.debug("Performing health check, current status: {}", current); + return current; // Simulate fluctuating health } @Override public Health health() { if (isHealthy) { + log.info("Health check successful, service is UP"); return Health.up().withDetail("message", "Service is running and scheduled checks are OK").build(); } else { + log.warn("Health check failed, service is DOWN"); return Health.down().withDetail("error", "Scheduled health checks failed").build(); } } From 20d34ec286de62439fb05dee7931280470a496d5 Mon Sep 17 00:00:00 2001 From: Naman Srivastava Date: Wed, 9 Apr 2025 22:43:31 +0530 Subject: [PATCH 05/16] pom files updated --- .../contextservice/pom.xml | 104 +++++++++--------- .../eurekaserver/pom.xml | 98 +++++++++-------- .../greetingservice/pom.xml | 99 ++++++++--------- .../greetingservice/MyCustomHealthCheck.java | 15 ++- microservices-self-registration/pom.xml | 21 ++++ 5 files changed, 179 insertions(+), 158 deletions(-) diff --git a/microservices-self-registration/contextservice/pom.xml b/microservices-self-registration/contextservice/pom.xml index 09990492f191..ea6d105bd06f 100644 --- a/microservices-self-registration/contextservice/pom.xml +++ b/microservices-self-registration/contextservice/pom.xml @@ -1,71 +1,73 @@ - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 3.4.4 - - - com.learning - contextservice - 0.0.1-SNAPSHOT - contextservice - contextservice + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.4.4 + + com.learning + contextservice + 0.0.1-SNAPSHOT + contextservice + contextservice - - 21 - 2024.0.1 - - - - org.springframework.boot - spring-boot-starter-web - + + 2024.0.1 + + + + org.springframework.boot + spring-boot-starter-web + org.projectlombok lombok 1.18.38 provided - - org.springframework.cloud - spring-cloud-starter-netflix-eureka-client - + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client + org.springframework.boot spring-boot-starter-actuator - - org.springframework.cloud - spring-cloud-starter-openfeign - + + org.springframework.cloud + spring-cloud-starter-openfeign + org.springframework.boot spring-boot-starter-test test - - - - - org.springframework.cloud - spring-cloud-dependencies - ${spring-cloud.version} - pom - import - - - + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + - - - - org.springframework.boot - spring-boot-maven-plugin - - - + + + + org.springframework.boot + spring-boot-maven-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + + + - + \ No newline at end of file diff --git a/microservices-self-registration/eurekaserver/pom.xml b/microservices-self-registration/eurekaserver/pom.xml index c074569dde58..7e5794f651a7 100644 --- a/microservices-self-registration/eurekaserver/pom.xml +++ b/microservices-self-registration/eurekaserver/pom.xml @@ -1,54 +1,56 @@ - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 3.4.4 - - - com.learning - eurekaserver - 0.0.1-SNAPSHOT - eurekaserver - eurekaserver + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.4.4 + + com.learning + eurekaserver + 0.0.1-SNAPSHOT + eurekaserver + eurekaserver - - 21 - 2024.0.1 - - - - org.springframework.cloud - spring-cloud-starter-netflix-eureka-server - + + 2024.0.1 + + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-server + - - org.springframework.boot - spring-boot-starter-test - test - - - - - - org.springframework.cloud - spring-cloud-dependencies - ${spring-cloud.version} - pom - import - - - + + org.springframework.boot + spring-boot-starter-test + test + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + - - - - org.springframework.boot - spring-boot-maven-plugin - - - + + + + org.springframework.boot + spring-boot-maven-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + + + - + \ No newline at end of file diff --git a/microservices-self-registration/greetingservice/pom.xml b/microservices-self-registration/greetingservice/pom.xml index c3390b920676..45988a145866 100644 --- a/microservices-self-registration/greetingservice/pom.xml +++ b/microservices-self-registration/greetingservice/pom.xml @@ -1,28 +1,26 @@ - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 3.4.4 - - - com.learning - greetingservice - 0.0.1-SNAPSHOT - greetingservice - greetingservice + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.4.4 + + com.learning + greetingservice + 0.0.1-SNAPSHOT + greetingservice + greetingservice - - 21 - 2024.0.1 - - - - org.springframework.boot - spring-boot-starter-web - + + 2024.0.1 + + + + org.springframework.boot + spring-boot-starter-web + org.projectlombok lombok @@ -30,9 +28,9 @@ provided - org.springframework.cloud - spring-cloud-starter-netflix-eureka-client - + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client + org.springframework.boot spring-boot-starter-test @@ -42,31 +40,30 @@ org.springframework.boot spring-boot-starter-actuator - - org.springframework.boot - spring-boot-starter-test - test - - - - - - org.springframework.cloud - spring-cloud-dependencies - ${spring-cloud.version} - pom - import - - - + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + - - - - org.springframework.boot - spring-boot-maven-plugin - - - + + + + org.springframework.boot + spring-boot-maven-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + + + - + \ No newline at end of file diff --git a/microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/MyCustomHealthCheck.java b/microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/MyCustomHealthCheck.java index 8c87127cba27..4c5f6ac9daad 100644 --- a/microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/MyCustomHealthCheck.java +++ b/microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/MyCustomHealthCheck.java @@ -1,30 +1,29 @@ package com.learning.greetingservice; -import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.boot.actuate.health.Health; import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Component("myCustomHealthCheck") -@Slf4j public class MyCustomHealthCheck implements HealthIndicator { + private static final Logger log = LoggerFactory.getLogger(MyCustomHealthCheck.class); + private volatile boolean isHealthy = true; @Scheduled(fixedRate = 5000) // Run every 5 seconds public void updateHealthStatus() { // Perform checks here to determine the current health // For example, check database connectivity, external service availability, etc. - boolean currentHealth = performHealthCheck(); - isHealthy = currentHealth; - log.info("Updated health status : {}", isHealthy); + isHealthy = performHealthCheck(); + log.info("Update health status : {}", isHealthy); } private boolean performHealthCheck() { - // Replace this with your actual health check logic - // For demonstration, let's toggle the status every few runs - boolean current = System.currentTimeMillis() % 10000 < 5000; + boolean current = System.currentTimeMillis() % 10000 < 5000; // Simulate fluctuating health log.debug("Performing health check, current status: {}", current); return current; // Simulate fluctuating health } diff --git a/microservices-self-registration/pom.xml b/microservices-self-registration/pom.xml index 36d1727f4d7e..953a75b11549 100644 --- a/microservices-self-registration/pom.xml +++ b/microservices-self-registration/pom.xml @@ -39,4 +39,25 @@ greetingservice contextservice + + + 21 + ${java.version} + ${java.version} + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + ${maven.compiler.source} + ${maven.compiler.target} + + + + + \ No newline at end of file From 2bd955d971294a11970cf02731e7521255f79024 Mon Sep 17 00:00:00 2001 From: Naman Srivastava Date: Fri, 11 Apr 2025 17:54:05 +0530 Subject: [PATCH 06/16] Removed children maven wrappers --- .../.mvn/wrapper/maven-wrapper.properties | 19 -- .../contextservice/mvnw | 259 ------------------ .../contextservice/mvnw.cmd | 149 ---------- .../.mvn/wrapper/maven-wrapper.properties | 19 -- .../eurekaserver/mvnw | 259 ------------------ .../eurekaserver/mvnw.cmd | 149 ---------- .../.mvn/wrapper/maven-wrapper.properties | 19 -- .../greetingservice/mvnw | 259 ------------------ .../greetingservice/mvnw.cmd | 149 ---------- 9 files changed, 1281 deletions(-) delete mode 100644 microservices-self-registration/contextservice/.mvn/wrapper/maven-wrapper.properties delete mode 100644 microservices-self-registration/contextservice/mvnw delete mode 100644 microservices-self-registration/contextservice/mvnw.cmd delete mode 100644 microservices-self-registration/eurekaserver/.mvn/wrapper/maven-wrapper.properties delete mode 100644 microservices-self-registration/eurekaserver/mvnw delete mode 100644 microservices-self-registration/eurekaserver/mvnw.cmd delete mode 100644 microservices-self-registration/greetingservice/.mvn/wrapper/maven-wrapper.properties delete mode 100644 microservices-self-registration/greetingservice/mvnw delete mode 100644 microservices-self-registration/greetingservice/mvnw.cmd diff --git a/microservices-self-registration/contextservice/.mvn/wrapper/maven-wrapper.properties b/microservices-self-registration/contextservice/.mvn/wrapper/maven-wrapper.properties deleted file mode 100644 index d58dfb70bab5..000000000000 --- a/microservices-self-registration/contextservice/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1,19 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you 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. -wrapperVersion=3.3.2 -distributionType=only-script -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip diff --git a/microservices-self-registration/contextservice/mvnw b/microservices-self-registration/contextservice/mvnw deleted file mode 100644 index 19529ddf8c6e..000000000000 --- a/microservices-self-registration/contextservice/mvnw +++ /dev/null @@ -1,259 +0,0 @@ -#!/bin/sh -# ---------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you 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. -# ---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------------- -# Apache Maven Wrapper startup batch script, version 3.3.2 -# -# Optional ENV vars -# ----------------- -# JAVA_HOME - location of a JDK home dir, required when download maven via java source -# MVNW_REPOURL - repo url base for downloading maven distribution -# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven -# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output -# ---------------------------------------------------------------------------- - -set -euf -[ "${MVNW_VERBOSE-}" != debug ] || set -x - -# OS specific support. -native_path() { printf %s\\n "$1"; } -case "$(uname)" in -CYGWIN* | MINGW*) - [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" - native_path() { cygpath --path --windows "$1"; } - ;; -esac - -# set JAVACMD and JAVACCMD -set_java_home() { - # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched - 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" - JAVACCMD="$JAVA_HOME/jre/sh/javac" - else - JAVACMD="$JAVA_HOME/bin/java" - JAVACCMD="$JAVA_HOME/bin/javac" - - if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then - echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 - echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 - return 1 - fi - fi - else - JAVACMD="$( - 'set' +e - 'unset' -f command 2>/dev/null - 'command' -v java - )" || : - JAVACCMD="$( - 'set' +e - 'unset' -f command 2>/dev/null - 'command' -v javac - )" || : - - if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then - echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 - return 1 - fi - fi -} - -# hash string like Java String::hashCode -hash_string() { - str="${1:-}" h=0 - while [ -n "$str" ]; do - char="${str%"${str#?}"}" - h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) - str="${str#?}" - done - printf %x\\n $h -} - -verbose() { :; } -[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } - -die() { - printf %s\\n "$1" >&2 - exit 1 -} - -trim() { - # MWRAPPER-139: - # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. - # Needed for removing poorly interpreted newline sequences when running in more - # exotic environments such as mingw bash on Windows. - printf "%s" "${1}" | tr -d '[:space:]' -} - -# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties -while IFS="=" read -r key value; do - case "${key-}" in - distributionUrl) distributionUrl=$(trim "${value-}") ;; - distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; - esac -done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties" -[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties" - -case "${distributionUrl##*/}" in -maven-mvnd-*bin.*) - MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ - case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in - *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; - :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; - :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; - :Linux*x86_64*) distributionPlatform=linux-amd64 ;; - *) - echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 - distributionPlatform=linux-amd64 - ;; - esac - distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" - ;; -maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; -*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; -esac - -# apply MVNW_REPOURL and calculate MAVEN_HOME -# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ -[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" -distributionUrlName="${distributionUrl##*/}" -distributionUrlNameMain="${distributionUrlName%.*}" -distributionUrlNameMain="${distributionUrlNameMain%-bin}" -MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" -MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" - -exec_maven() { - unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : - exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" -} - -if [ -d "$MAVEN_HOME" ]; then - verbose "found existing MAVEN_HOME at $MAVEN_HOME" - exec_maven "$@" -fi - -case "${distributionUrl-}" in -*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; -*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; -esac - -# prepare tmp dir -if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then - clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } - trap clean HUP INT TERM EXIT -else - die "cannot create temp dir" -fi - -mkdir -p -- "${MAVEN_HOME%/*}" - -# Download and Install Apache Maven -verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." -verbose "Downloading from: $distributionUrl" -verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" - -# select .zip or .tar.gz -if ! command -v unzip >/dev/null; then - distributionUrl="${distributionUrl%.zip}.tar.gz" - distributionUrlName="${distributionUrl##*/}" -fi - -# verbose opt -__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' -[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v - -# normalize http auth -case "${MVNW_PASSWORD:+has-password}" in -'') MVNW_USERNAME='' MVNW_PASSWORD='' ;; -has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; -esac - -if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then - verbose "Found wget ... using wget" - wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" -elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then - verbose "Found curl ... using curl" - curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" -elif set_java_home; then - verbose "Falling back to use Java to download" - javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" - targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" - cat >"$javaSource" <<-END - public class Downloader extends java.net.Authenticator - { - protected java.net.PasswordAuthentication getPasswordAuthentication() - { - return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); - } - public static void main( String[] args ) throws Exception - { - setDefault( new Downloader() ); - java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); - } - } - END - # For Cygwin/MinGW, switch paths to Windows format before running javac and java - verbose " - Compiling Downloader.java ..." - "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" - verbose " - Running Downloader.java ..." - "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" -fi - -# If specified, validate the SHA-256 sum of the Maven distribution zip file -if [ -n "${distributionSha256Sum-}" ]; then - distributionSha256Result=false - if [ "$MVN_CMD" = mvnd.sh ]; then - echo "Checksum validation is not supported for maven-mvnd." >&2 - echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 - exit 1 - elif command -v sha256sum >/dev/null; then - if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then - distributionSha256Result=true - fi - elif command -v shasum >/dev/null; then - if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then - distributionSha256Result=true - fi - else - echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 - echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 - exit 1 - fi - if [ $distributionSha256Result = false ]; then - echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 - echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 - exit 1 - fi -fi - -# unzip and move -if command -v unzip >/dev/null; then - unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" -else - tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" -fi -printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url" -mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" - -clean || : -exec_maven "$@" diff --git a/microservices-self-registration/contextservice/mvnw.cmd b/microservices-self-registration/contextservice/mvnw.cmd deleted file mode 100644 index 249bdf382222..000000000000 --- a/microservices-self-registration/contextservice/mvnw.cmd +++ /dev/null @@ -1,149 +0,0 @@ -<# : batch portion -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM http://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Apache Maven Wrapper startup batch script, version 3.3.2 -@REM -@REM Optional ENV vars -@REM MVNW_REPOURL - repo url base for downloading maven distribution -@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven -@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output -@REM ---------------------------------------------------------------------------- - -@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) -@SET __MVNW_CMD__= -@SET __MVNW_ERROR__= -@SET __MVNW_PSMODULEP_SAVE=%PSModulePath% -@SET PSModulePath= -@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( - IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) -) -@SET PSModulePath=%__MVNW_PSMODULEP_SAVE% -@SET __MVNW_PSMODULEP_SAVE= -@SET __MVNW_ARG0_NAME__= -@SET MVNW_USERNAME= -@SET MVNW_PASSWORD= -@IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*) -@echo Cannot start maven from wrapper >&2 && exit /b 1 -@GOTO :EOF -: end batch / begin powershell #> - -$ErrorActionPreference = "Stop" -if ($env:MVNW_VERBOSE -eq "true") { - $VerbosePreference = "Continue" -} - -# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties -$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl -if (!$distributionUrl) { - Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" -} - -switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { - "maven-mvnd-*" { - $USE_MVND = $true - $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" - $MVN_CMD = "mvnd.cmd" - break - } - default { - $USE_MVND = $false - $MVN_CMD = $script -replace '^mvnw','mvn' - break - } -} - -# apply MVNW_REPOURL and calculate MAVEN_HOME -# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ -if ($env:MVNW_REPOURL) { - $MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" } - $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')" -} -$distributionUrlName = $distributionUrl -replace '^.*/','' -$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' -$MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain" -if ($env:MAVEN_USER_HOME) { - $MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain" -} -$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' -$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" - -if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { - Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" - Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" - exit $? -} - -if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { - Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" -} - -# prepare tmp dir -$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile -$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" -$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null -trap { - if ($TMP_DOWNLOAD_DIR.Exists) { - try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } - catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } - } -} - -New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null - -# Download and Install Apache Maven -Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." -Write-Verbose "Downloading from: $distributionUrl" -Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" - -$webclient = New-Object System.Net.WebClient -if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { - $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) -} -[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null - -# If specified, validate the SHA-256 sum of the Maven distribution zip file -$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum -if ($distributionSha256Sum) { - if ($USE_MVND) { - Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." - } - Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash - if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { - Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." - } -} - -# unzip and move -Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null -Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null -try { - Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null -} catch { - if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { - Write-Error "fail to move MAVEN_HOME" - } -} finally { - try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } - catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } -} - -Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" diff --git a/microservices-self-registration/eurekaserver/.mvn/wrapper/maven-wrapper.properties b/microservices-self-registration/eurekaserver/.mvn/wrapper/maven-wrapper.properties deleted file mode 100644 index d58dfb70bab5..000000000000 --- a/microservices-self-registration/eurekaserver/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1,19 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you 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. -wrapperVersion=3.3.2 -distributionType=only-script -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip diff --git a/microservices-self-registration/eurekaserver/mvnw b/microservices-self-registration/eurekaserver/mvnw deleted file mode 100644 index 19529ddf8c6e..000000000000 --- a/microservices-self-registration/eurekaserver/mvnw +++ /dev/null @@ -1,259 +0,0 @@ -#!/bin/sh -# ---------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you 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. -# ---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------------- -# Apache Maven Wrapper startup batch script, version 3.3.2 -# -# Optional ENV vars -# ----------------- -# JAVA_HOME - location of a JDK home dir, required when download maven via java source -# MVNW_REPOURL - repo url base for downloading maven distribution -# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven -# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output -# ---------------------------------------------------------------------------- - -set -euf -[ "${MVNW_VERBOSE-}" != debug ] || set -x - -# OS specific support. -native_path() { printf %s\\n "$1"; } -case "$(uname)" in -CYGWIN* | MINGW*) - [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" - native_path() { cygpath --path --windows "$1"; } - ;; -esac - -# set JAVACMD and JAVACCMD -set_java_home() { - # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched - 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" - JAVACCMD="$JAVA_HOME/jre/sh/javac" - else - JAVACMD="$JAVA_HOME/bin/java" - JAVACCMD="$JAVA_HOME/bin/javac" - - if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then - echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 - echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 - return 1 - fi - fi - else - JAVACMD="$( - 'set' +e - 'unset' -f command 2>/dev/null - 'command' -v java - )" || : - JAVACCMD="$( - 'set' +e - 'unset' -f command 2>/dev/null - 'command' -v javac - )" || : - - if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then - echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 - return 1 - fi - fi -} - -# hash string like Java String::hashCode -hash_string() { - str="${1:-}" h=0 - while [ -n "$str" ]; do - char="${str%"${str#?}"}" - h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) - str="${str#?}" - done - printf %x\\n $h -} - -verbose() { :; } -[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } - -die() { - printf %s\\n "$1" >&2 - exit 1 -} - -trim() { - # MWRAPPER-139: - # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. - # Needed for removing poorly interpreted newline sequences when running in more - # exotic environments such as mingw bash on Windows. - printf "%s" "${1}" | tr -d '[:space:]' -} - -# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties -while IFS="=" read -r key value; do - case "${key-}" in - distributionUrl) distributionUrl=$(trim "${value-}") ;; - distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; - esac -done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties" -[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties" - -case "${distributionUrl##*/}" in -maven-mvnd-*bin.*) - MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ - case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in - *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; - :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; - :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; - :Linux*x86_64*) distributionPlatform=linux-amd64 ;; - *) - echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 - distributionPlatform=linux-amd64 - ;; - esac - distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" - ;; -maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; -*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; -esac - -# apply MVNW_REPOURL and calculate MAVEN_HOME -# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ -[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" -distributionUrlName="${distributionUrl##*/}" -distributionUrlNameMain="${distributionUrlName%.*}" -distributionUrlNameMain="${distributionUrlNameMain%-bin}" -MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" -MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" - -exec_maven() { - unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : - exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" -} - -if [ -d "$MAVEN_HOME" ]; then - verbose "found existing MAVEN_HOME at $MAVEN_HOME" - exec_maven "$@" -fi - -case "${distributionUrl-}" in -*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; -*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; -esac - -# prepare tmp dir -if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then - clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } - trap clean HUP INT TERM EXIT -else - die "cannot create temp dir" -fi - -mkdir -p -- "${MAVEN_HOME%/*}" - -# Download and Install Apache Maven -verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." -verbose "Downloading from: $distributionUrl" -verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" - -# select .zip or .tar.gz -if ! command -v unzip >/dev/null; then - distributionUrl="${distributionUrl%.zip}.tar.gz" - distributionUrlName="${distributionUrl##*/}" -fi - -# verbose opt -__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' -[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v - -# normalize http auth -case "${MVNW_PASSWORD:+has-password}" in -'') MVNW_USERNAME='' MVNW_PASSWORD='' ;; -has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; -esac - -if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then - verbose "Found wget ... using wget" - wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" -elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then - verbose "Found curl ... using curl" - curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" -elif set_java_home; then - verbose "Falling back to use Java to download" - javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" - targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" - cat >"$javaSource" <<-END - public class Downloader extends java.net.Authenticator - { - protected java.net.PasswordAuthentication getPasswordAuthentication() - { - return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); - } - public static void main( String[] args ) throws Exception - { - setDefault( new Downloader() ); - java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); - } - } - END - # For Cygwin/MinGW, switch paths to Windows format before running javac and java - verbose " - Compiling Downloader.java ..." - "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" - verbose " - Running Downloader.java ..." - "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" -fi - -# If specified, validate the SHA-256 sum of the Maven distribution zip file -if [ -n "${distributionSha256Sum-}" ]; then - distributionSha256Result=false - if [ "$MVN_CMD" = mvnd.sh ]; then - echo "Checksum validation is not supported for maven-mvnd." >&2 - echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 - exit 1 - elif command -v sha256sum >/dev/null; then - if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then - distributionSha256Result=true - fi - elif command -v shasum >/dev/null; then - if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then - distributionSha256Result=true - fi - else - echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 - echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 - exit 1 - fi - if [ $distributionSha256Result = false ]; then - echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 - echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 - exit 1 - fi -fi - -# unzip and move -if command -v unzip >/dev/null; then - unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" -else - tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" -fi -printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url" -mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" - -clean || : -exec_maven "$@" diff --git a/microservices-self-registration/eurekaserver/mvnw.cmd b/microservices-self-registration/eurekaserver/mvnw.cmd deleted file mode 100644 index 249bdf382222..000000000000 --- a/microservices-self-registration/eurekaserver/mvnw.cmd +++ /dev/null @@ -1,149 +0,0 @@ -<# : batch portion -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM http://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Apache Maven Wrapper startup batch script, version 3.3.2 -@REM -@REM Optional ENV vars -@REM MVNW_REPOURL - repo url base for downloading maven distribution -@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven -@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output -@REM ---------------------------------------------------------------------------- - -@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) -@SET __MVNW_CMD__= -@SET __MVNW_ERROR__= -@SET __MVNW_PSMODULEP_SAVE=%PSModulePath% -@SET PSModulePath= -@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( - IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) -) -@SET PSModulePath=%__MVNW_PSMODULEP_SAVE% -@SET __MVNW_PSMODULEP_SAVE= -@SET __MVNW_ARG0_NAME__= -@SET MVNW_USERNAME= -@SET MVNW_PASSWORD= -@IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*) -@echo Cannot start maven from wrapper >&2 && exit /b 1 -@GOTO :EOF -: end batch / begin powershell #> - -$ErrorActionPreference = "Stop" -if ($env:MVNW_VERBOSE -eq "true") { - $VerbosePreference = "Continue" -} - -# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties -$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl -if (!$distributionUrl) { - Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" -} - -switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { - "maven-mvnd-*" { - $USE_MVND = $true - $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" - $MVN_CMD = "mvnd.cmd" - break - } - default { - $USE_MVND = $false - $MVN_CMD = $script -replace '^mvnw','mvn' - break - } -} - -# apply MVNW_REPOURL and calculate MAVEN_HOME -# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ -if ($env:MVNW_REPOURL) { - $MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" } - $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')" -} -$distributionUrlName = $distributionUrl -replace '^.*/','' -$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' -$MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain" -if ($env:MAVEN_USER_HOME) { - $MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain" -} -$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' -$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" - -if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { - Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" - Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" - exit $? -} - -if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { - Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" -} - -# prepare tmp dir -$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile -$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" -$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null -trap { - if ($TMP_DOWNLOAD_DIR.Exists) { - try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } - catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } - } -} - -New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null - -# Download and Install Apache Maven -Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." -Write-Verbose "Downloading from: $distributionUrl" -Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" - -$webclient = New-Object System.Net.WebClient -if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { - $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) -} -[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null - -# If specified, validate the SHA-256 sum of the Maven distribution zip file -$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum -if ($distributionSha256Sum) { - if ($USE_MVND) { - Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." - } - Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash - if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { - Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." - } -} - -# unzip and move -Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null -Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null -try { - Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null -} catch { - if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { - Write-Error "fail to move MAVEN_HOME" - } -} finally { - try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } - catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } -} - -Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" diff --git a/microservices-self-registration/greetingservice/.mvn/wrapper/maven-wrapper.properties b/microservices-self-registration/greetingservice/.mvn/wrapper/maven-wrapper.properties deleted file mode 100644 index d58dfb70bab5..000000000000 --- a/microservices-self-registration/greetingservice/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1,19 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you 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. -wrapperVersion=3.3.2 -distributionType=only-script -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip diff --git a/microservices-self-registration/greetingservice/mvnw b/microservices-self-registration/greetingservice/mvnw deleted file mode 100644 index 19529ddf8c6e..000000000000 --- a/microservices-self-registration/greetingservice/mvnw +++ /dev/null @@ -1,259 +0,0 @@ -#!/bin/sh -# ---------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you 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. -# ---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------------- -# Apache Maven Wrapper startup batch script, version 3.3.2 -# -# Optional ENV vars -# ----------------- -# JAVA_HOME - location of a JDK home dir, required when download maven via java source -# MVNW_REPOURL - repo url base for downloading maven distribution -# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven -# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output -# ---------------------------------------------------------------------------- - -set -euf -[ "${MVNW_VERBOSE-}" != debug ] || set -x - -# OS specific support. -native_path() { printf %s\\n "$1"; } -case "$(uname)" in -CYGWIN* | MINGW*) - [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" - native_path() { cygpath --path --windows "$1"; } - ;; -esac - -# set JAVACMD and JAVACCMD -set_java_home() { - # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched - 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" - JAVACCMD="$JAVA_HOME/jre/sh/javac" - else - JAVACMD="$JAVA_HOME/bin/java" - JAVACCMD="$JAVA_HOME/bin/javac" - - if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then - echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 - echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 - return 1 - fi - fi - else - JAVACMD="$( - 'set' +e - 'unset' -f command 2>/dev/null - 'command' -v java - )" || : - JAVACCMD="$( - 'set' +e - 'unset' -f command 2>/dev/null - 'command' -v javac - )" || : - - if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then - echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 - return 1 - fi - fi -} - -# hash string like Java String::hashCode -hash_string() { - str="${1:-}" h=0 - while [ -n "$str" ]; do - char="${str%"${str#?}"}" - h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) - str="${str#?}" - done - printf %x\\n $h -} - -verbose() { :; } -[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } - -die() { - printf %s\\n "$1" >&2 - exit 1 -} - -trim() { - # MWRAPPER-139: - # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. - # Needed for removing poorly interpreted newline sequences when running in more - # exotic environments such as mingw bash on Windows. - printf "%s" "${1}" | tr -d '[:space:]' -} - -# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties -while IFS="=" read -r key value; do - case "${key-}" in - distributionUrl) distributionUrl=$(trim "${value-}") ;; - distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; - esac -done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties" -[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties" - -case "${distributionUrl##*/}" in -maven-mvnd-*bin.*) - MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ - case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in - *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; - :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; - :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; - :Linux*x86_64*) distributionPlatform=linux-amd64 ;; - *) - echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 - distributionPlatform=linux-amd64 - ;; - esac - distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" - ;; -maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; -*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; -esac - -# apply MVNW_REPOURL and calculate MAVEN_HOME -# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ -[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" -distributionUrlName="${distributionUrl##*/}" -distributionUrlNameMain="${distributionUrlName%.*}" -distributionUrlNameMain="${distributionUrlNameMain%-bin}" -MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" -MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" - -exec_maven() { - unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : - exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" -} - -if [ -d "$MAVEN_HOME" ]; then - verbose "found existing MAVEN_HOME at $MAVEN_HOME" - exec_maven "$@" -fi - -case "${distributionUrl-}" in -*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; -*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; -esac - -# prepare tmp dir -if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then - clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } - trap clean HUP INT TERM EXIT -else - die "cannot create temp dir" -fi - -mkdir -p -- "${MAVEN_HOME%/*}" - -# Download and Install Apache Maven -verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." -verbose "Downloading from: $distributionUrl" -verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" - -# select .zip or .tar.gz -if ! command -v unzip >/dev/null; then - distributionUrl="${distributionUrl%.zip}.tar.gz" - distributionUrlName="${distributionUrl##*/}" -fi - -# verbose opt -__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' -[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v - -# normalize http auth -case "${MVNW_PASSWORD:+has-password}" in -'') MVNW_USERNAME='' MVNW_PASSWORD='' ;; -has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; -esac - -if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then - verbose "Found wget ... using wget" - wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" -elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then - verbose "Found curl ... using curl" - curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" -elif set_java_home; then - verbose "Falling back to use Java to download" - javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" - targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" - cat >"$javaSource" <<-END - public class Downloader extends java.net.Authenticator - { - protected java.net.PasswordAuthentication getPasswordAuthentication() - { - return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); - } - public static void main( String[] args ) throws Exception - { - setDefault( new Downloader() ); - java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); - } - } - END - # For Cygwin/MinGW, switch paths to Windows format before running javac and java - verbose " - Compiling Downloader.java ..." - "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" - verbose " - Running Downloader.java ..." - "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" -fi - -# If specified, validate the SHA-256 sum of the Maven distribution zip file -if [ -n "${distributionSha256Sum-}" ]; then - distributionSha256Result=false - if [ "$MVN_CMD" = mvnd.sh ]; then - echo "Checksum validation is not supported for maven-mvnd." >&2 - echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 - exit 1 - elif command -v sha256sum >/dev/null; then - if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then - distributionSha256Result=true - fi - elif command -v shasum >/dev/null; then - if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then - distributionSha256Result=true - fi - else - echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 - echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 - exit 1 - fi - if [ $distributionSha256Result = false ]; then - echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 - echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 - exit 1 - fi -fi - -# unzip and move -if command -v unzip >/dev/null; then - unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" -else - tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" -fi -printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url" -mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" - -clean || : -exec_maven "$@" diff --git a/microservices-self-registration/greetingservice/mvnw.cmd b/microservices-self-registration/greetingservice/mvnw.cmd deleted file mode 100644 index 249bdf382222..000000000000 --- a/microservices-self-registration/greetingservice/mvnw.cmd +++ /dev/null @@ -1,149 +0,0 @@ -<# : batch portion -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM http://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Apache Maven Wrapper startup batch script, version 3.3.2 -@REM -@REM Optional ENV vars -@REM MVNW_REPOURL - repo url base for downloading maven distribution -@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven -@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output -@REM ---------------------------------------------------------------------------- - -@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) -@SET __MVNW_CMD__= -@SET __MVNW_ERROR__= -@SET __MVNW_PSMODULEP_SAVE=%PSModulePath% -@SET PSModulePath= -@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( - IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) -) -@SET PSModulePath=%__MVNW_PSMODULEP_SAVE% -@SET __MVNW_PSMODULEP_SAVE= -@SET __MVNW_ARG0_NAME__= -@SET MVNW_USERNAME= -@SET MVNW_PASSWORD= -@IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*) -@echo Cannot start maven from wrapper >&2 && exit /b 1 -@GOTO :EOF -: end batch / begin powershell #> - -$ErrorActionPreference = "Stop" -if ($env:MVNW_VERBOSE -eq "true") { - $VerbosePreference = "Continue" -} - -# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties -$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl -if (!$distributionUrl) { - Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" -} - -switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { - "maven-mvnd-*" { - $USE_MVND = $true - $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" - $MVN_CMD = "mvnd.cmd" - break - } - default { - $USE_MVND = $false - $MVN_CMD = $script -replace '^mvnw','mvn' - break - } -} - -# apply MVNW_REPOURL and calculate MAVEN_HOME -# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ -if ($env:MVNW_REPOURL) { - $MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" } - $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')" -} -$distributionUrlName = $distributionUrl -replace '^.*/','' -$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' -$MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain" -if ($env:MAVEN_USER_HOME) { - $MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain" -} -$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' -$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" - -if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { - Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" - Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" - exit $? -} - -if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { - Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" -} - -# prepare tmp dir -$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile -$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" -$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null -trap { - if ($TMP_DOWNLOAD_DIR.Exists) { - try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } - catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } - } -} - -New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null - -# Download and Install Apache Maven -Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." -Write-Verbose "Downloading from: $distributionUrl" -Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" - -$webclient = New-Object System.Net.WebClient -if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { - $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) -} -[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null - -# If specified, validate the SHA-256 sum of the Maven distribution zip file -$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum -if ($distributionSha256Sum) { - if ($USE_MVND) { - Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." - } - Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash - if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { - Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." - } -} - -# unzip and move -Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null -Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null -try { - Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null -} catch { - if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { - Write-Error "fail to move MAVEN_HOME" - } -} finally { - try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } - catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } -} - -Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" From 8b08728c8311c0d1e7ab4357fdbe73c21e3a7873 Mon Sep 17 00:00:00 2001 From: Naman Srivastava Date: Fri, 11 Apr 2025 17:56:47 +0530 Subject: [PATCH 07/16] Microservice-self-registration added to pom file --- .../application.log.2025-04-09.0.gz | Bin 0 -> 37553 bytes .../application.log.2025-04-09.0.gz | Bin 0 -> 18884 bytes microservices-self-registration/pom.xml | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 microservices-self-registration/contextservice/application.log.2025-04-09.0.gz create mode 100644 microservices-self-registration/greetingservice/application.log.2025-04-09.0.gz diff --git a/microservices-self-registration/contextservice/application.log.2025-04-09.0.gz b/microservices-self-registration/contextservice/application.log.2025-04-09.0.gz new file mode 100644 index 0000000000000000000000000000000000000000..bd773dc8ba59d123795a9ea1518f8adf1e9e6e2e GIT binary patch literal 37553 zcmb@uWmsI>mNpvPA!u+2?(XjH?(XjHF2RCRxVyVML4sS*;O_2UWuM*Wbf4~f`@7F` z>&IJjjk$^iHHXc2jsZb5^rydGAE#X}&Z`pN`5$j&2VarW5be@X>U{t1#s&X~ym3 zTWv#0a_kG%9YK&qk&Qq9{_?3v&HnWLEcNaabi4;TO#J8M1{^zN3Kdh+u6ic^^fLE5 z!IISr7xI>Nx5cxpBjF})toP0JKFyj63IhI~kNjJ&fx6ivm!!?&YSegs&>Rn>#iZBj z*JcKq19#K%m1C7IiB2AUI$LWi@RSpZnUBdNK<_2!c$<2?bdAsRyZ&%+-l6Z_4D9~c z!ialj)O|<8g?`GQqTO0DJL%>JLJ=3)Rh4&114~eVN9>2Mp)9Yu%Bj1L(G(YcTgz*& zF@lf${WiCPi+s?9^6I7UHZ@;SeA?K0;x;DSfFg}}S@%NE#~r;F>qbO;syW4g%aK#swNV)ol`!e?5>%m;zy6JE-cC$Xhld@RHfJf?0Ocdxg=87!oZ zoymzzOJV2Sqp%rSVyAq!7hg}Ji+S;6n)3)t6lH`p2nN+I(~l>ybGzSQ+loX_#Ay_2 z23XB^@)K_i@HHu?771(A?D4A1+UF1|O&@!Ci4GP3nG_+zZJ@ygk zvvut95%<{TPA)VH50k$;9j$32{?d3#;sb!g8q!ZCZBA;U2SxK+>#8byC&I%v)!piV zWgMa?4pdk4{5qenJ*bxdcz=4Z2=sv;iBoL5J@oINQ8(x{K9QnnrNJh5V&R*;%Z2S0 zVYcqz%)MH14R+C*T)c^+e=F!%rDI-kb&%O-Hu}FkO}URN-SO>#s1` zkoASl7|QG{*p#B#IxUNPAPnkKOZFtP+RfDadNQaAD(!8s?4!Q0lKIs6VgsssvhoFe zvpbJGl{)T~AxYoPz6MPXJC=%rp*oUa4dr(eay(7_a6x>f{lQXB^k~$It#6QBk7*a# zMkphgANMX`i!*2K#e3OzvOm&G@IjeWPpi(ywEdcgaNbV|UpKBU*;WRGro|yOr~aMbjLQW|S*#2@j1XVWOONQZ zr=a@OXAAgHw+e$(Uf0N{^ls8fXQ(P291{6~$oQIDVEUQudrCd-0{Eh5`PE^Ck8x|Q zI-i6efOy=$p&(cpJ+@}bt`pV8ulT1ojP1W6Ay62K&gHk;6lgBh#0lvpDLoG0VqF`Jk#7Z0OB~jkXjP%(6QS#1ogfe8`}R6IPVTiI1eYHU~f-A2QM~aOaZnyWQVGmlESOxN1MlA)wlY z-U;W>cL=X|mXr&+PJeRK@r0PK`G-G5*JQu#qj#NTzP&n=nC8TY3!j;9l;nIIu&QvA z%1nCQTpiGNT0yKlI(Wjp{-#yN+9_G{`nEUw@l?WGF7A*^eybo)TT@x|mc!~>=(hFI zxHR@`_(1dSzj9HVA%MbEkYV{?C=JR8nZ2Ia>t4dYW-1WZcZAfsCO-;b5e$j?q&%#c zj1Qw?@4%OZve^UgjTF9obM~(PaqZt1)6%+QJ?e2B=pxMIF(Zdo^qkxf$@kjfLtX4W zN=7SLQP&|IL(b$n&?+FL!*Lf@W zWhENEyEQ${@Rt^E2TZB?~kDg|Y3LSp&+R z_rpf_=H$++WD5c{R7Cbwmb-;d&O{!Gocyg!34L+ugU!D*C7w;?^H*CA?SQu1h^J(5 z=cU&n2N`XNAck?;gT6Px6;9Irvi5bfw{gfaDywjRf<;Qdx(lcQK}6vTXc|M;VOPWQ z9Ja%1!q9YVq@&++RakmW`E%q?WF$o&?apsN~&}N{AL;*{RduOz|(= z8CiEaIh(&Ql5!+)_s!viV?n=6M)ASl*++`aZQKm89ICD_tCx?+UUPRmb-%80_Y{!r zQfhm~)w0ojBh~F-9IyakC8hcdHKE`qmr|Ok|9Y6Hu&$F$VygrvS?rCBteTP5r{H%k zQCGr4`h1==NR6tUdgMoV>M3nqg1*E3TKb4P*1X?h;hR&5mCh$?d;OC+MY^AaaPh)p zw6>`;RB0Z&ila!$mZdDj7P;rTwdqADPTfs^K0dpGiD9j1Y>U>Yr+9O-9tw9%2=PwVvU% zsuW|$aGbB)xvxT7<&F!EOI#|3@;-eb;PdrawQ_AKe&j!=EZC}L{Lqv=0kuTa16v5a zauFvQr;)6z{8_JaKEXY5PdJF0Qr6iV?m1=<*?eS}WfL$(6Gm)vkh&%FgF89Dh!hdV z&?7Q-mYQqm7lu(gyy3zm-B&xSHXiy_9cr)JK4*35nbn|Xs2N&5+u#>yFtH&#*L|mWw|)+aV4hk>QT#Z_mn<-!#}q+M`>!``RncR6YG^OWjUddoDk?#n(%FQk3C0Csk#)X&sRgtb}^tvB%`e8X_q>gn730EzLW;&B_0m4QiFw| zxPs{+-i;i!WHDh|pQP(Em;9ANw5N)_Q1z&Nb;=|XE>^g!hD_&Z`Ev=Q_>?U~lY}Q$ z$U5u`^{?4gQa&_uhYj10%Wq?>qbX$O)A|e-7ee{nx4J*MW|IPVjI(?3_GT`VlLyuu z0?hMTqS2v8I(jHu=3$WRTvM#Il=oA8FWRU_zK!uI>5p#Gv(8&bgWgRjW2 zzwv#32KRTsfptKA` zfwJg3&gNp}XshBhEudP0%N#Q>aNJ^o&{)IEc@^_q?zwyV3F+qdbO`fMG;NXsk%Dqu zW_S5X(N5X8OWTnkY)$u?M6k*CU`HuNxExmYT|<4${!5Op@Wiw#j<1}z80b?~M3#5&EZGuC}` zexp{KHK3ST+5;bb5;1RRi-ET6zvjK{ik*$B1$5f7f?W)i_{ZZ5)o$$y>N4#`PSz#c z7L}<2AiMiC5pGB-+^V=KM+=kquG%%(>yHVnu;!UhAU~+o1b2lwh1l&}cEtV(b_(Xx zF)zy@1vu>Oj{k!34#yL(SR8l#g(Xj-Xaizy?S862ka&L$2LbN?sMfFg!H)m_ z8A?U{D3Fl5vQXn{FBxc9nPt|8xOBafm{Lrm?(*%gI{g=+z_K66IV(Ljc0A(_d>f{` zf2UWrK;6=;ib^Ri(m}CNzX*?|Z&&P`9mrjskGD*@J{;6$V|4K;bl*4T;(dG4^68Sg zsgFOgbG}nWkprt7FT$&on$XyHL}}0P$t}JAHHH{nWqumkq4C*V>Zs#OD4KqfQnGy* zdPv1jgFFPGugfJ~vIYmUWFVu5Q=hX4vjNwbS%lLtpjm_&(8FTn5ntj)#K|Lw8Sws= z{x$VC5TSZ}lly!K9{4v{zvrTYa|!+hohIZFg{1IVgt2?ziklojSr8F2T4b&SxF`_? zieN$sY?R6Mz^5$2%g&J-{3&mqi!0#ZeRt|**7FO;bUUh0NfE;`0bAgbXz%gNC3N+t z%dZ1L%%JSiCIKtr0@juoYU0+j2*iM9NmDv>S*W6(j#n2?@3tJSnoO_bq}~(yAZutR ze>%bk%H-rzl+W%}+PsrrM4G>=NBy9P#eBg2y=a7j7SlJ0$A1lOLDc_NsJS8G<4uaY z*(p(z`O1ASGVYGD{7R9u$ZT~|Y?9|2i`A8Axtq=uZ{AechP2tIx!WdxFr%Dta}QgX zkc8GP2|DIWD*zhILnE0Cj$Mq586}>qIm5*L*~0UNlOu1bA2LO{B&rF zh3%G}V_0t6>IvH%rqMtHJ39uOtkROr7@_w}+R88?U)4$f<<*Gomh7z)LX}V6!v^+w z=xEfH)*Vlp<%B81)-igewfc4UD@@T%VjR`+OQXq@Gdk$eQ^yW0`^IFO@$4hos$>_c z=+FxGo`eK}Ax@#QVrawdY}(}N3|Keg?z!yHU@;lKd>*6IVZwrOfjrK0W8Oc3wS@U_ z&dsKOrUb!vW%{46>$~E$gPYR~?okX4M+=c%wib658o+Tqa(MmxJbq``tB(HEnqHW= zy&tA$XDzr(QTi~O@@v3&!}Qx;geU)N?zvH1O=F)?a2L<-PQGYA7zbz0xpy&9gyt)- zqRe_k;!rR7HZP9LigFAT|}bkOCp$ zelSJimn=8O#@!gb5PFozn6UlcLE7FRdpAecw{lroQO3)Alw2A!?A0@St2Ted&~ZCf za`6FytCp)<+}Zj3C>KBD=YF4+k)4FIuYZ??C<4VMcd~Ir6BD4v_I3ehecYCB*0Y1^ zouZKHEAO_$9sh@xoLCg~Ii?t4a#-i3jICqP=&w4~e)ERB@%Hka_&5!Vj7rJoZm`LJ zB=M-4fCmr>Byk%*2UD4|4(*y7X`ISDN%A~V#vEst-;sY;Y3MYBU~0B*|+@(xHC~e!m2;P`|=5p1k(O23oE6X;QbJ}p5N`FTg>X0rT zWj}6nRcOBVO4lvDd4Neg$LZakWQZ#0i3kFBO?4H*<-=5uc*U+UN60ssW>V@ca0P>j zmblCE2p^Nt+b9T3tJ6SKnyj>jJKSBIUKTDm1L8TuCkif#jw+OjW6BE@r^2 zvN`9E%BIoog{8gOk$ruTg3V%=sD$P zfZTP^$Aq@ZIx(3ALeBhiqIs`-vV#c|p0uOhkm3Z&d&(WawDqL3)H79DIXn%#qPb40Sevlk1v^E0w`BARu7EgKO?k$i`=F_VIK zo+N(68QqaJCY3Ub1!(6|6nf`1dYp_VEN{EhZ-c;^r1;BPt8m1wQCIu_fiM(r_y=Jq zn>;g=GRUtwz(sdx9B5NWs{mPBK!AAdxmYUOm?eiOOnS9JYEo|NG_V z9)Wb~old+BI-fCQohU;E^o1Q`<6!CFAVw#3IJ?TgGEU%m`=e zigs|ZUN4^Lu4qd*ef8#KH7BT-tWE>jpcxRTmY*-YK=#KcpVItwk6aqe48PBF>T{pbj+LjqaK(`#fpE$^ ziJOpNZP*loz%PcWQ!YSMy!$4}^Cb#mgDSBd`yrB}=64po$Kp(^*bG!%T|c@_SDBb| zGz4{~=Xp?;k`WY40=i|R-0_;J{Xr6oKgM?xCv;|`*n zbfCB+Z-(ab*ErY)UjFGhSh*5CvIOq4_dOvcvrd;RcN4*(l!aMv#RSCe7ij9?0)B&N zWef~J>f4ya21p*7RPz-MEd!^NQPm~MVpm@+61bzGlQPdIkXc<$2hvfa?%Ub#KiK{7 z;GCO;o3CorRcCyDWNzDVgay0G0Wa&mZRbU#cvThaQui1DaKO54j2veUuIQ8%gKIg z9*cZPkXrKbyc9QfHlzx#vAX!NF+W1m>gh0NH9REtHSE-9Z_Ww9s;=#!8E)JkwQWung@Ug z39&_T+=aL7$^jG<(hwkhf|&8@VxfR8@nBgo4P=3b73#<@^F5N(VMi00W{o9bMuea& zgv%ow2?@GX#Bp)w=0pU8KxT=BPQ6Lfg&+rrkf|H>}NX=B(fTB9 zu8iY-a^HmlHzup$4cD8Fg|TZ+ddrWPnOAk<_2&<{Mz4|1z>87uR;mz=Z@172S}i%7 z13zn)O(}XNM-}KK7x+sj{}V%tFA86kU)?E!Q6^5JymD11$5#6m6h8d}t}J~;s1p$u zM#h3wd+GIi*M_A>pU785RR6ijD*2GD8Rct-1$06hVr_w6tp-nR;!47?YYamaO8^Lr zmK7yyg0{H+C9N6h+2iILzR&f^KK1FHQpP|18-m&tPOkjEC@11Hy3rd+IS{!Am9Qf+ z$A{lK5%cQg&on;xFd|$FXR4}U%sN~=lQUE7qJgY>0dydu*q4+hY-KBZ2^Fd)9 zDx8O+r%Sgl+V=rqIu>BB?%V~RF66E(Y<>_55nxhrgvy{iNNKRY?VWG3sLDzqJKiLu z1dKKLwbAYtHfE;)jya|NCq7kFs;CpM)nVN~Uo+*Obm}zd|4gSc5x~};Ye*p{EECDk zB-@;CZ#17zu9Kd~oUA7r(^MX{JsCU=eha#7VEp3Wf~p^q_gvIKi6(!f7Cit;$LI6> z*t~FTCwt|;rYtsKX#C!gvB*yNe%$ZTPMi>#LZY^4rb*|%pJnX*8AVim($YJv1U|)r zd*DdQ^swK}4{H)U9X>>nN7yl`T6i&oE?B3jK{^7UMK?9h)`E!h`cDE?OUlS1GR;Y~ zHWGO(m;pnf;(&aPc0KCbP0*TVLaXaMVAw-vLRp07M)cQ{Ryo)X_>brv9k2bw#E z%OBQ3;}?ZZYT1)Gc@AHmUapUpAlY(dAmt@N7l}}i3Q^`T{{HmO3uLKC1*s4vq9m06 zQA7?~#1mvFmYD?TYu6AVH5lm+5MMj|4R@mSHNjNY3B|BM^RkBllDO%((x?x}dC>zo zufu>Nl$_9?EV@>FF#Bp^gfdcIF;+}=L_fd#%5E-0x6OG(8?&i$i)?n@{q2QR z9Lpc_P7v8j(8K0G5j@dw#7ubPM201b)No%MI+^9jaYzf3MPU%gI@n?pkfIr-aiSJZ z6-)8yUDGJ12Lr;%CvU}qZm71O$Si2e+0bR#VrjCDnu_3TW&BgFq-4f?dbOWhXuDds z&k1#NrfgyegQHdfUX&`>eka%_+U-7*vc^~n>aqj>po$d3q)*M7F4RH3O;&Av7!(fs z!Je6g37?wrvd?icsuNbPO$xR%l&xAwC{cU0%xFxq=ik}ElF(J%CBfzf+B>KX@Qjx0 zYIo>Msc&w(HrSag@XI*b>jA7D)$3q|%tg$mg=<`HrNsXU_EP54)Neq-NS({8=wC4I zU3B8rt^Qotss21!Tsx+_l+$*!9}ni};Qrv@bn8H2+Bx{~oSNt^uKxbO&d1E{W9aUZ zrseB#kyY2@$6u^=|9eofZ0sbz8dmrD2(hA*&97$vUSVlz+D_8fZ#0Ek{ZY6h)^Q(m z@0dRCDYc@O4K)B4t78@P-nOJtk+3IA=tSW3h6cn)13;pVc;>}Tj&HbSr!i@n))DQ> z^h^OqC+&A4y15-T8`6T*<$fL8G<`pdnYJQ-gb9K2m-b3(=uAiMP z^Njm2O@mM*aTx>^C3O%k`}fd9t?zeHXHW7xE{pEKG7u7e4aSEq1}5W5sL8Qrz^}lE zYAB}%_`}uPLu-~zR6YW}9s33tM7&7@+2I{js_r}TJl@Ad4>~lsPE}#<&j%cL=V+N1 z7P4f|U@&Q$C=${q()%k@DI09*J5*gEu1zh*}Iw+}I1Y`Mv6^UB=UI4mytHiP9V3AS%XKC{G84;`dk9@yu&A?KWj*}?yW zIgazCgdRoc#d$^&W-44A}yu>ei z#OA5uu&j8xH=VOK>aj_ldh6ozpu@_AOXVg=3yrBf37xguiL2IE%(a z)q;aQi}PY?YTmwfxT>P&nn6|!i69a|`J~r2Bo>=BU?Gf*fLcZ8Cr5$UM`}M-_LpOQFDo{@t#KspV$``N8kjzCgcO|gb z&rKM-ch)eaS>QT~M{on{4UJBWd{2ycJKhrB9?uC2Xu|^owGAw>F zgi5+#fsw-iD0HrM@Z>c2TM{5WY`JmSS&&?@&iHcRhyA1sQ>;?LqgupvOo&0#6a zWHEY0_hK)vqRuxQ?$9fWC~)X3(g^0 zhM=Y)ELlEun`T7ma+yaloe74Zd;7Yk41rAlNn8HX5TP|igb?EMzsG+mlZq**sbSqL z@R6ti60Qi~WD0ipDu*u0?}lU}iMVQ>MVw|%gEF!7jB7es*D8I_z2IXWr`vVjQUg(c z6vg8d1HS`IcR}pAZrx)yzmqLs{|$(_U>zc!wx51EDeB<}T>1fV8sv$h27$1BjG|^5 zuWNM#c;T)%L{W3-bxEUx#4u*P5{g~W$u>Z`UBn^BKF7XYa5FYUiUbjA)S`)lIR){#RjuSFDWQ9MRb?}4S?l*Goq9pe1>Bs&{>4;M*p z)XM#tMp$~&x$c&9ZZwsl(vn*oZ%pmrVXXXyoLl>Dx?0UfM`AKGC=Zi=$#Yr+u=2;j zo>{6g`K_|;#gD*KxVx}Yn#V_(3>aCfv=sh=u2Qs!5wb?pDwxI&U8HCf%VUN8cM&ft z@YYIJSZ73hs`;gCA9`bmO1`xfI0gy4NpqA$VLk(=A7Pwcxv2B!;=dq6grglVcNOFh2zq(CaC5L_;QzVd z_g*WW$*|pKqnIK5RWYVmIU7z2eEp`t_|^^VoPHbnrKc+at=H60ehab(4;Qxd@;%B! zl-CbR;o;h6jYp_R;W#$23CU?2?wvojZX5HLt>-qORTWv#ids`@NzZ6SEh;sp)s#E$J4U zsODb8O(|&tZJx(`z;#&G8Qdpg`%>2y@l(`>&d3=VpbfV5&vEphX|;3#O^wPh;74Ho zU)ENHcY)%6T-&WW?rBwD2EOKs3LVfr$mvdfAi5Z&f{!5(YSRTefkAK31Cfg`N1zQv zL_J*~-OXG@JnE^Kn~bN10TB}hPZudW^aMmqNWMeCnB>;1RircNH_^}A7!S%d`@%%< zFt@&GI?NS_F52l;&@S3p3ITh#+vdL^8t790o|s@gPL`_NhLOL3y^P%gJ-Ut5rQ>n`XB}}jmR6kvb=%aXTl2%`{ zKdX}&k7`^6w4qKR3ds<++I)<0b2Raqx*n$g@wml$rn$|5PDAYHmz99ik&1it^ z<9>auIG6Qx1{IxGamh8GoNDF0qW-NUr?PAG93&zG6HZnS5OgFmXSH9+ z#GVZk|M37UKtGV~Zm{NS1~d`DW*MM^_}nQEL>B?zV~8WF=>nNfpp;p;8p+o{<(^*%r&5{mFdpS%CKS z|KRxlvx;Eb#f-`1(o`yTjFk6g26Kl#uK+I6TAw+cE3C6hC;jS8YgSPCVNV(Y%=6((I&K*oYjTLm6I7$j+9!7<7i77 z`y|^+YMtm?Sg?MxTwHRCLt4y?_+5lbal`j;a^$?DI6KApSGr(x<2=X){Ch-LbN-|Y zpc(SObYWi02$(LEy#UjNe-8v=pIw3J!ast--%6khOc(6xuw8(W0JXRMuY5u5H?o-% zkKzOnfr-K$)i&}SNu*b~Vm6fq0Z@bfEVR6(#y=K)z2De9x1wvqu_3EF5g1i07PB4y zS9ej;^MV*zw~B-P0Ak!y;6E_>%x-Y%cI)IJi9856I=)2V*p%=GMu`oD5-1mLfflfT zLNFO}tR2*$TfiTP*8>KD*qCDRKR0-A+Cg#Ftv)o0B?CVw5Ilbq^{&_Ecm#|92%=L% z3XRB9Tq};!Y2Q$`t$25nz8Y)zM%)F5u#3;3hqc=`KOO%`PsnIwSOOv;r=i2eI9U4g zkP%}XEJB2dak01lU8M6*w=(*Jg7@pGvJmaRBW!0++bivNB zEtUj2h6Pb5$mP_4QNl;Q301y68YW5J-G-Fc2pAsT4+w@?5~D2_32yb(KuuQ;u08>+ zpe5iQ_&q!BOd+$!0z*QM?{%9G0A`%ev6x-S8kkQ4O3nws$Nt@pfuWxDbL@W#`@q$1 zf=NmQ?jCY|WNPhzy9eM8^9V`Dl}B?1B4eU)SCoecuVj9tgUOH$T~eN* zZsw)@Upz&*=U81!Q+s}9y~s}{aZUW1wmO(}1@m&D;U*ERV95J(T&66uHPPNvtL|bJ zoHr#AmHzbTF3I z4s3@Nyj46e_L#X$Y!mD^ss`zY5T`|TbK%|y zGP!HqoqM-FxBHgE*?%0>d`;Kg@YwYjju*i16ZkKcUyAG`6zv+_Gh%Pu)pz2-eDUvE z$YlBKjo~$0A%sXN9oL&aUC+KB?`&VrHMFi#e9u)mErFdfX^nv$0iefF*xlfA9kt6| zvwE%35RS!3z21rvSE7`vPi7i61bKv7#$!Ir5MBc%y&AuPwKjeCWE5N~@~wdVvBdn< zy}M)|53a8RMPlaz`wr*`;d*`?RBOV&h1o(eLjj^p7y}Y#lBLw;#B6QB=BVtYHbwY; zOaPM80u;b_8Prjom)F<*y3t~`9L{r_L=a0f`FTHj$vQr4GvrPNns6#58&wWdG5Q^$ zoO(S+hiy+AI`dS$r`xxlZ&1QBtW6b&k0AbcS9m3bZ|A4ncO1%g8XSceXoJ&?k@oA{ zSw+YS1ZW>G{TW`>rE3?DgW0az+S3mv^4(yn4(N{5EOo*?E&#(zYkid1>5=UrDlG8%1v~D_2$T z`Xpj4$k3R?859LV)7wanp|*P$8N2fM!Ds9vx1j0ihL|=FGd73^wpxXU-FM___!+o% z4Bgk#)0u585Lwn4np260>-jOqQAcCH58*M&Mj7ppkI}wNu{(|I5HUVw@CHSKmUI~o zEXcGjDf|HR-^Z}s1^&W!miy&EB%OXa8zPp+Ir53kOC)q}FD=X*7KFQP_pgG2MccMI z3?;fO@A0oV6*;p|tBFF(p0fG2Zu z?={vhPwvs_s7uijpsGxIBGA#ABRB;;tgP8knX>B$`_;y56D+y9nh$YXSQ1PAo%a_9S`WjICc_->hj&q( zIwan$CH1}3)m3Uy+!kst0}@>DxzUW<{GZ`li*WxpeMlL4S3^THeoCb+#I#=m7Y1~* zi#$KQPaQ>mo;E=`jTFKgPdD~0qzm3q@=Vt=lW84TIse`r7RZzwpl7K^t#&yE<>)^~ zC+f1$>j|n)`E|>10TIu`c_{O7{=-TA64wq=V8vyU-;h_z=QacXN0{X-JBB^WLXXC& z*sC&YWw5292qx+ZsOcx}%dN+3bA%NUCA4kwFpyNFV^!>7>?adW{#RMR?4Mc!SEcAm z$uYc4KYkzXl7&Mt&v??l``Xo>at{FZV_8hc(lQ_fsIM7nATrQ>}cA; z7tCppZ!MZ;8sfedx^3^q;0BS5?(~p>g%OI~^SNX0gb>QP;Vp(sp@Sn>6PI!UK;yX- zT)X%-B$wg9X}^CFNXH}UWD_}JPWt>q@NNLn6MUnO#3xrA4Og;@2HU$HN7S>V_giZ9 zO)O1mZauJi7H2lWoxrfp;}*)scC6pX*-0CjilW*+q#!(x1gED1G@4jC1VxJ|3=Gfi zvy9hT610Gki#no?K)uFhYIj328@BF+In%ROvZ#}9zBGi{SIlpI{95x!={_LZpP#JONS!e48TDc{({%Q_51L>}6GwxniSx;$RDqV$-zWNODG?VoJWz^1tE>>h%+@|cwK!!?XR_t5 zN|lQt94<-MZ0t`uVhv!O+_kEE%~$)sm9FXO3<(`IzW85Qpz1D!8LKKcoo_@j8-Pr> zwz_)fbzl5pzKzjUHjs04fB0^cw##aYi5DK7r|NZ~&-o%N-;ufmuzWFZU#Ss?_%`bv z4EgB+e3ZN9)OhDUL*RpsePu_P*8S*AQgTuj?2I+g&vHT!HKO|3OV*p2!WM>`$;jSi zabbS6l%-7;>h$V8>B}!b$P&&8wgO$~QsSANGsNO-D$~r~tW;oe!JUY|6kHXQP?cjn zS&`}N{v=I$Mf{=bQNv-HLKkuut4oKf?RqlN9f$26ddCz-DLI#x*B$P6B2P2 zenwDNkP^t8cza#;$Azr-&+UP%MijD~!rZC(xt__Q>l)eZgn1nj_6*89-vuKU7p#dz zcIZdZC#5F$4dI@OEEnVW?6Hj?DfcE=O(2Ue>$v>in5fv`|=7Dz1{zwmq zD#JQGmzG0s?k%a?lRf&9<&ERjM2`h|+STDCv&X+Anz-DQwcN%@(Ge%f#UF;VOxjkI z$l88HuAz1WNnrX-_-%zlWlphpfL9`Mv%noJcxvLxA{WUUkLg5~yKAd;6H8vEi-3NnWuyxi-;ZwWjJ>vWfeG=*vN|)W7#B7pE||n5lqS|Mt*oed$~0e;s{Kxg{mKWmt+a%C%`(0j4EQX#r%=qx4<2_*an)plCgWi z4W+8YAd@D~&iQyrJiv=^Jsw`Kuqb&hJej7+KZx;*3w^G4#Tcg=#xa4=}m$~*GzTQ!D+o>yT$>t=kDb%H$BIM z7oq>&5Ets}414tBEvrpmbU&x~zqY@99i%QQxtVEyd&Rf&8#)(!a+M2vT3y%||H#b< z^DkanSh_avkYxkS!D&zlE=i8vlnJqgy={?Nq)@HbCls-@59Ebgn^FMuWWGJRD6{Ome z>@rwmO{RfEhKTcSg69P^YihUO8{5x1kwR>e$+^drk*(hW=o6t#aSt778Eb2+-pI;9 zsBNe`U5;siwHK9#0}3B07A$AH`ZB?K3o*V$UTY*h4S=biZP^<>X_J8JPH_#KFT>xf z*VC>_0y0q0Bf!ik_{pVJCh7fdB}?t-!t+z{K{VB-(QfRPU;HMMQ_S`>OnavyV)z!D3a>q`O(9w}6QxYG zAeJb#jB!OBr`tXsJig46M1va2t&XWyTt~q*WIR#-~nuC12a1#UB$l9J+ju#B! zW0<#xO(!`IZnJwHU+>xaVON5N%uZklQ>t^4x+)|mb+U5FLV}Z`f0dyQ+GRXVq8QCV z!KQx=!#24Z2)Fb`?*1H{c4~h!=KSFiwFTDCXHzr(-fE#%;~%QRA7SScBK4FkW%`-n zuj-7+N5|}Z>R)R^UAF649ny>Giyh=68X9xXH+|QUqb}Ae1*5|{uj_I?U#kp`3Yo;Db==vP~2O!AH4m+&2)W&HfXB4ez7+egQYrmI)3!0pACn;DsH=sXp-Ea(%Qk1 zqFdP@(_`kisR8yT@B9GIMMfyC3Kwy_J&3HyDfk3! zT?|jYUZdvj=AzZqb5rUypLQ6MC-@2CVdQ$C8~?&rtRoh(sna#fB6{a`Fzm;)=Rq9g zn#WFZH*lj-GCYF`lJHc&TjFE9aN~9@b@)ABe0;qE<<)=_E{ z<+RhoEjR?D8Z5Y_6@YTcLqELe<@o~r$K>V3Y>*^f%FZ5vK+}{Rb2R~U(au<$tRxooZDi){ z*Kt2j>%o3UaC(t;;*9(vya>Uh|@)%Kqk7ra@oLG5Z5AY1?^|yf*~Y62kgfS!CZvwi}pj%`cteNX5wXu7$hWZTRBDF5MJq7w(^F zp24HFQC-CriIi)GV#((o3BEA8bjP^$|0IZ}1)n2($35tN`i7)iDqLwjfzqi^RG7=MrIYCgBq5Tnu?WLp8(3P0*Akvtl(pjy~R4R@@H?8*Zgk zKIrRjEhRsqTN?C3&TbYH-n-dTeLws^%)N7PW^KFen~plRZQD-ANyoNrCmna}q+@h! z+qP}nwsF$k@AtmnTIa02_F1*7&iUu6dEXOH&8qq6ca1S_6}o~Il;>>-^$|<4c}VrF zJ~y)WwOdcPYwGvS(v+WZ$Z+r3gfp?HJ#M-Xm?sJ@Y$VIfWvlkNgOY`o6Vz!xO>1T4 zCBHg)buobzb`m}V!4H89y ztMUgVuDe^S67lqQ~{2`m}#QUcyA9Y3(Xa|iRA94 zmT})Tqn*k>iQXbdLbVKNUhZz53ZhISA)rjWnAwli4>*>L0!6;w;F+o>o>@_#28KJK zTp1>nLAO}<;Kzqowz4wk3IVQdew zjbTV?xWbbS3()y!3A_mr)_)CPW2epldO;N({uU6CPwzI$a*tyBR6wSKFA_)e&n1hqJjhY?oHto0CUX zl)|o#3HK3cgyT;=T95VX!SqhxmE=SCY|vvl|+*M;)4~{^i1b%W1p7EE}3{;tC&8 z6r_JV>wa-m9%k-@f|k<%LFeFo1s2_*L9e+*IU_sgP^fP~7l<)qWUG855ZxFTGfDp;Sd z-PB`p z2n}3a5Mb*zt=53iA6zPDLtggwZk`^`m)C*o_h*Zsx2ZR#YrmYevPfe{v@B;^;YCI# z8Ls7&%{P{cJqRD4M{s%)J+gYsh$TrrT}=GG96m-uKR|O^ccT3P^I83cE52hQD(V*u z%}7arI)Vf_{Em^|9d2==rIdnwHks6!T(iLG ziZkU>Z^F|&Bg$}$dG8#|3T*D1`k5R#!fq917-VKCWCq^lbtircdx3X;^M{Y5RU(mKogb`#0jRT zs7PMA;7dlxw>I>7k|Gx7jZwC)keuIsU_1)N9= z&^OxO@QB8WyS=Bs;vV*MJ$6iI(s-)>)_98j(s(X^XgnPrGv{ZIqqm1TS*-Va2&u3m zGpV>y^Ui!iZ8}o~H-sPbg{yD;*0)^VOJG5{&VMOAe_LFi1JdsaTd90pC=X6X-H{V* zSf&6f<=#GNV_WmWdOK^kd6YHt20GyY49$-L)%eoidzUMtM*tzLT9!45jM-+eo?+|y zZ3^sN2)3`C)I^J!x2q3dWOxBQeg3DMc-Fh6$pgFs!HhZFzbkggapmMA71k4 z`}XMo_xrDM(e(=Sw951JnW=*}BhU8Z+#W~*Ex1dcAXLE?ye$xEG+LExtiZQVfBend zY4^W2)?2RMY)p=GyuPqBsZpkeW(L*e5f-g$dN#GRu1KRQO4Zwa9XLkqWEM2xMfJOj z#kp|;cfaF+H1NNw&{D#QplSk}DEmZ7MZ!0UcCvCwDE*zJt6DmFHyqelx$AONePd{_ z9Z#yp-S2r%qz qnWt)g5{eGweFh#@=@3xUVzylPM3FHJ6eQkDB^5*75-i<+_Hyt zbD^j^>|cNLU)osC_OO(kfrX_~!Jm1j4d}sDa$WY;CYiF%rd@7ssAJmzO$B#U{McUx zlcNr&XGnfqd8t->x$p%4la+TENc2RkqDkZ3Rs0LtZfseiAE{8@+OY3E(IC_`QMWY9lIXj9uSC&7ZkUJm#zpAj#Lt^+ z6orOZ!DW0s^1Nht)#okwi4Q9oWI06Ru}YR|!lpo|`ixzqW-v-V@$ztMz;sQgSy^&u zz5Q9@IuxbJJ}NRJM>nJ2ATh4)btdB%f5ekN2H#DbD%?tmY;~W$fzN_Ux4~922cZ6c zm)VrD49uBIa1mBA2VefbOSH4^QTWwr#@vrMf`<|$gIv4$d{n^H0o?52<73+SKyNO^ z9TdZ8sSsl%4&hResBC~-@nr#6*qC^FSwe}Y3*V+tiREg7S2^{WpWB{j*I24YVZpE@bWDy&0`kQL4=MoR%T%I|yKq%>akDM*bBLwD7}k%Fkn^j7x7z-_Ii##p)3U?SM;Uh=oMDNl^n0cO zQojmXgdY3QM@Zq!Q1%Ml=d5!F8;%MQ)q5#pQ{Wq|eJ^bl`Eg{wXYBNaYCoeRw<>e5 zaXra)o;i0XkDlGoNCo)`Un654Z-KC!yo4v5U+-9KdQVKcT)|xP zk-XT3 z#B{Q9EyE~M&UKAEy1oHx4|bZzS9V3O>LuqLX5{+ zKkf&aCAK`Esg{jTG#2ytYnw^v95Doo^@iG1!TlMlAraG~FebDrKgWLeH$&{sewB%t z@oPck)nBGJ41Ir2iq-~jQaAY_4_fNtNB+~4gvR^{Bdt4cM-^81%R^++E*i@VczTzN z-wlK&p9#|Ac<8tCx|c`+Pgvr|QItofx*pTdg69X)O`KEelo!wc!q&9W?rZ+(KeMZz zGjbSn%BAmAxm34*dPW<@SzSdbu|}G4OgYr@9-LOlqaF$a&sP47(@U~8+WW>d@nO(Q zy3I>nvspP0Bh6bw#|WUGG1{(VZxqkBV~AaCahc-B>rH}3Gr#42W&MPl(L+zM-o51F zcn;4`n)#VD6<$!Y;t$Z1s7tbX#JR1oBU-P_&Y=37mv#8Qmc~`Z7J_Fa*PD5@?tD znDvq-4Bci0e_iMPac6D4np--E5!GRd>~bn(H?R=?l+<5K(WH^=MBV|3z99O_Qp(tq zE+2Q26vAJSUNjL7;DChBi1O!YAc+fJU2{&kZh=G{?^8K4=3OB zXSS<7bA(%hu4enbt zl)wy+>`t)Ai%SZZvEi~v2Fw^;;&sLKqWO`LpOqpAR?I37kx9sKeg&iaAOEpN;D`S> zvHW2!-7or{^iqQiB4i_TPpfS&bIa^c1`stPth9}LC;j~z8*AzHEG z<+0~414>t$##a>K%>zZ0=h#it zagYo3jEblMQp`W?*8PZ?a#dR?*(Y19P=J_kK{&wnr3_Z<;j4U%mafnsz36g$4;KE; z@ZoEY+kd-65`gscSkNkbwVf={dWR_Vgj;<8i@TzX8`9A=SgnjDAUF{Iuem-t2%L^S z&6^cz8(24(sE8|B+Egh@Ac%(h!_B2-@$72y)_X&KSl&XZm(uhTv=>GrAyrsDCqj~m zn4Y0!{H~qx8hhPme9T}Mxn-O^a$n-5ygho^o-kBEbzr`nEKPV%?K4PsB=L`CpF9Y>^Mg<=z{9d`7(6cJ8gL zg<{VmaE&808%(b=L<}OWTC0yQ=I{W6j!{D;aPk zhuP_{h^->|RQOYlL8aF5{<`h(Ra@Lc?dEw*=Znv?{-dsThB#e2cK?yb>6R+DO; zn5DdueYWe~#y3+?U0hFKUcEIQWv=0t0ZJqa{))X_@59b0O6V*TGR{5zE$f+&^640q zW$FuXD9U}LIls4kMa`0I;g2J$;7dsVji8FcW_O?MVN2`Q%`LuqVA?t!kDD;!l7P^c zrso(0$9ze)xQ`Y+1WXxb)3Q9GZ!7m{)<9+R=pKV)*w>Mh(y~BgV>+Sp(<+UuWz)V9 zOo;%+6K0{G5}PoLMGpO;C*pMTWmDssa|Pc?JgPj1WEW8B9N-ayQ72o6C|A{i1+wGzNt?5Ghg5`<7Ss@ND^D|-?CD*Bs3<8T_uh;Lw0X)AWbWCYZ=8M zghn!wAc(ep>o? z&tH`9tHbtq`e@P{*2q~og{OU6T*b_HEN|a7nJ!Z3&YlEN`7fD$4Odo!!) zf$p-Pp2!Bm~h%$ zDb2`&mts+ncMu99s28|nEiLrS;bC~`V-xEJ5B>7$RM9?RLZZ)8*}(YJ5MlrK#P?F7&g3tyg=k$Tq7B!v*L zAz|W{^$1SK+Nk&Ha`K5_R!o91&NE-!=AZdS>R$ru?W~lPzPv<6$jH|rp8Jzi5gV%p z4|UTomf4=BQA%2Uwe+>RT#+aaPd1Y)I%Zr2+AHsUsZDH0xt`a1QybA<{(vcOOCK=h z(VX6k`k$Rc`{f{wG=$!kXc^W-=^;4+AV*G8Z=%i5k2DkS3eh-Swp|%ZlQ%cMheE-_h#ioiz3i)gD-wyw8 zCQJ0zbW%!&oVb2p)9e(mZ}9Ik0I;CGSG)a01K39b-1znA09zrBVrB+dBGyvd|2`gO z0q5V2PbmpZ-ZH@MJXFfSi-V&opbKO-+-rn1JXD1Q!m$mM)BXm7il92T+Qbz#qWXbm z-@3V+KG1A06s*+t4?6b`G+Xr-npONjv*y3iEYwus>h^`QLk^N#pqd900~g8eMM?** za}OAHnC3YYnDan(mrNJz1ne-cyz43z!E=?MT*7lugG~SHWK!e2AEB^@G&p+F@0djY z&BP%yQ;bitP|HrZ!G$spbdFa_DDgmol&@6Lu$vQQLHSC+>@3JS4B;Lisek1p;*H-v zw{9kWhKDmmrc`(l7^Wm;ldnqTjW%rifV9{Ea4plDgCP&N;m#elLk`hs=2Vf<4wL(S z_HYdE>J39)twUKZGTS8|lorkJN67yJr487Yv|tnV{h+jjy2yVhEqBy^qO{dbEEKD? z&{v#?@~zjnd!60nDdbufJH42Sqf4TsQ<#Nj#RO$4Hw*#D`dtwS%Q-r$NJx2=7&B)k zNCD6M-(Xk+F=J=@)B4TNdnHT^{Pvup}V9|%k*g;e0+74Zpz z)-dry0{L#=II)s{C0#38X+*udK+lHQAXp<@ij{q&EPf^v8!IFXpbQ3C_$H5K5#SPL zo1Uj)5k9>s%o0XRc>v>lHlib`hKIuqd()zBlCEh+lyn>Z+zgECQ`;Hg7YiZMh!eJ( zWo`*_8ie)TPW%$)6ibnaGcQ<)C2vrt%6yyMO%rKg>`?;8IuU7QjFQGG^>LEpjxe|3 z)z(NCCJZCUT{w9T;j}bCtc(!XI+QJ<;!licBdkv0DRXhurNlMT z?YP9)$4!^1cFV(FWan!evJW%}j z_r(ChfvQ!BXXdZ+U&gNRhAaOS+_>3Cjw7D)5>4Yt=)~B9=gsB=xU!X);RUOUOgpBPdbBRY=EMK%n zPczHPGgqUZUZSa$%Ps<)u(wC(hi0|;uW6NaElB{_8Jy}tPL`!qv%h$9`pFVNpW>WU!x68+3TLsG{B*bhymOA@ftB1OFvNKJd8gXd}QJi1tP<`b6s3^ zSl@Z`9>fLCS@&kNCY1vs!iZqdDh)|*{7PaZzxb8JSnGT+AqD*9X({;o9o?Sr#Vtj* zx6TA+8{20ezV?;`d4GKd4u6QznO zyTl9-&`U&y;hW0oxdT2S7prsQf={^}Go=otp zdYk5E5_IfP*G;cq_1Os#B=sF=GUel2M)$kZxPilK`1?2i7Nu+2x(ayJn0QRaKJ0mm z;vQ?amH{~ z%P=ZJJ3LV_{DLGFnwk8g6km-Z)TgEjP<6J{7%D5l6PyMrkP}fh0Me5l(>2C(%?BbO z+Jw`Ox>tdbAW+*K;^{QSZc`EePdMWb6WdU=vr5Xztr`Qj#(A4$DV0%0`%9-W?CYPp zAg3=`dcwvHfpm>KgcdvwpanKQni$hAoUVB8f_H@RhYsQsXzV@%6ugtD5FVKmf0yKG z^c#N;mdyi5|2CO_%2k_8t85vq0#vnJP)1x=iNe|Y4SxmVqp!oS0EDM61^FTF*%DJ? zwvqhj1+`>$NEHsIp$D6pQw+jpeqV7tWt=O0m6voXGc|DXHPVS&fl2C8#5}UIK$qvd z<)l;t;b+i`nmBY;jJ>c6fRLBgBIh#AEUy(Evk{hGb%V%tm)BE&a9F&Xo2i^)%ev*m z)|iA*+|A=CAnO3%k!FBW@$JUss+Dxo55)8m%n0f`s`zI!R8qxn25C?QJ1*#R79&E! zFDvx~$ieC|m;?h&5_#t@1ZE|}p;kTuLp!+QiP(!Jzs3>Hq5v@riPppsFgl$LYiXGa zlsW^KGn@H+_wY@GXr;Y$z(2E)FRd1{wFZpNS~_<`L^|%aYESA!09S zr@5ig0@7{93i>pz0&XEW2`|Xs3&kkF&J0$NiZPF7I^=^M@p~YdpHovMXs;f^9+3mZ ze02aT$Ww+Jt|;Xt4{s^qcN5uVCrlg*CgqXUYAuRx`A**Fp;e!}wuR#29}9JqZP1EU z`h%nl&L6zwV^x*#oXn+J!z99HIMafnnXWI&(z7Cji2)O_zk=D?Whp8kIbzclKEpO+ zR-5F*m){!%2Ua7nHMI=`ihaP^iGN`2%P&~#*i2&c0c(eU!&=ARuyzt-!s>5Wi!J*B zYezm{tsDLBU$C}L?Jrncm~1Ni2iBJTCs?cU0c$1sOc4LTTC5)ep3+2*qe>sJw(l=k z%RR;UU%^^~j6nvXO4q7B)>pJ)iq(Z{sE6!x$C3T({Jd+6oI8(LRcNYJN>dHm|NnrY04=hVxd8BT$2x_~7ME*4T}Q-uh{(q_asiXU4eU}3c%3()-h z4lc8W7I&_@+R}6nmWe1cbN%(v^)=X%vt!`%Fi~ESd$omnCOd4x+|B1*j-NUN6q6q- z&#;^nrg8!qtdMKkA8MjI8zxK!{CM<7--dc#X}*tH?n~+lNB$EO38$^>03@MO%Xn}^ z8b06aAOu~1pnLUiF_9J5zhWX6JxL9cAUP~!f2Ty=1bw7L(vsI`Al;C21fWTXJ+kC8 z@_sBVbAagIm5GKWk@Du?i&q^tddDBb1-Gm@HBYBNvW)rqDZ>|eYb3*G5g`)Tpedzf4Mqt>xNw!k<*KGu~Ba-0oJEbKB8=tV4i2V z%x9dUtIiYzh$W^V@T=0P_5-DTK^N#I`J?u(B6Ejb3xzIeV>wlJzeMntJ3tUid>A`Q z@{wzUa=-fMI}%VIh?t77>yY7ylCDS*REAyvNASaF(27RYOkZS!Sy6T(SszK86F=PE56bbs-NB$!ya%13n5FTtRSzu$7Ax!33kdGASa^LnU zCC(Dpn}e-eXRLe7xV-Que3K$}q`vJUl9SO;5`kF`GvIDvBZ`sZ!iB!yV~F*u7@3O~ z!nnVlcRdHFqpemar}jljHgr@VxG=zAfazCQQ-y zz(xev>%=PIghllSjHq9bD>+i-?GHmhRorL*Qmw``)b>Z>4GN1oa$>s{k z1In>V?20{}1`HJ-D2Vc15jk`EN3Knb8%=xS?(YD-hGuuOuL^KmR=fKK z!9$O|kv!nYQ@dhQB(*;bno!|obA!>LcK0KY+=k?{&ZWd!7%Cl;&OUdg)z>(w(YJN) zTm5YIo;Y`@HpRPH5f$^_uq$ALR^f?`gi7p-4AOR4S@Ov2r);J*BjW|g+@zW9xHuDQ z(4IcGUIen5&xgKPKMezH;q1+>#PV4xtwR4> zoedvE_`k}|gQ)mdb{KjU6mePgGgOGHln# zc#gH~`y|32fO%PSZJw&)ukbcAV#J}hYP|0e>hbrbJ>}4_8BlwuE4ah3&#o=^=%*YQGgott zS=14`h?oQd7pc4$HrwIKPZ0|{X&55PFdD-HPqS#!6@E*vF@z%_`VH@rCaOm+(v}+6L)6V3d#Jdp zfSsljqC5)|0jZs(rDfps4birkOGjh%TFSepJYMf142&O~O=a8d+h%Cq0g61FeyaA% zi#j=Fr%V*}sY@zJq_~BoGY9kDQaPzMX4ov&<3%KmIGVf?$XQK?sdxH{s@HI2aSUZ#gJZMJTeZ@N=C=DqvNFXKw*^i7|-3H6>mp=U3_8y zDm;6)J~wk)o{PG@2f5?5LDiZ;EpQ}k?}cFrm7K2054FPVArA?)AN$;!g=mR9_~T?} zhsw$88M|#TT2eNen%#=yRi+1lnGq|x8=w7p!Y`-}msJ}C!%arod^uC|i9C6-H z)y=7A!`i8tZ>*@yz?!Cet3h!5!<9ymk{xSBYur4#@EAR7Dm9K77U;N;Oh71aq8nje z`)%+M;igvnm1~BB=0_ptT1vFa0%|C^0zbL)K8(^QDW+DS{l0nxMz1jhf&4<3j8Ye3 zCEr@K7r9%SB1a=P~o?Cgin$F$5FtT?Zg>?vyR`--$kbK5YAqw#YoD#g4kuHu#2;*wS7 zTT8uL+0n#g77^;T{$7d)) zjNV3oqdnd=6W&R|eE}{lEse$#4zqpVti|`aBOi`@vReQd4)RIr4uxU^3cpdSU_6zc zQvrc;7)o{rscjV-K)x};<#0XVD{{-DHzpX{NdMemUD2py9kjMUquX6Hw3I$BNIcI# zsjWhsCprsm+UiPg@QatU*8@^x36G)TM9$5`p+Gqv&t<1rb&WfSfSNN%rQ%h)@ll7~ z4Oi~Mo?J>p9&YPMstJ2Im|)Y$HU`GCUBbWg&otXm>AP$c5keA}?zD|r^iYs1-e zqufTsLB%YKISpUOOR35NmNp6+td9yRvoW9>dDh(?+Rkd2iC4G5S-*p$@V#H=so(h4PQ7LwdcVB& zTK9WX{nbHw3K{dR_mSdwa|jS>shIEcrZRwDH^BWbh!vMo>uxv%lLB zH4)r(`T#SKVL)6eYSUWmcGUV+bz#m4p}=^XE?jizz&0u?TtQw7OsAYpYd-Q>qGTpo zmox2~+A_5Zp$UqQ5&oYN&&DkT`suX&3QWHQAUcDwMy6z{1gphlC1!YMD{rd2kl zloRb;Za@Y3^`rg}xd1r}!kkL1P*7zxD69plPmhCLwMl}qJ;hS@el^7Q?DM14_J-$988&>` zqQ+g!;i2lZY};MFb9DqsDwiY(xNRI5F;x;YDiDA4FTS(K;mE>3rsMwld^%S~QSex{ z`UZ~d{1Ig+-Byq6bzkib>4bnuP(!_!z93KPhS(gyh01`ZI#aw_gXG>@&oXHfyx+vZ zOYZQNdzbY5U>nVd*6>VI2p}GG$^rUBE{1QBg3>*D5lbI66AL*1Eh%|0@^IL913oE@ z-E6A!%0Uu-V)@gng+SEa6y|NcH-Qg*_x@+-PJMk2efE-4Xy8a9%mJ0J3MS@3QSRRn zo2fbmby}$HeW4|EPJN_rY`ZkK>Ixe)e3COcoe*;q-v`3(Dv?)))TC5ADQ94BtI}yI zC_7|O4ZtOvH#3g>$2_EeTm zGfoOAmjjO0l&Fh}ym$gD|1XOdSP1{OS0FT8&aPwUW?_d{-Fo+${<(g`T7ir948l|o zmLX4_=WL|4M6+QElY6h1?$E$l()U+YhtUYM#Z;P`Ql6GbsR!+Lo_&$O-1 zM~jm76{FHN=61wp?7K6}4Rt&FcB1_y=XY=GjTB%h_9x>(%j4R-%vzZq z`KaFyif;gwx)ppn6NXb}e6}G}5kJ?B%Tw2GeEar-1r3RNWkGg#>#8W$R)KtlN9Vf% zz^X{^3&05Wu{lAQMDM#12y4_24x$V7{p`4!PN!* z1d8Mt8D)$n^FZ(u83=+t0}cqnnG@fHE5pV@AN13&TiW)E{Bv*ZFW~L>P_~PUP(CYc zCs7^>KWzeW++OdtwtH`TtuW;RxZ{8pi;KAFp8I7mg)O~kWtZhy7N3dr>XeHvcmCFaq`JxT4-Jxp8*7-RlQ~@dj9ydTx;U)LEHc}653N~8R4q^P8Khv z1H-&}yMD$x9Mj)Yp_f{T8SYJ0jZd&~LrQAn!JZv3xEd0GFtxHT2y2h3bqT*tnS7O? zQJo|eZB15_!W?4@;LaNQ42{xUbw=GB%jC`>p4R3)m9UXCfQgw2>vdz~@Wga$s`TM) zAC5WmCdbQ?`h-2N$|fiHSO~{iMp9u35xXF(W8U_38{mUWN~CFLT^^mdnnpfCN}1Q> zfX=~rVT_Upuc-d1Y-3@r9eE^-Mi$w~g4s;RAX0J&wJpJ+pBk;f-mEqMQwd5w;$3#{ z0kP(mIWUh$k>_EwoxYC2lrB6gkZ!Z_mF=+=*76R(J{=I8yJj5~wl`vpneN1Y2-ws6cf{Sz$=qN(|TS zHq$SKnM5wd1GzJMVJ*OPt03ETnJH=%X#KVzb@-8p)O#k85l5SB)Pv&V4rf zo%>Wa?Hp@amNXP@4pISN_u@R?FLk*)e9%w2lGbWtKI^ezQ1e$-xGUHDg^AIK&Ynt3 zgm=x5{Zl^6XVWo5{9TUlko*f}KhyCzNrWF^W6Ea>J3W3|`U+1~n=kN6=8g2EbTp*Y z)X?rtu{m_Z-J`Z!(U<4LByFg)uV8hZ!nid!h}pj`W}-I z<3&AHlThOYz0s2}oQc&W+4yosLKv||z{Lo(m83}&f(j=DvI6v|g>S%69NZV#{-mSt z4Bu*d@zD*rmelka>&k|ulFSL4-=UJsPYynvfI5P!(+0Z7H zsfkb3BXu*hi)OFV5o*FBqlLTjq8%I+iHR;qV_fOci8NXOem3Z# z$n;7Lr0>S?9_R4XfjZ6h8L(2Vsz4sExyI_BLqjEa1x#C0DT8vvmB5LP#^a@JyR|c- z3#oRQ^}nzi)3;_vz4*1b#t~}O7s&~<)sNJ5>+>y7*{{Hr%S2n*N0$U-=NlkkW=(iE z@9>Pln=*Yw{xLLASnB?OEZH&vUWHR>q&FS!4T=7a43)^UIK~MDfn!pH=*d*JR7I!k zBdlz$3TL{v`t^|~AVNHw7IHkYktd-|d||B&QZ1DxT9AKpqMj#Nc;z!AB*==JMg6Z2|i_aRld`sxp`Q zdms_8US0VUC||W2z zdubzcj~}^UdX&`<-Gyh#4-6c^I3@R8Eh+Pc@5b>gJcb<_ucUZlB#-wgwJR%{dFtzQ zmIcLf)aDVSxpCNw^!uJw%xC_A#!sn}3#U#25!+CwizYh})=Y9R5me31aj_^t2qR=Q zwYL$k>EJLrT_3?eoeeIIn6g7089CP>?u}0aqcCJwo%V(1QRQjph)#rCD?dH;)%LL^ z2oSkHp7YK;Co8NA+kA_W!(s-E8ww@E(ZQDy*lnzLs;2O2qiw&SZiuVt+gswOv*T#= zjuBO-2#xF$;;CLc;xKg!2AA$*$!vRLPz=}ueMAAN;`BQ% zVoKA^mN~gt=3U8)PqG&sQZ0uQ ztU(IaG6ZkN3!W%GL({^6GcK6IwO` zEHpZ^1IWP`MD0=r5 zaWorRK2*mFvPJQ~caM)o5%hmMFgS&csIM{n47qyqmc{Vn!P~EU7N-B^wFnSDz6~`f zS3Q~MG&rVX8zE7=zprLjt%sbjPsTL2@1ae1@qwqg{?@WH=v4uWx?v3)LS5fnA!Gjx zG7t>tHrwPK4?fdO>CF|3f)KX>@gc3vm)I|aV6wk>N#xZG735kdI%)5l3iQZPxdrW( zwX2%P^2&4Z#L?a8JhXDQA#lrtWRyFjbd6(t=N=^dh5pxd_GTXIC{KK=ungyb+JnHdMi ztKO>Wv0uFoh(rOt=o57hroX+CRNlXuluOR{rFT{7Jcc+Z)F0O^izR0`)F2WQeh_*b zG4m@VBbw4VXWWduR`l6jbWX6?^lrd8xz}3Na+6+H7v|`m6W>9-Pbm%9YEYa4ng)!Y zqxWwAY~?4%C(#?jsku8KZpo9npeS^o3Gn^7u3)Res`-;=^S3W4$Bdv`&Ybz*3#4q# zOCIs;(q$~&zozd{AY)hPy*}<~L&=E93zoT4xP94e(6-=U$2j9)Dm|a9-b|p<04I>) z#OWd`90=BX%{|cRbGYcTeUH-RYkaZ3XMpf>`zi!qz+n+F^HxxxT<%F;h-<*i10Y+O zQ}wL`O;b@qUa-qLk)^5XWX#&*e2*&SdZ=cN2V|_3mD?V-C9w%S7Qov6(V6qw9}uY^ z>``VVSDhN3#^&v9JCL<>Zc-Ta{g_&wDRloyoqL6J%QQN}=A3JFV&@>gyGQUAScL(1?H$_35>2EZXi=96PVFeHVXFhtI2GM}@!Jrq#m4vm4yngm(;G5z*~ zPl&nhSbx-|Mh@V50a3s1xPq)loe;nKb@&O6aEUshB)JC8VH>(UM_>&Nz90JJ4 zjmn5()}utjF$I`v<2jYPRGZ1|l8e6~MYw6!HcpoXdeB7aaWfbSe&?yd;124VtJ`)a z+PuGKKa0ZiY^5eO%BTKlg)0T?`%&|iswQhg&r(BxU9xtaSCzI!<o)l2#^9F!#t>!c1%cQoY+=W0`7H{PtW?!dNpIhr^Us%jiXF*7Ygw+U=8Tt3yn zNIuOj-HqyZH1>X$CVlJMhu*_Sp&u_{OjZ`IuVI*b(cw|Me#iZ>%y3E(~5r6K*XvXAzdiyy61$C z^3fbHzyV)3d-rKOr0P2dn%ZfO0>Y1IpyE^%b@t9+ooSml;A!QBwQqzgzS#&(3lBH+ zc6)RfW1}_C+Xyv|*kf6+5$%4#=3OP+oO&0m&8v9Eipo{23A&lyDztOq{~x2=AOFWt z?)d*-P_7l~e}{6_{*R;FzB4l>$a4BaoV!l4^Er?o6~Cj;b=WBNbKG{PREUxUSSaS>j?n3=S4qq4@3KU0$|80cT_9 z@l_zo?rXZRKi0|;csT3THg6`j{&xn8kZ%l@?4O}}OaF(}ig5oP{!fZx3FZgv9o_nk zf0@-l{&^X}Za$`zQx^h^G4U_me1AFso3(#B0PMfm@Ep$LU(onBKAsa0$WUcZs_V|) zW3V(tB9iU&@gp6HQbk&eaoJhrybvXd?PG9kkQu0YoZI!^86@aIz6&%yq1mSlcHv?J zBG|kH*@1WW=G+QkBB4^8gH|;=*@7WcamiX9&(>CrvO79uAtj9LH^6AizUYT`RPeDy zOZ~p_$%BaN>%*s`&0f+R=UCF6jG`Y@`#kVcr?y^TMw`gU@PxX8u>`fW-5b=c&VUJ2 z`(@P`J(sT+QB8jSu+>D?cIO~?Oo#iyTuTBdoKe!PL^}(_83v%9AaPCUh|dk{=S$i8 znDLK>LOjZ1^riyl09fVkW&P<^VP=x0{24Z~EUq6G$aFA{ZkN3skv0 z^4q}sQN6_%UTM=@8=SE&6sL-K`)1@MuCaGg6W@3vCtVotzf6L7UD;1zHK)TM4+EV_gY5U|*cl}tWZUW+z`&tj z7gY}J%xF0*n$kd*fcGBk)yrU!5pqZ*z~bm3P~hKB{raxXclfH#Jen}T>tQJPA?Gp2 zqogO2Vk{s^NGFZc6|2HN{PN|i92jPPuMH!Yp#%|gZU?hgp3#;5(-qz~!93%LWQPha zO?luOr!TzAGC7Sm!mpMYK{_KBk9-0b3yEVYFduORorHs+4DkraOBi}YxEnn*kTwix z*2610K!_^M8;Bk$HVF-u6f_ALMh6kAg5-O=4A~wQAoW%8i1F(Xw*svv`H&|NbTdM^ z?O+<2$qsE1&M`k`0XM^<(Ga+qTN(RVz3sFHrA+&dCcT!AP!M?-KytrZQ=pQ@b65te zD{ov^ZQAc~*w=LexB0D0X%%Z4$*}l|~mIG&&e^{aLwX*NJLC(3U+Tu4WdGGN)z5dN2MXvQi`TJIJ_B?-~e<$wB&zNy_ zyT!x$>&DD}KlC?679KjzDX;$L@VpQ0qE2(oFJ!8hpKj%ztn55#?G(oksvTvg6)S%K ze7*db_Llcwm;`F4#vRC-;brinXy)XofTjB&gR}_|iZ53lYis4NG!yw>j;Ge1QLxy; z)3i*A6{r_9E(;!<1rzZx4i62}1RlUfW%Nr0u+#hv%JYd=q+AZpPo_6}*eL?VrBlt>)}Ee}xQhueMgr{?fTSwf51I z6!GS5(jD^C<}O&lyKUVM zdiN{;`|PJDlj9;bp1aX|%wgJ10l|V_lZAKen-h5WNuH}SXXd-&MeRGe*Z=5vFY5c# zd)-YR^^@izQRilzv|!jb`{-Y`?%2rh(_+1(?B=Ta-*U9J`BWuIvwE?lT>$)-r?_f2cJlO& z7O}R&Yg;uIx9*7G-CKCyWWkkyNqa({1Z5Sw#WBrz*Hm~rz)x4S=kX4v+Y^p=iWP5h zcmG;2XWEnWm^R>bk-CrFravea+W|Zu?z#&;EQ7X`N=*kMvyvs7TuYG4% z2Cn9qb_jKVR_f$%AE3>fnZ5X0%w+gefFnPH%Zu@d>)pQ8E8uFh>^16V|m+|@}kiCN#ok4lDmWc39;LC0rSjS ze($%{vlN>p-b0|u`*Dy|{Qn*LwJt?&1GgZ!4Cuh<2=yIxQ`}U}ceFOWY-s9z| z$JL5HeFJB5iMP~Z2m}m!r+n_GfYC*1OTC z&EEXANrFJ{QR@kBDQxeH5RI5K$yFXv0g~Y&4F0WwNck+cNY)!W1>7F}7FJ<6oZU|FTqWTNG z%%i+xX7Jf+PX;tta>< z-909~M4Gl`<~_k8+`sT^E0^0AuT%DCYZfoJ&MKwcXUsRFCfAczI~(8F3Y$I0CG_oq z=P)h%jw+vWW>+a2Da=fBnSol(m_NL=Pc9ifcsz%ST!8lnVJzoszkPTIhOam7`ROcR z9p^HFb~zf4eVe5YOOH*DHZY`1K@EI!%>76_%X%5?Dd(H31aB8hiO+GgL7KPgQ&5*C zCR*K%+Zk$MXkakW;K#JHVycTfAV^1*-PGqBr%3#T^UJM!@|l9Xrx_MKF3a~LC5_KO zF0Pfg^Golv9`TOtuj;=`X?b$i^${*4BDN{0BFi+mYEpAWR|W7bGI4BN4_$THn2E=2 zNtAqRnbY|_dpIdfgxZ<$>UAOyzeLrSA7tCf#;q+=I(iQFQ}yMUKNyS&B##%mA$_t# zJ)3`(~1cn*NoPabgjM+XA$ur@f?*^CU_@9w*wx!6CY^$6hNir~74Ufc-s zctCi9TCaroE24Jch1n`Ljw_j%(;6|Fe;-orw2A}jSaKj`-ym0dJj7jE6dBesH{qPU zI;-`lbKg#)8d5F{*-?c{Gb#?Fx__jfrb!s__=5XfXVkz-)wfyJ^y>8~Y0BrX0d+1; zX_{ZHTD|l-c>~i(aRgVl=;dX7b3MDzJE{l?u-ZYo|GWW0M;nQ-71HYP`_$L%L%zey z9IeuF-9KbcIWkL#Ho5GCECY&2e!d!zZ&xgMor$4#v6Jfi7E~>=3<&p0`H|4d+S%s% zeT(Pc?RB^aBNTl!XS27`ZJv~tqo!9@RN-V7)VHGt0ku4;wgAVC4Ja zG3oJ>p;jP+H5@>p)Zja8+v63R2)Vu#o%+htXm;ZiAciaad&4O*J z6q~CLa;6N>?PpZguD#C5Ru)33FIOKnLN@3;i}zKZZQV*ahc0=|^Ar$fS`Xj}#cH}t zlOEEDMY6=;qoGP}ss+sG6w+^~N8Q6{ThL&H88TFFZ<%d>z1(h=mWCZooWiBKd)2ZE z4`rQGzN#9V1l6jl*_S$9Ng{;p^jm0gDuN%&<#Q>F4OYg<AQzUB**K0@x1iL0hMfkyge84&wz?0B;4&HoUdd@ZQe({glf(JKuWC$;LzEjJ6|o z=*Z;o+4{Ao-nNcjQw>Sy_vPRBUl$rRRKzIX>M+;S$*3C7POCqbkAQZ;I0lDY%-Wo5 z05|IKmOoZey&a~qJtEx>94my~-ozaNTs~j#2rcp+ww{oC%?s-)vt)}YSzP1INJKvJQAAl^8B|1?J6SD|d*mZ-#5nAKIu9B@8C>6JZjbPo|o9jsE zF`;@3JOv}zO%>(Nyvx?CE%HJuCsXBBNR^Kx+0MO;%;6DGjp3riBgP$s+=RTBlaynW zq;yq?-qnh?eXl@fRezZJRsAf7$>9H8HICLhRSsmi!n8!G(gE)86zIi$v@4}XVAYmr zJ`8>_joLm^qOOam`T3N!k)a9C^4OA)y^)^T-S`ljd-|DMWbWo}&W{xGBZxC&!P8LJ zU6&BsP$ERO*>6v!iu4Ef0GMAz)0Dc9Jej?gA#rKyeSM0p<>1+nh2?2b6O4RH(+YMA z;gJ}|`BY(BQ?Em*lhdJuHSPGhj$8ZwC2fOFJi-m_jpk*H2NZ_2a}-w)@&QI;wCar` z*08F3nF_b_Y!(FZ6P)t#8WMvaL4S9d{R>(1oDo`|cXf&3yT!KMbpXs8IZ0QTHq*uT zHeeL(9m;eN)T8J0GT!>>d2^p>F2(tGWy0HZ*ZmvFe4eycXBc8s{BBNlH~i+qnRm_- z?IBFo^0l@nJR?2h$K5@2h{!LavOVh7#U4~Tm&R1Lr}5CWrc|*^u|SH(LghBvnY9~g zjJ+h-b>ds^$7`BYi(oZk+CU#mvTz^H_I%x)NN*Q=uM3oKfKD3;?P6ESls1~9%^ccx zMt;bQs8o2*Dg#ipscE7H?(b9YUf)U;4e{sgmEc}!dV&=V(y2wOkWa_#@|y z&78A8KrXSl6nFh0dZI8{^QOsgg)(P_My>fi(2`_TcuEsVUoYVGW>2x3cM!r7hBALo z9>}-iJeMgfhB(xvlUhh69Z_#Qggsg{(A96F_2YExdHWI_(bS|f5Soj%L!v1|E*tKD zF3=s@sLks1JEqN=%UV$cmz+P>wb^DLiHkLr~iOy`ojJ zE#XS4wvCl&VBZ-ORFZC=sp!qUW(&W_UL$Q*+ZF3QMs*6aQ%)amN_6ma8*rTpU&Vwu zUfE2{B*OIM1!5_D#y~rGS@Sku*V)^*sIfjjB!7ty-Pn4}Qs;Lh9G}nboxi(KzXY84 zxhs5~JBkI4S{xDcQrzSW9Wi^uSpte?pQ3VYu?$lLhd>T8uyg4!rp!83YTTj)`wdA{ zGXw!f`bdy{pBAAzM4`yo`@M%G(0BT*=cYV_q8CFAokk?BI(}%eI-7l@P+=Y>l3M3y z->IDi#N^N8FIujc*MbKshIshUp6?|3hJj)f-S|A=ev#%u)-N|46p>d3lQY>sr+4?% z?oP;DB1WY~a>BAEyg$7FuTZP@bh*0Fuxam$rBMbp`diQF1nIo{p>qa3{E@ND{V-R@ z!vF(yA7f`s=-A>4(vgt#tzkKjwzG`ic{x(IUQ*4xWvP8GVIlc$XOXoosAPXm3`hw} zY$&=CY(ebTykl~ZZ$ff<6@1ihnWFtdlTFj>fH<}lutcp;OiC^-<#R({+DXP&sQrC< z)65vgyS)$blyaLBn|_`JIP~YRu(J>&Syx*Dw8R20xABaQ{Tnu5OIy&vFjSJ;P!{q- zRF65A5rWMLDqJB^Rk03ejZDeiHaKtc>`d}^+W|2vB(pGByBAX9)HYdR5nlejQr^+* zO*Nzb=tK*YNqFor&K73{KQx$g9b-$Mq#TZsdd#B8N#^j;0DteX>F5mU05sL6$M#I@ zbkyKiq9RkYSz&{t*N18EF*_i|5S7&d=mcF7`K{>!bP)^|5FRtoH8_(;?m~XN#_9(M zU8qCP2;r;7c9!amZ4Ao0j0_uT8PF4XcQP)_%X>3!WIqeuch~wq zauYtn@M#ox#N9IUy^7@$;giy|OSdo;${OL88N)kcXNf|$L>`3lnBhBPPa*}Z3Ec2! z(f^y29mqUKbJrQ`W^8Y5APTE|2{TH3njxClRVxU!ZyOBUHITv+0WR=;SpT4{C$V#9 zv+Gp=i-#av`z^!FWj*WqU#|1V6x zlV1YCIBdZGRoaPV2VQ@L;qC9a8Nh#tEO=g&l54|i2fGDt^QPs3`*fEc?hd{UefYVL z;O(ZoUmv~7F2%k7_W?nrRewpTV4Y@DEgarf)v0A}5}m6chI(PNL?cm*LE7N)2+dcO7<^ zR>NlLpsq=36e678uAYa_ElQA~CXvD|Rzu5dl)A7^Ltij)A={?~aF1kn;m_TIXd-cRW$ zuhYu8O^pFl>vTLn&imZI1HK8l}{b`t`))syvT@ z+Nxal(hkq4YeAICZSFg5)Y%M~2R+yV+x0K*6D;e1)(>pL%ekYB(>wAgv(JMzJox8k zrl*@fi3zrxUWMix9+02eFNwGHPHbllviX?{Np}KJF0JZjh0@La{ik{-$uvUum5Bem zX|X=`3%k(LX8K@}&M)))aOrA37Tbu9wIx~tcHU(XUh{L#;w~}(grZXKi7pnVdPSj1 zUHOrG6Kn55n2cjKmIh5b!)b1W(-k~Mvv*n}^gmx#~s6b?Adh!Y(FFnl%? z@8N?`?!b9y&&-o^0d3+pw%O&-E~y8{ylRC1RXV=%$W$FgNNlzY=$Zn0V-p68zWehx z(*)NGvufu5Jj3!MJ%~pU28Gy6tYZ^$CN5islVf-OJY|}l0%oUi7y<}5kwoUqtcKxv za6G}nloA&*f`PX$@Md`y57MONUxq`vUr`CX6NbatK(uK!EszX5)tFQk7NTY3g&838 zRDVtSnIH?)-OxRqPU`uyH>Y>%-%s_Qy+MhQ+hAusL$3H8u=C!3Z3drk2|VNe zFVc&_Mz9e3wr7ijXzu$>hzI_u=VH94qnG33X<1Sio681AeN}9!-W9b)2G@Iy<6U;O zo=elffE6l@Rol%L_pY}mcMG)rHHK0h)pb}q+r;#Ahc!7`&3S?1Y@cSF!zGbT&UqSf zm1@-&eAA5?l9d(Wc9N9pxeHe&AHD0}S5$wKD5mwi3p}dd4HI-gF9#+H)K*b#Ud^s0 z+OY44>l0~t6hhSf#h_P$3dRItP-@>Vo&W$m;9s~tKYs}P#Nh*g0}T0>6oU5;b?w*^ zt$d5ALsGvxCTH`N4K@m*Z=C@KK%7m@obq3{k7Ygl=@pT7ONq&QsMv*+G%#AxX_WYY zQrBNUALt1~Sfwatrg2{LInH#Of-|Ln?R;pz+Lqsrrwg2`v3*$^Kv@En|UW zgRl{#4pjdB;&(8@BT~_k>l{joaaI?I{5{8Z*Wdz2O4_lD{QZLqD7*fjrm}!HP~`7% zppH&^bZ8i1H@%gR1r9zQUY_>@_Bq^Zu?dmE`eA4;0RDSl|GoPp|2P79pM^(oTTN2v z^7j~k@CgZAMMu4VH3w#SV1h4<&bl^2UT_45ZfYI!r&-)Mv_H)foucZ;{b?4^*Q*Ga zb~qH|?XR;{7*k@>zZmqt_V2%SISNBHJ~fT_G_G%fL-+uF^qTz7ku0F4ndb0>{L}9) z&+t-L8pdha;v-Zup=Q9bqcn5%+646Fc|nt2rrYx4&lf3<8T}M4{@rgqBh7GWq_gmm zKN!q-`FOfTOmxC9lAu-|;!r3;^0rwZvg`BVaQ`Y@L3g~H2|Iu)p9Qf6i0@i8*8J-t zf}8DFx{HpS5HWL7``q7Zd8XaX{bxrvf!#ufk)(&{5m#q(r{K-o{oykjT84t-R(p>> zJ7}c$o~A5r5dSGVF##9Z0s721ecEQZPXiULgLNYqN?R_oKj0cjKd~fo6j>8SoAH)~ z&?fEvjTADTFGXQ2bE(5-oGhe;E75QuUI%Fqf#N1#_?Om^60QAPF>3dYGs_4Jz88&KRZ27v z!Oj|g4KsICz~PV#_ai=Tu^A0XI&Eg=5wm$p7&t1D&L)S(NNjp~tx?|8=mGKXCS643 z4JvR!b~~J{M;Eb5kP>oIA>R{CKb0xwI5&16kzg90fFF2JzjS?m0tukt^Z~$uhWrO< zBR1z3s0;ADzB)=yED(^!ZIEK{kEExd#b^+Zy{Ytvs*~#?au|R|gd?`?2xnuY5G=hP z&OX1(b<#Gup=!c9F?4-`PnOPzUMoi|b?di(Y{m(FW+S?{&~pRu;gIv;I2ZEMI9BO| ziEu1UCcGu+e@fClbE0(6=Z*%-i&?x9e$eW=vMe^Y>~o)1{&4;pF3OcQal3R@piO-_`O%T5Hp%L7ctnDuAao6dd^whI6Te%ps?_y+qT^uiW{8Fc}nWev=7wR3>l*b{b{p{DmDj7&2^0QY9`R@q78HTGWPY zZeo-B^=Hmx2E1MCbya*A3}#r=i`F8kx9B-97TRtS-?S+Lxc1Hya}`Lx=~@sLIN!EA zM`Tu)?_6?Dq{ds8PVH@P*39kxN^Ut+!n+#ViMuOH6dNi7B|QUS_?>*OlT4(pXE6NY z(YUrXNlBsKJjn75S*@wV-Hd3t1!y>Hb{EZxFPFNnYT=lRE_m4FL$jYsm6$?c$^=BL zpa}LMxb}&bKIr5J=F!bcy8NYIn~e^Jc0D$@luuR zgVPpA=cue=0OMZ>#*5}8XEQQTbcqbSvj)>?tssX_ie6m`xY(T({ryDy@(XW2%4GEv zS*j^u=ElUxW!#xPe|18MiR5l?r-ahU{R|tNL3O+*N=OrnYXa05oS-+Z6S4RSI+-E(6J0%cP5q#R;curxBCDVmVs7@{VlZwG z4cKwmD#XltywIq!7iQ!o%i0XeiZc1=#wnQ6L%0l^cK`=sztYz9N4(H*guS>E zMM$-=f0Z`@(1$n4=}piKSd_+K0NZG-@wa=oxFQv^_Dw!-m!`iQniHyAv{XkuZe<#G z16Q?VgmcTz!o9!w%J-^<(=VKv2QBT-9eZDv{$SMm0kf3jRtxCJn2$`+>y<+4%eaye ztEmH*v~jbhUiYN*+hvwj`JM!8#$udmojHxIl%Xdn!_WI zfS9NW{f7wZV!IN~=#b?qhk)%OQOk5rH@z!##GrK$oNw3`fvKNZ-NtFZD!vzckLgAXo*FaI zDe=d7m{saW@VODDQMs65!hDA{3^ZN`-aT3;qW39wVy|IBQ#6unv+*UHv6uW+AkCO! zSY`N@)X{9|cr?m3qTGA2W@x~^cev46ubHL-a^NIM;_b@Um32o}fT4YA$%5@DR7wHU z;MD9U4JdzeomzxeP00y+^IU#COW|7G7E?d^+b9ndz?VyVd+c2A&R4rzxnhK78TP{9 zbRvUdI49+M-$d9aQG!_qAr0gd1D3q{JJj+J!5J}Ss?_^806W6F6)qgwPXf-o) zvVfHeWYbpF%O>3m8qwW5;vEv4mB)?5dE_aLewDY86cM7(`tNyXZWm`~8hdF4*zDTD zkO6T7cA4L=tkD6dgcTYI3&NGL`doLT$)xJi{iN?9um+$jJ3dIb04^|-hRjX0$?1aE zrTdes=78}50T*tq$pbLjzyrnlUc8v-RyAn-$^x`iWlpPO7U2DfPug36S?vS>OGEOv z;MTKa!qlrlMrz3J`jC005LFq&d-9TtwnJFrE;#u;z&*?oD_=#bokZ~=KA@>4z6F1TkA)9O&M z+SgMyfDqy5kPTZaz>5qHGk~+>qMGL!Jtv$57~9CuqE*%bbstrK4{P+jOWPY`BQ`F+ zydy}`Kr)x5|EcbVY^=x(ez^R^c#k_XaAtEvky4Jo+PcTA?F^z`77k=*ojx{F(a77gu)?V0A(fVovx7;n|cXvi_I~;}~G0 z^Pb0;sOFAU{E8@nQZYDQMT0viF;%oEBpq{Vfc*5%AB1}d1w)W0(%|Bg*Aq4@@N4ha z#-Jg{H6Uqyk{3-B)j=P`anfNPS|nwbf%Tp{eV6zsl0Yx~k}Ia!5YIMdHM9JX8cpz5 z1hQ95)~uB=t^6a2qG7Jg+OxtYB~>p**0j}?<0;T?)Vh0?%v8kQu zBBn7>bbDaf1K!s;JC7?xmrWI)4Ivta`QIipmMaoZta-2o652UV zmFQm@H=)t`+QRIb45UaL=jSVHGnS_+^D40h>Uv)E2wd=N`|VWtFdPFe@q7fHuiZ`E zR~b3TRVq~cIDG#|5q6_f>{elv(vhE9;b=pOs#EUnBxW{Fru8tB|5g{rMortoHft+t zZf+8y{q6#XV0cVKx(rP8NTB`QCR#nPLe>ki)8Ie5*WkR0BXe2Gp zT=WRKR?`RG+Vd%|`>i$k+A<3B^)#Ox&2ByG#q8_}P(jV?ywtby^z}+-sb9UarLT2G zW^qxmh$O{NI7GR9yQt*d3oj@2*WiKD0P7 zBEb@zDO0e2qay-KpzR!L=1I_!xJjhjGR>MIqSw*vJ?C)l7j$@i=y$wdu}DIcKIxh` zMxaifD@sDY99<`-SdmkTzfL<41n(gX(z|fUqz)`x{$1p8V7Kc&w%nvfo5MVV=TaM@ z<+otvM_XJ->M~B+T}OM^&*@S`|~p zl-JMUARhG~dXegM6uXIK$vR{l;w~_d3D(=`xJcYYP3CMj z#2yfsc`8Y_cn~S~(?~vkNrd-SimCUfTv3uvOMs+yPw|wA6b`=bL&#NvU#%2vVW}%J zMWbD-Mdot_bMtGPPfiG=<>~XxO%-#)?ftZHmaR(%VJ5=t8q(+v%xX={{CADQ`?Zej z7tIg7BW8|k`BLTu&uo=htEf-yp7Cl!G?A0OOP5dOb*<_Jae5WT6UQWE7cVFwsrS2 z20xX6KXshd~xo$BOx+h^G znmp0tc#*^$yT4@V{-M?&cuHJzitUcY?ClBE^S+8MRWUxn}?K z111JOVi*Z0NXpjLQ8Ude5;y7LGV7Ugd*#LT1leu$LtC5M*GaWpGF)L)Wqwr$x};pQ zh}8;$XQ!CXXW&R~T(UZ2B3}ngkf|oECsWk`oJZ?ih+laWJevFbM5XkRE}a~e0sCD0 zHmED0C*UtezT+k z?#-|CP1OWBfh-R)bDqPJ>}qmW(uH{{Quna5NxTM3mY_Sa97haz0`pjO!Mnl^b#iME zs*Gps6-RaC@AbBa&TZ_&6T^LpMqSS$r(nT+w^wmnPwMnrEHWfvvPl2xlR8~e!2@Vw z*PtpzJ7ec4PxrG)SA8^VY)yNkXz5CK_8cV#b)akeS7-Y}NJnG-LvzNkV26C%93bQ0 z*jwGE3~T26AJ@(jGf)_h(QYNgfC>$%uP);F*i@RSs-ty$*Awf*O*#Z()tUV5*~U;+ zJnZ;pGW#E5O;LW`!QVX{v#Wa^rZ=x^*@n5$8r{{kQ|2?OHTnflXT)?j%Q!xm&fOm78bEM`lpa z!+qR!0@cp<(=CRE+bXY#BZ_IbAAa}xuU6Vm&rF@2kbZ7k9a_1BHlB982PR$fUsvl-4a}KP06WW`t;B0u4a|dsjbq-I95+|b<{}qImcC} zlBIIDQ3srK+8Y4Cn>5+R4gs>G8)Q;N~@G8 z>TK&G4)nK=f)nXMGd+RMQU>#Flc@3bnb=DPORF}L;TRk`Q&ok-UQP793fiw08olWK zu|2kR(DdML6YYnt0(BFRh4^5P+zorE^B1~!}Iu)F~3^a(cwQFTHYz<=9$%l)(thwqQbKpK5p&?C4 ztdEk8qshkr9BCTUWJ`a>%#jt>sx>QTu)xsaK~TpcLGEikN*%8qm>(k}pY-JDWn3`ccH4zR{!Czb(fu6iTh*j}zZIqM{ zl(Ja%n)EHSH+P0^ zDd(enqs?7&U3&ksTu;opFykW1ZO4$=I%TQjs_jc5t;pz&Vl7KK9XRr;2t0p*sG{0g zc$5G9Qp{2@vS9Aa`WO@6Cbh>9Fd1BfNN;>#s>rpbC9_uip=|PYDrn4I=`a?G4pL-B zTGC)YxCAk8uMsDe-U`!xw~j+<&yM6)(ZKH;7)cJsD}<4{I-=q5u%x&>XIY!O_Bw8h z#JDekxVi0#VQtXCy)h)wRRezmp|PrUm4XEKu!GYUOl~TjxcmT7jGt41Aa455PND6Y zY>|CJRWfeTZaMFAt8k&?Nvs6lR&_*u)98rPQMdHwbRbBLbu?rT>^^$9aZMRZ4Ayzj z?fVhcOLI&+7DNb6#5>(@Wj#ZoVD`2{ycMy%AC2@#jxK^vY{C`xaNG3@)~pkb`yVHz`-96oT{q#`J?qg;OMJssbuf{ z(OdlSobXN!h{@s~^6TwJGg~*G7FQ+|=*^E&`BQjAN)RDkmlf!KbmbVw3-l8-B&|@# zFoFIFZgJCt7BqAl0cAwC;*JWu1Q}jqV#yfNP}0@B^9OHTP!}3bZ^f++tYmnGV-W5w zTE70`)B2?Qb7qP%AcH)id3Jh@;&aEQtrxXLG3*x6U1}{BBP3;Hog(y=5gG<^OYfL* z=n90tDbXA-Did#wNr}7Y7VE61i)xxO!#6C&J&9lWCZIa?K5JwHwpQ$wUbI|E6mJq3 zzj7k%3!u?6>szV$n&b1N-7{~LvBmXQEaGj*vOshSNlU2(`5&fY83hVsR7`uu_(xxA zAAQuo^=!Y#CFn@0nKcP9sB58rFCAnI6 zG3$i1GQ7d<7wvbIan3>_-318&y^#}tAD?jqXlJzf1&7p=hv$$QEv3M5&Bc@=4x~!AY67`dcZmLG$9nHJ%NNF+~`K!X9E} z1cPjK=h*RIi`UmP@rcV{9r(t~4;`fs8uVS4k#KX{alx4xtS((Ud08Y$Mp)~m6~WD% zk4)U3W`8Fn4q7WP>fV?kcSlU{kcsNkg=e#9hAs5agN}9OPm|ngqy?~Fo{f&3cR>=K z115mc<3J`88-w(gLX|j?AkcpYZqyJ=+O*Ykj$_?-Y&mamBPDv)U zHFqwJ9UNLuW2+Qk**~C~!UBn4th+}ckr5bLZ*~at?+Y}x$V5|p1FCaIp`rCHTYt*G zDgSAk|BF~rxfbweb9@-1f!+v~;cPgtzwRkEsVrSsY;}fu#`73|HCw?s_n&siu{(c2 zRkgS24aVP+5GszO0cRJ^-r&zGHQn=NDtNSjfGJLYFk~wQrh{gdI2IKjMJ?cM%I2WQ zD4lRXy#oP;E)NzDdJ6n_{tw;Wx};%0{eIGg9L)3pL-8^2l@;80jQCLlj=$1&jEXU} z$JqeKRGv5(q#m%)wf+cmrpC6b&Uh$6bZ=^Nk~V zR;jpzMf)zW3wTic6L_7Y6HdP7bCY|nEzu@Uc-d=kH!FBJMoFNMYK-X!o->zdZ#B#4 zPHRB1Qank7O?2Nthk@u>F%-AwnPrl<4Ltgq0B_E0VyPqEDrZ1Hl#TWWH2B;^@OZRq zsCq{BtWoK{U+Kcn&-{z}W|*)Aq=5gCv`d(AS2{@JX5WvVdX2A^jqZqg4B2uQ-QfV2 z$MyItY*!Kaci8UyJbj*g>E&A05=!pGL;gfw{C>eqld-k zW1(X3`KKaxNdt6N9aK`h{rn>WG4d3vL-a_JOe56f)X_gbCt~E)s<7~3;X75IvL($5 zQXiq)(+`OKRQsPp6Cl7^ZzB)kZ7K^NLi+se#6v+XGwcc2_d~Uq_C>85NN+O~X~rCn z|0Fqw7JQK^b@XLC^Pnc9v(I=Rb|)hd)Mg$G;iL1({CQ6N+?Me;LUY=hMyV0<&IzW7a)K1qU z25((GwA!gmqtDoobWaWw*l+vyvLlpXlyJde#g+5a(3e}=4tvk316{pL*QwhM4`X6G zf9!AFx?e)195+@p{%ufRjnGXfL6E*&ys3jCb^I|O^@ZXeAes@88BDitL3`fmwtN_A zk!^2Y>F}3wij_n3+1Tu*8&&+Xv~W#|ho%ByT{95h*;du!CM~PO;XtI<`@-NrP-K1J zK!l?$hC=+Zu{NUMK)`;n2_fnT{P;hWge+_n*_t!j{t&|8&x1FJC_SaT=8IA?n~(KhbXYhokzu+`o1| zjy%NM6|!^>MJ$vW^&7mAdvX2VOL1C;EykV2cAAra%Pf_kq8l>qkBo-{Tw&^j9^#Ok z`A4FA?fkHbxVbc@yvql+UdFpUaJAVz!bTEy;{xP*mBm5ojaZwzf@txe&Yjy0a z;tn!fMZ@bU?oO*Z9Kl=+r_!4s#Z7*PBA``1K*GH3ER+9=BW~uXzM~AxnkRxs=&@AO zu%1~tbh2KBF522ReRzOQ=mMS;(7OJq|KiV?yFXmZuZ&9a-1y-3eAff#NN1vEWFm%q zSnPM1gVyhcWuhk@)cAV0j1J+JvE$I&*ePa#mdP>M~Z^hsWYbceCSk z92Rt3hn*ubk?`e!(uTG%N=ks0Ywf50Cx$Y75T9Q|5(%+3zztUo--=<{{6WM=-FB?7{kR9a=-rDUJ<8=3!jp`)rQh=~>92x^ zAyXm9yKbZIDjq98XLP{W|6z_v3~wOirl?x2Q}*g3{+3((8Kx_TLKOI~VyKsb7$mCu zuYwtvLnCqa^Jq9pS1yy+D@DOu0ZU08d`QmSWMSIBaOAq=zPwyo`JIp7@;8Oytddv< zVvsoHVvN5}vADa?Gi+wnUWL%f!xy_Fg11X0a5(1CqV0J5eMxf9NRoXeF&Ud4HoFZO zi@9x(n&;$`U))^o* z+i}=;BZxAHiti=r%8#O)r(QYgqn%$Dih~3fA;WJpkYGr9suKM_3RU3mYXtWe7R(pC_pk!+CGZ5r?o1T8pz_$q-tnBFEfeMm8x04E-_2sKP95 zV#EznzyOh9%;21K;F}{|;tN=bN9~lkPaPV(oFD7p_^+LVRVn`R#)`QA^2QF-nHoH& zZA-lSFDP%lrB*&enKa|65_faz6qJbNl$eXHEmRAmorCr9=$uIM zFfVO@Dyr%SN+r{gSRm!= zA3oigA7qnH#Y-?f3VM~%I7P3DKx;4Z0drCR2kciWYpTq8p|;MJ*Ui<{iyLmDA3c#J zJhkKnkEYxS2Yk_ey`8L7p$X}62=<-fn2-dEA$Bcs0B$%-otRagh1u+A-!6IRKTSFn zKFY2-VCqoJE}u%sr#jS*TAi$37ys%IJq^Xnx>{p!_45D0q|0EW4DYN3nO*3|x1Ln- zDl281TG0>HH$+SUc;Wj=?~yiZ*{0>nix8GsDqB@c(sBy6{s~v3;{g_wHU~B3o$cO{ z>XxACx6yY2;PsOo4{iw6^%lZt$j>!JPLWKf?yU@66M$@n`Bs9_3`^(?66u*#EYK`9 zSX?X16jbKu=pl@?a{iV6;p|ND)qf@IiPX5{@{S>o#^5(^cpC4@T)j$p1q%7Epz2gu zUm_%8<6aJj(J!QKRP8%8g~jn7t<95)AY}gCQr5wF{=pM^0Q9Tiu0xD7Tz$eWKi&m- zV0&X}hJ785$Y3w<`R!jAQifjbe@Dd+YIz4={Bh{macThA#Gi-~Dpf$})(Pcpp<$Iw zh|>A%>VHkl**k?H?qc3YPtp)UEFp?q^{u^4 zb82{v{X^o3FS+1rR4-AZv#LmFf@kGNbsdEFqY`lVo{~h&7)Bx?s{%9WEFKaS%mSt! z$N7#QriPU7_3R4uaJ1}L5TAyIOr2pkk)vp*=ce&K^Cemp>TlwIN&g4(&V!E$QP$kP zXmxlBz{AsqD_cc`k|1DBoUVa??MdpaQ`O)rKzL=OUi)R^r5X3pVTn@aX{gXmc z%RrJW&;_$Nd`A6$BJYFS#RLOxZ>`OU28U_r(t(DQ4InE%tq>=gh=WG|0lL?B9VnvV ze-FYG&)pEOX--I5U92fhB*X|@0Z0?W;LGT^caBIk^D$g@rbu*lh%7~hcp52fE4muT zZ{wWH1qAv18*|6CeBDSW;o(&)j~<0j4EM)&&y$!xRGkxM*B!l^!YdM^pFdZ|W=|ZD z&qC0*m)c7lEgZk2BJtjuNjDuFfXHsQunM~FLNJ)W*=!vRfv{bdu|+d-m*ITXO5?zD zJrp&+55=m!s0xwsisJr*+;dO2WgE5XudQEzb}@~C2d<5Te#~aA2t=0fn8OalX?yJU zD=@ z2UX6QWI9&_)HAR(k)!X9_{EpV5F)GNzaf@fYo0Vrt2lW9e^-!1eqVQxbnE}St2t$S z33=w~loU0MJZI-`>Mo#+7 zy94Oe50s84nD$XaC?OlkgxpAw<+06i%YDj(UJo0MW`WrQPw@V!#2;YbTzepej>Qh! zG}Da{{Vk!!{d%(r68^w~Bp(%VbfsRY9t9TE^q<2U_ zc!Dm`M~)s+?FxxlzsNx@Zi{2aH92vkua82!pB?%Tao#L7|1<*Se(CCE7{J>jKaSXh z>?fg&2*8?n9`h;2``@Vhg7+n%Y0zWekXfw=*kK(%pBG2tR-r!% zC|qP-D*&k8>GsmumOqA58cf&{V_n63>>0P(qN#MMv8Hb=GEsA3UYUc4$GXbTd(NXy_J?gXpc-;If=Yel)WLArfDBD_v65}N zC!S#*RS=DuwVKa5UCWtixf3qLCWM##{{!#JRxPVZdQ^n?hf!U?ghw60ch?->V2xWL z*k65}S}VBFTkUfas~WDv9qc(4dMrn{v1+Kcc6sIKNdr`8 z<7%h$D`U*ZESQe=UV8*ud=9FZeZBsIcKY0N_)}hX6>QyhgmN4o^^K_;)|W^85ECd( zZ0o(P52>nFBIstbzMIjBf9*fP(Eu>$zscrX$lr)nG1}$-f=mAaWB>av6)DgqG8EUt z{>HaUQt3Yb0m;IF(eGJEA<*w}1V^y^b@KR*58OV^#8M)#ryu>jPnWS+fAidb?qJ0` zCgIc=MAM=(iUqlDj6g03cytQ>pP9&9De?lfTav)=%OXY%6hCA=`z$a0X67NjGq#mS55bcu& za$A*_`bBVl1G6~)2{wuBx|@VxX2eLbhmUI+QmI~e4rJ0fbUPDoAtBYkO%sbHlu~m( zQ)Z@C2_oB%Ly^*A4!h?d>!Ro(pGq1vL2ATXAy4;v3e+RKE=2hZBmbbSXHc0bTg^E6 zD`y`3IcqX=8twpCM^T&jicLbjaT8z=+O6&yqA~|t4D>) zNdT8at@2yP;I8j zZQ{H(c(#tB5pm95O9*i!A*-8I#Y?{ilvwM_aLhM}Qm0%9K@VQpfA1>gp|;(@D2#}epf1K>vY&y!iYon3hbrxs|7UJ& zg`aE{`!l|0%MpYfeRT^*{L%5rlWTmQ!cHu|BqC~&CZGv8;c_7gpD(3!ej-M~>!|x&x8?sgiKC+1KL=>FObc@gF_$~0ZIQwF&k@a)NiOE;@MYmkAzH|PlZu05*LKDI^&3pZEN)&fM zY|HB|)k9%Ari;oslPvFhyo#Lo(({$3C_|(E8NKJ`o3pM@pLgNZRdbiSdn6;je&6j@ z_0{H0NR8-f1*2@E(@5i~n1ihLz1h%V*Sf27ez#4WT~wb@a(c17*|!;2=S}}_X<7R1 zmhNw_XYY@1ny~WUnn}$6&(~LdJNfNo{l2b;H-#?mPCfA96?F64gtA+Ejl)k??9+bt zYQsAF`*~~g=HKtSBgXbe_JVHaLw(PkW#SAMO3w;k*9ouZjCa_|RsKw5#j#`0?ltDV zoKh(Th}^59z_n_*!xkprv=E{-pMHVU%dNp1rU z(*nm@H|HJ1GQhgw`r!_yJ0Bqf$2B0vf6lT$Tr=OlcFtJuCbC3%)9&20ch?oXbQUZh z9cLXKXC+~rwQPn+`^KJAhqJT~Mr85#{;J#{@>3SP9WN_BW5wI1r8>8~I;S5hSh-ZH zNZ>g&bpS9_vre*8{c*3w^J>{iyu7*TXMJOAXZ=-3CY z&tpFB-}Yb?gZ2hnX6pkYSL`BQ9hH%3+Pi8-i|oe;`Lu@%oOHS~Ef$D)C&_J#I9Jx$ z*`cdlK@|rd9+P1f0D`bKR^Bd%R6cBv$fmF!T1.26.0-SNAPSHOT 4.0.0 - microservices-aggregrator + microservices-self-registration pom eurekaserver From d06d61e7557ecdb723998d43ddd9a09a0caa1ffc Mon Sep 17 00:00:00 2001 From: Naman Srivastava Date: Fri, 11 Apr 2025 18:03:37 +0530 Subject: [PATCH 08/16] POM file updated for self-registration --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index fb0bfd7565e1..48bcd69d6300 100644 --- a/pom.xml +++ b/pom.xml @@ -166,6 +166,7 @@ microservices-distributed-tracing microservices-idempotent-consumer microservices-log-aggregation + microservices-self-registration model-view-controller model-view-intent model-view-presenter From aa788f0541eac01e24be7fa9d0b18fb8d1513d3b Mon Sep 17 00:00:00 2001 From: Naman Srivastava Date: Fri, 11 Apr 2025 18:05:07 +0530 Subject: [PATCH 09/16] pom file updated --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 48bcd69d6300..43b76c34a57d 100644 --- a/pom.xml +++ b/pom.xml @@ -166,7 +166,7 @@ microservices-distributed-tracing microservices-idempotent-consumer microservices-log-aggregation - microservices-self-registration + microservices-self-registration-registration model-view-controller model-view-intent model-view-presenter From b47a00eb79fa3e356ba75abc1e45540bfdda254a Mon Sep 17 00:00:00 2001 From: naman-sriv <82610773+naman-sriv@users.noreply.github.com> Date: Fri, 11 Apr 2025 18:08:42 +0530 Subject: [PATCH 10/16] Update pom.xml correction to mudule name --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 43b76c34a57d..48bcd69d6300 100644 --- a/pom.xml +++ b/pom.xml @@ -166,7 +166,7 @@ microservices-distributed-tracing microservices-idempotent-consumer microservices-log-aggregation - microservices-self-registration-registration + microservices-self-registration model-view-controller model-view-intent model-view-presenter From 6b1c680714aa8a6cc812f85a827b4b8ddc614da0 Mon Sep 17 00:00:00 2001 From: Naman Srivastava Date: Fri, 11 Apr 2025 18:50:58 +0530 Subject: [PATCH 11/16] SonarQube comments addressed --- .../contextservice/controller/ContextController.java | 11 +++++++---- .../contextservice/ContextControllerTest.java | 6 +----- .../ContextserviceApplicationTests.java | 4 ++++ .../eurekaserver/EurekaserverApplicationTests.java | 4 ++++ .../greetingservice/GreetingControllerTest.java | 2 +- .../GreetingserviceApplicationTests.java | 4 ++++ pom.xml | 2 +- 7 files changed, 22 insertions(+), 11 deletions(-) diff --git a/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/controller/ContextController.java b/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/controller/ContextController.java index de84a01b1ea6..5ad8969e0871 100644 --- a/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/controller/ContextController.java +++ b/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/controller/ContextController.java @@ -9,11 +9,14 @@ @RestController public class ContextController { - @Autowired - private GreetingServiceClient greetingServiceClient; + private final GreetingServiceClient greetingServiceClient; + private final String userRegion; - @Value("${user.region}") - private String userRegion; + @Autowired + public ContextController(GreetingServiceClient greetingServiceClient, @Value("${user.region}") String userRegion) { + this.greetingServiceClient = greetingServiceClient; + this.userRegion = userRegion; + } @GetMapping("/context") public String getContext() { diff --git a/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/ContextControllerTest.java b/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/ContextControllerTest.java index 75c303ecec75..6b572b673fc7 100644 --- a/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/ContextControllerTest.java +++ b/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/ContextControllerTest.java @@ -2,15 +2,11 @@ import com.learning.contextservice.client.GreetingServiceClient; import com.learning.contextservice.controller.ContextController; -import com.netflix.discovery.converters.Auto; import org.junit.jupiter.api.Test; -import org.mockito.Mock; import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.cloud.openfeign.FeignAutoConfiguration; -import org.springframework.context.annotation.Import; import org.springframework.http.MediaType; import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.web.servlet.MockMvc; @@ -18,7 +14,7 @@ import org.springframework.test.web.servlet.result.MockMvcResultMatchers; @WebMvcTest(ContextController.class) -public class ContextControllerTest { +class ContextControllerTest { @Autowired private MockMvc mockMvc; diff --git a/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/ContextserviceApplicationTests.java b/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/ContextserviceApplicationTests.java index 92acfc686dcb..a5d5c869c664 100644 --- a/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/ContextserviceApplicationTests.java +++ b/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/ContextserviceApplicationTests.java @@ -8,6 +8,10 @@ class ContextserviceApplicationTests { @Test void contextLoads() { + // This is a basic integration test that checks if the Spring Application Context loads successfully. + // If the context loads without any exceptions, the test is considered passing. + // It is often left empty as the act of loading the context is the primary verification. + // You can add specific assertions here if you want to verify the presence or state of certain beans. } } diff --git a/microservices-self-registration/eurekaserver/src/test/java/com/learning/eurekaserver/EurekaserverApplicationTests.java b/microservices-self-registration/eurekaserver/src/test/java/com/learning/eurekaserver/EurekaserverApplicationTests.java index acb8cc911159..b5150fefa940 100644 --- a/microservices-self-registration/eurekaserver/src/test/java/com/learning/eurekaserver/EurekaserverApplicationTests.java +++ b/microservices-self-registration/eurekaserver/src/test/java/com/learning/eurekaserver/EurekaserverApplicationTests.java @@ -8,6 +8,10 @@ class EurekaserverApplicationTests { @Test void contextLoads() { + // This is a basic integration test that checks if the Spring Application Context loads successfully. + // If the context loads without any exceptions, the test is considered passing. + // It is often left empty as the act of loading the context is the primary verification. + // You can add specific assertions here if you want to verify the presence or state of certain beans. } } diff --git a/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/GreetingControllerTest.java b/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/GreetingControllerTest.java index 042d1fe8e67a..392dc760fa95 100644 --- a/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/GreetingControllerTest.java +++ b/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/GreetingControllerTest.java @@ -9,7 +9,7 @@ import org.springframework.test.web.servlet.result.MockMvcResultMatchers; @WebMvcTest(GreetingsController.class) -public class GreetingControllerTest { +class GreetingControllerTest { @Autowired private MockMvc mockMvc; diff --git a/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/GreetingserviceApplicationTests.java b/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/GreetingserviceApplicationTests.java index 586ae35fcb73..945898278aa9 100644 --- a/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/GreetingserviceApplicationTests.java +++ b/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/GreetingserviceApplicationTests.java @@ -8,6 +8,10 @@ class GreetingserviceApplicationTests { @Test void contextLoads() { + // This is a basic integration test that checks if the Spring Application Context loads successfully. + // If the context loads without any exceptions, the test is considered passing. + // It is often left empty as the act of loading the context is the primary verification. + // You can add specific assertions here if you want to verify the presence or state of certain beans. } } diff --git a/pom.xml b/pom.xml index 43b76c34a57d..48bcd69d6300 100644 --- a/pom.xml +++ b/pom.xml @@ -166,7 +166,7 @@ microservices-distributed-tracing microservices-idempotent-consumer microservices-log-aggregation - microservices-self-registration-registration + microservices-self-registration model-view-controller model-view-intent model-view-presenter From ab2c8ac34bf509e7d5a2570590149f188648b78b Mon Sep 17 00:00:00 2001 From: Naman Srivastava Date: Fri, 11 Apr 2025 19:18:00 +0530 Subject: [PATCH 12/16] sonarqube comments on coverage addressed --- .../application.log.2025-04-09.0.gz | Bin 0 -> 5525 bytes .../contextservice/ContextControllerTest.java | 15 ++++++++++++++- .../learning/contextservice/TestConfig.java | 17 +++++++++++++++++ .../GreetingControllerTest.java | 12 +++++++++++- 4 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 microservices-self-registration/application.log.2025-04-09.0.gz create mode 100644 microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/TestConfig.java diff --git a/microservices-self-registration/application.log.2025-04-09.0.gz b/microservices-self-registration/application.log.2025-04-09.0.gz new file mode 100644 index 0000000000000000000000000000000000000000..d51965d73d7a6d06bba18c80c7aeedb468916013 GIT binary patch literal 5525 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 literal 0 HcmV?d00001 diff --git a/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/ContextControllerTest.java b/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/ContextControllerTest.java index 6b572b673fc7..4eacbf4e586d 100644 --- a/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/ContextControllerTest.java +++ b/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/ContextControllerTest.java @@ -2,18 +2,24 @@ import com.learning.contextservice.client.GreetingServiceClient; import com.learning.contextservice.controller.ContextController; +import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Import; import org.springframework.http.MediaType; import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.result.MockMvcResultMatchers; -@WebMvcTest(ContextController.class) +@SpringBootTest(classes = ContextserviceApplication.class) +@AutoConfigureMockMvc +@Import(TestConfig.class) class ContextControllerTest { @Autowired @@ -34,4 +40,11 @@ void shouldReturnContextGreeting() throws Exception{ .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().string("The Greeting Service says: Mocked Hello from Chennai, Tamil Nadu, India")); } + + @Test + void shouldReturnContextServiceHealthStatusUp() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/actuator/health")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().string(Matchers.containsString("\"status\":\"UP\""))); + } } diff --git a/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/TestConfig.java b/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/TestConfig.java new file mode 100644 index 000000000000..f378f46f59df --- /dev/null +++ b/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/TestConfig.java @@ -0,0 +1,17 @@ +package com.learning.contextservice; + +import com.learning.contextservice.client.GreetingServiceClient; +import org.mockito.Mockito; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class TestConfig { + + @Bean + public GreetingServiceClient greetingServiceClient() { + GreetingServiceClient mockClient = Mockito.mock(GreetingServiceClient.class); + Mockito.when(mockClient.getGreeting()).thenReturn("Mocked Hello"); + return mockClient; + } +} diff --git a/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/GreetingControllerTest.java b/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/GreetingControllerTest.java index 392dc760fa95..dc96b9dd7edd 100644 --- a/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/GreetingControllerTest.java +++ b/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/GreetingControllerTest.java @@ -2,13 +2,16 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.result.MockMvcResultMatchers; -@WebMvcTest(GreetingsController.class) +@SpringBootTest(classes = GreetingserviceApplication.class) +@AutoConfigureMockMvc class GreetingControllerTest { @Autowired @@ -21,4 +24,11 @@ void shouldReturnGreeting() throws Exception{ .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().string("Hello")); } + + @Test + void shouldReturnHealthStatusUp() throws Exception{ + mockMvc.perform(MockMvcRequestBuilders.get("/actuator/health")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().string(org.hamcrest.Matchers.containsString("\"status\":\"UP\""))); + } } From c4b33cd296bdd4cfb904d0c08c181ba7568fc6ca Mon Sep 17 00:00:00 2001 From: Naman Srivastava Date: Fri, 11 Apr 2025 21:56:08 +0530 Subject: [PATCH 13/16] Code coverage for custom health checks --- .../myCustomHealthCheckTest.java | 66 +++++++++++++++++++ .../MyCustomHealthCheckTest.java | 66 +++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/myCustomHealthCheckTest.java create mode 100644 microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/MyCustomHealthCheckTest.java diff --git a/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/myCustomHealthCheckTest.java b/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/myCustomHealthCheckTest.java new file mode 100644 index 000000000000..032d254383f8 --- /dev/null +++ b/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/myCustomHealthCheckTest.java @@ -0,0 +1,66 @@ +package com.learning.contextservice; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.actuate.health.Health; +import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.boot.actuate.health.Status; + +import java.util.function.BooleanSupplier; + +import static org.junit.jupiter.api.Assertions.*; + +class MyCustomHealthCheckTest { + + @Test + void testHealthUp() { + MyCustomHealthCheck healthCheck = new MyCustomHealthCheck(); + // Simulate a healthy state + ReflectionTestUtils.setField(healthCheck, "isHealthy", true); + Health health = healthCheck.health(); + assertEquals(Status.UP, health.getStatus()); + assertTrue(health.getDetails().containsKey("message")); + assertEquals("Service is running and scheduled checks are OK", health.getDetails().get("message")); + } + + @Test + void testHealthDown() { + MyCustomHealthCheck healthCheck = new MyCustomHealthCheck(); + // Simulate an unhealthy state + ReflectionTestUtils.setField(healthCheck, "isHealthy", false); + Health health = healthCheck.health(); + assertEquals(Status.DOWN, health.getStatus()); + assertTrue(health.getDetails().containsKey("error")); + assertEquals("Scheduled health checks failed", health.getDetails().get("error")); + } + + @Test + void testUpdateHealthStatusSetsIsHealthy() throws Exception { + MyCustomHealthCheck healthCheck = new MyCustomHealthCheck(); + + // Force performHealthCheck to return true (by time simulation - might be flaky) + long currentTimeForTrue = System.currentTimeMillis(); + while (currentTimeForTrue % 10000 >= 5000) { + Thread.sleep(10); // Wait until time is in the "true" range + currentTimeForTrue = System.currentTimeMillis(); + } + ReflectionTestUtils.invokeMethod(healthCheck, "performHealthCheck"); + healthCheck.updateHealthStatus(); + assertTrue((Boolean) ReflectionTestUtils.getField(healthCheck, "isHealthy"), "Health should be true"); + + // Force performHealthCheck to return false (by time simulation - might be flaky) + long currentTimeForFalse = System.currentTimeMillis(); + while (currentTimeForFalse % 10000 < 5000) { + Thread.sleep(10); // Wait until time is in the "false" range + currentTimeForFalse = System.currentTimeMillis(); + } + ReflectionTestUtils.invokeMethod(healthCheck, "performHealthCheck"); + healthCheck.updateHealthStatus(); + assertFalse((Boolean) ReflectionTestUtils.getField(healthCheck, "isHealthy"), "Health should be false"); + } + + // Note: Directly testing performHealthCheck (the private method) based on time is inherently + // difficult and can lead to flaky tests. The testUpdateHealthStatus attempts to indirectly + // verify its behavior. For more robust testing of performHealthCheck in isolation, + // you might consider refactoring the class to make the time dependency injectable + // or making the method protected for testing purposes. +} \ No newline at end of file diff --git a/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/MyCustomHealthCheckTest.java b/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/MyCustomHealthCheckTest.java new file mode 100644 index 000000000000..c92f1bee31fe --- /dev/null +++ b/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/MyCustomHealthCheckTest.java @@ -0,0 +1,66 @@ +package com.learning.greetingservice; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.actuate.health.Health; +import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.boot.actuate.health.Status; + +import java.util.function.BooleanSupplier; + +import static org.junit.jupiter.api.Assertions.*; + +class MyCustomHealthCheckTest { + + @Test + void testHealthUp() { + MyCustomHealthCheck healthCheck = new MyCustomHealthCheck(); + // Simulate a healthy state + ReflectionTestUtils.setField(healthCheck, "isHealthy", true); + Health health = healthCheck.health(); + assertEquals(Status.UP, health.getStatus()); + assertTrue(health.getDetails().containsKey("message")); + assertEquals("Service is running and scheduled checks are OK", health.getDetails().get("message")); + } + + @Test + void testHealthDown() { + MyCustomHealthCheck healthCheck = new MyCustomHealthCheck(); + // Simulate an unhealthy state + ReflectionTestUtils.setField(healthCheck, "isHealthy", false); + Health health = healthCheck.health(); + assertEquals(Status.DOWN, health.getStatus()); + assertTrue(health.getDetails().containsKey("error")); + assertEquals("Scheduled health checks failed", health.getDetails().get("error")); + } + + @Test + void testUpdateHealthStatusSetsIsHealthy() throws Exception { + MyCustomHealthCheck healthCheck = new MyCustomHealthCheck(); + + // Force performHealthCheck to return true (by time simulation - might be flaky) + long currentTimeForTrue = System.currentTimeMillis(); + while (currentTimeForTrue % 10000 >= 5000) { + Thread.sleep(10); // Wait until time is in the "true" range + currentTimeForTrue = System.currentTimeMillis(); + } + ReflectionTestUtils.invokeMethod(healthCheck, "performHealthCheck"); + healthCheck.updateHealthStatus(); + assertTrue((Boolean) ReflectionTestUtils.getField(healthCheck, "isHealthy"), "Health should be true"); + + // Force performHealthCheck to return false (by time simulation - might be flaky) + long currentTimeForFalse = System.currentTimeMillis(); + while (currentTimeForFalse % 10000 < 5000) { + Thread.sleep(10); // Wait until time is in the "false" range + currentTimeForFalse = System.currentTimeMillis(); + } + ReflectionTestUtils.invokeMethod(healthCheck, "performHealthCheck"); + healthCheck.updateHealthStatus(); + assertFalse((Boolean) ReflectionTestUtils.getField(healthCheck, "isHealthy"), "Health should be false"); + } + + // Note: Directly testing performHealthCheck (the private method) based on time is inherently + // difficult and can lead to flaky tests. The testUpdateHealthStatus attempts to indirectly + // verify its behavior. For more robust testing of performHealthCheck in isolation, + // you might consider refactoring the class to make the time dependency injectable + // or making the method protected for testing purposes. +} \ No newline at end of file From edb73c15ab3a6c3855b1f94b84f23841b986d909 Mon Sep 17 00:00:00 2001 From: Naman Srivastava Date: Fri, 11 Apr 2025 22:22:58 +0530 Subject: [PATCH 14/16] changes for unit tests --- .../contextservice/MyCustomHealthCheck.java | 3 +- .../myCustomHealthCheckTest.java | 39 +++++++------------ .../eurekaserver/pom.xml | 1 - .../greetingservice/MyCustomHealthCheck.java | 2 +- .../MyCustomHealthCheckTest.java | 36 ++++++----------- 5 files changed, 30 insertions(+), 51 deletions(-) diff --git a/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/MyCustomHealthCheck.java b/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/MyCustomHealthCheck.java index d62955c775db..22ecac5d27a1 100644 --- a/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/MyCustomHealthCheck.java +++ b/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/MyCustomHealthCheck.java @@ -6,6 +6,7 @@ import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; +import java.time.Clock; @Component("myCustomHealthCheck") public class MyCustomHealthCheck implements HealthIndicator { @@ -22,7 +23,7 @@ public void updateHealthStatus() { log.info("Update health status : {}", isHealthy); } - private boolean performHealthCheck() { + boolean performHealthCheck() { boolean current = System.currentTimeMillis() % 10000 < 5000; // Simulate fluctuating health log.debug("Performing health check, current status: {}", current); return current; // Simulate fluctuating health diff --git a/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/myCustomHealthCheckTest.java b/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/myCustomHealthCheckTest.java index 032d254383f8..3a7256e65442 100644 --- a/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/myCustomHealthCheckTest.java +++ b/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/myCustomHealthCheckTest.java @@ -1,16 +1,23 @@ package com.learning.contextservice; import org.junit.jupiter.api.Test; +import org.mockito.Mockito; import org.springframework.boot.actuate.health.Health; import org.springframework.test.util.ReflectionTestUtils; import org.springframework.boot.actuate.health.Status; +import java.time.Clock; +import java.time.Instant; +import java.time.ZoneId; import java.util.function.BooleanSupplier; import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.doReturn; class MyCustomHealthCheckTest { + MyCustomHealthCheck healthCheck = new MyCustomHealthCheck(); + @Test void testHealthUp() { MyCustomHealthCheck healthCheck = new MyCustomHealthCheck(); @@ -34,33 +41,17 @@ void testHealthDown() { } @Test - void testUpdateHealthStatusSetsIsHealthy() throws Exception { - MyCustomHealthCheck healthCheck = new MyCustomHealthCheck(); + void testUpdateHealthStatusSetsIsHealthyWithMocking() throws Exception { + MyCustomHealthCheck healthCheck = Mockito.spy(new MyCustomHealthCheck()); - // Force performHealthCheck to return true (by time simulation - might be flaky) - long currentTimeForTrue = System.currentTimeMillis(); - while (currentTimeForTrue % 10000 >= 5000) { - Thread.sleep(10); // Wait until time is in the "true" range - currentTimeForTrue = System.currentTimeMillis(); - } - ReflectionTestUtils.invokeMethod(healthCheck, "performHealthCheck"); + // Force performHealthCheck to return true + doReturn(true).when(healthCheck).performHealthCheck(); healthCheck.updateHealthStatus(); - assertTrue((Boolean) ReflectionTestUtils.getField(healthCheck, "isHealthy"), "Health should be true"); + assertTrue((Boolean)ReflectionTestUtils.getField(healthCheck, "isHealthy"), "Health should be true"); - // Force performHealthCheck to return false (by time simulation - might be flaky) - long currentTimeForFalse = System.currentTimeMillis(); - while (currentTimeForFalse % 10000 < 5000) { - Thread.sleep(10); // Wait until time is in the "false" range - currentTimeForFalse = System.currentTimeMillis(); - } - ReflectionTestUtils.invokeMethod(healthCheck, "performHealthCheck"); + // Force performHealthCheck to return false + doReturn(false).when(healthCheck).performHealthCheck(); healthCheck.updateHealthStatus(); - assertFalse((Boolean) ReflectionTestUtils.getField(healthCheck, "isHealthy"), "Health should be false"); + assertFalse((Boolean)ReflectionTestUtils.getField(healthCheck, "isHealthy"), "Health should be false"); } - - // Note: Directly testing performHealthCheck (the private method) based on time is inherently - // difficult and can lead to flaky tests. The testUpdateHealthStatus attempts to indirectly - // verify its behavior. For more robust testing of performHealthCheck in isolation, - // you might consider refactoring the class to make the time dependency injectable - // or making the method protected for testing purposes. } \ No newline at end of file diff --git a/microservices-self-registration/eurekaserver/pom.xml b/microservices-self-registration/eurekaserver/pom.xml index 7e5794f651a7..b1a4b26cf4f4 100644 --- a/microservices-self-registration/eurekaserver/pom.xml +++ b/microservices-self-registration/eurekaserver/pom.xml @@ -21,7 +21,6 @@ org.springframework.cloud spring-cloud-starter-netflix-eureka-server - org.springframework.boot spring-boot-starter-test diff --git a/microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/MyCustomHealthCheck.java b/microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/MyCustomHealthCheck.java index 4c5f6ac9daad..218a4ad002d4 100644 --- a/microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/MyCustomHealthCheck.java +++ b/microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/MyCustomHealthCheck.java @@ -22,7 +22,7 @@ public void updateHealthStatus() { log.info("Update health status : {}", isHealthy); } - private boolean performHealthCheck() { + boolean performHealthCheck() { boolean current = System.currentTimeMillis() % 10000 < 5000; // Simulate fluctuating health log.debug("Performing health check, current status: {}", current); return current; // Simulate fluctuating health diff --git a/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/MyCustomHealthCheckTest.java b/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/MyCustomHealthCheckTest.java index c92f1bee31fe..350dda59f0a5 100644 --- a/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/MyCustomHealthCheckTest.java +++ b/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/MyCustomHealthCheckTest.java @@ -1,6 +1,7 @@ package com.learning.greetingservice; import org.junit.jupiter.api.Test; +import org.mockito.Mockito; import org.springframework.boot.actuate.health.Health; import org.springframework.test.util.ReflectionTestUtils; import org.springframework.boot.actuate.health.Status; @@ -8,6 +9,7 @@ import java.util.function.BooleanSupplier; import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.doReturn; class MyCustomHealthCheckTest { @@ -34,33 +36,19 @@ void testHealthDown() { } @Test - void testUpdateHealthStatusSetsIsHealthy() throws Exception { - MyCustomHealthCheck healthCheck = new MyCustomHealthCheck(); + void testUpdateHealthStatusSetsIsHealthyWithMocking() throws Exception { + MyCustomHealthCheck healthCheck = Mockito.spy(new MyCustomHealthCheck()); - // Force performHealthCheck to return true (by time simulation - might be flaky) - long currentTimeForTrue = System.currentTimeMillis(); - while (currentTimeForTrue % 10000 >= 5000) { - Thread.sleep(10); // Wait until time is in the "true" range - currentTimeForTrue = System.currentTimeMillis(); - } - ReflectionTestUtils.invokeMethod(healthCheck, "performHealthCheck"); + // Force performHealthCheck to return true + doReturn(true).when(healthCheck).performHealthCheck(); healthCheck.updateHealthStatus(); - assertTrue((Boolean) ReflectionTestUtils.getField(healthCheck, "isHealthy"), "Health should be true"); + assertTrue((Boolean) ReflectionTestUtils.getField(healthCheck, "isHealthy"), + "Health should be true"); - // Force performHealthCheck to return false (by time simulation - might be flaky) - long currentTimeForFalse = System.currentTimeMillis(); - while (currentTimeForFalse % 10000 < 5000) { - Thread.sleep(10); // Wait until time is in the "false" range - currentTimeForFalse = System.currentTimeMillis(); - } - ReflectionTestUtils.invokeMethod(healthCheck, "performHealthCheck"); + // Force performHealthCheck to return false + doReturn(false).when(healthCheck).performHealthCheck(); healthCheck.updateHealthStatus(); - assertFalse((Boolean) ReflectionTestUtils.getField(healthCheck, "isHealthy"), "Health should be false"); + assertFalse((Boolean) ReflectionTestUtils.getField(healthCheck, "isHealthy"), + "Health should be false"); } - - // Note: Directly testing performHealthCheck (the private method) based on time is inherently - // difficult and can lead to flaky tests. The testUpdateHealthStatus attempts to indirectly - // verify its behavior. For more robust testing of performHealthCheck in isolation, - // you might consider refactoring the class to make the time dependency injectable - // or making the method protected for testing purposes. } \ No newline at end of file From 84b66761273be0cc96ee637841e9767bce8b329b Mon Sep 17 00:00:00 2001 From: Naman Srivastava Date: Fri, 11 Apr 2025 22:57:55 +0530 Subject: [PATCH 15/16] changes for unit tests --- .../myCustomHealthCheckTest.java | 14 ---------- .../MyCustomHealthCheckTest.java | 27 ------------------- 2 files changed, 41 deletions(-) diff --git a/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/myCustomHealthCheckTest.java b/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/myCustomHealthCheckTest.java index 3a7256e65442..eb26eba89f41 100644 --- a/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/myCustomHealthCheckTest.java +++ b/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/myCustomHealthCheckTest.java @@ -40,18 +40,4 @@ void testHealthDown() { assertEquals("Scheduled health checks failed", health.getDetails().get("error")); } - @Test - void testUpdateHealthStatusSetsIsHealthyWithMocking() throws Exception { - MyCustomHealthCheck healthCheck = Mockito.spy(new MyCustomHealthCheck()); - - // Force performHealthCheck to return true - doReturn(true).when(healthCheck).performHealthCheck(); - healthCheck.updateHealthStatus(); - assertTrue((Boolean)ReflectionTestUtils.getField(healthCheck, "isHealthy"), "Health should be true"); - - // Force performHealthCheck to return false - doReturn(false).when(healthCheck).performHealthCheck(); - healthCheck.updateHealthStatus(); - assertFalse((Boolean)ReflectionTestUtils.getField(healthCheck, "isHealthy"), "Health should be false"); - } } \ No newline at end of file diff --git a/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/MyCustomHealthCheckTest.java b/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/MyCustomHealthCheckTest.java index 350dda59f0a5..645c0c51189e 100644 --- a/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/MyCustomHealthCheckTest.java +++ b/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/MyCustomHealthCheckTest.java @@ -24,31 +24,4 @@ void testHealthUp() { assertEquals("Service is running and scheduled checks are OK", health.getDetails().get("message")); } - @Test - void testHealthDown() { - MyCustomHealthCheck healthCheck = new MyCustomHealthCheck(); - // Simulate an unhealthy state - ReflectionTestUtils.setField(healthCheck, "isHealthy", false); - Health health = healthCheck.health(); - assertEquals(Status.DOWN, health.getStatus()); - assertTrue(health.getDetails().containsKey("error")); - assertEquals("Scheduled health checks failed", health.getDetails().get("error")); - } - - @Test - void testUpdateHealthStatusSetsIsHealthyWithMocking() throws Exception { - MyCustomHealthCheck healthCheck = Mockito.spy(new MyCustomHealthCheck()); - - // Force performHealthCheck to return true - doReturn(true).when(healthCheck).performHealthCheck(); - healthCheck.updateHealthStatus(); - assertTrue((Boolean) ReflectionTestUtils.getField(healthCheck, "isHealthy"), - "Health should be true"); - - // Force performHealthCheck to return false - doReturn(false).when(healthCheck).performHealthCheck(); - healthCheck.updateHealthStatus(); - assertFalse((Boolean) ReflectionTestUtils.getField(healthCheck, "isHealthy"), - "Health should be false"); - } } \ No newline at end of file From fcf605d18e2c12f3eaf3295c5cd77369ed90eada Mon Sep 17 00:00:00 2001 From: Naman Srivastava Date: Sat, 12 Apr 2025 00:04:56 +0530 Subject: [PATCH 16/16] changes to for code coverage improvement --- .../contextservice/MyCustomHealthCheck.java | 2 +- .../client/GreetingServiceClient.java | 2 +- .../contextservice/ContextControllerTest.java | 3 +-- .../myCustomHealthCheckTest.java | 10 ---------- .../application.log.2025-04-11.0.gz | Bin 0 -> 121657 bytes .../GreetingserviceApplication.java | 2 ++ .../{ => controller}/GreetingsController.java | 4 ++-- .../MyCustomHealthCheckTest.java | 5 ----- .../GreetingControllerTest.java | 6 ++++-- 9 files changed, 11 insertions(+), 23 deletions(-) create mode 100644 microservices-self-registration/greetingservice/application.log.2025-04-11.0.gz rename microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/{ => controller}/GreetingsController.java (73%) rename microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/{ => controller}/GreetingControllerTest.java (86%) diff --git a/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/MyCustomHealthCheck.java b/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/MyCustomHealthCheck.java index 22ecac5d27a1..0226fc50e803 100644 --- a/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/MyCustomHealthCheck.java +++ b/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/MyCustomHealthCheck.java @@ -6,7 +6,7 @@ import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; -import java.time.Clock; + @Component("myCustomHealthCheck") public class MyCustomHealthCheck implements HealthIndicator { diff --git a/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/client/GreetingServiceClient.java b/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/client/GreetingServiceClient.java index a0321da4b627..367a3bdd496c 100644 --- a/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/client/GreetingServiceClient.java +++ b/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/client/GreetingServiceClient.java @@ -3,7 +3,7 @@ import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; -@FeignClient(name="greetingservice") +@FeignClient(name = "greetingservice") public interface GreetingServiceClient { @GetMapping("/greeting") diff --git a/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/ContextControllerTest.java b/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/ContextControllerTest.java index 4eacbf4e586d..f11da867cda0 100644 --- a/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/ContextControllerTest.java +++ b/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/ContextControllerTest.java @@ -1,14 +1,13 @@ package com.learning.contextservice; import com.learning.contextservice.client.GreetingServiceClient; -import com.learning.contextservice.controller.ContextController; import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; + import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Import; import org.springframework.http.MediaType; diff --git a/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/myCustomHealthCheckTest.java b/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/myCustomHealthCheckTest.java index eb26eba89f41..129209469827 100644 --- a/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/myCustomHealthCheckTest.java +++ b/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/myCustomHealthCheckTest.java @@ -1,23 +1,13 @@ package com.learning.contextservice; import org.junit.jupiter.api.Test; -import org.mockito.Mockito; import org.springframework.boot.actuate.health.Health; import org.springframework.test.util.ReflectionTestUtils; import org.springframework.boot.actuate.health.Status; - -import java.time.Clock; -import java.time.Instant; -import java.time.ZoneId; -import java.util.function.BooleanSupplier; - import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.doReturn; class MyCustomHealthCheckTest { - MyCustomHealthCheck healthCheck = new MyCustomHealthCheck(); - @Test void testHealthUp() { MyCustomHealthCheck healthCheck = new MyCustomHealthCheck(); diff --git a/microservices-self-registration/greetingservice/application.log.2025-04-11.0.gz b/microservices-self-registration/greetingservice/application.log.2025-04-11.0.gz new file mode 100644 index 0000000000000000000000000000000000000000..62d73c3020c17289baf7a40eb622f4d950b5a784 GIT binary patch literal 121657 zcmc$`V~{29nz!3sc6HgdZQEV8-DTT0yKLLGZQHiZxBHKoJu`d9*(c_WbJmB1?UnN`CJqxAO%8{QZW(__R8fK`GKXnobr@J7%wAg36P~?Kj zqg!f~cn`m$0xRu3ZA>Y zbjZn?KE9*pXuOOfy@9_kh6L!X!@Ai7QT75P3m;Su5{N3upb{}i9)-wn)(Xt{bAu9) z5_YfL%49R};A-YtJ>&}*>D-NZYHkzgLy)&$aq{S`d<`+0(6Dcc>M)$$lGtm)lRsLi z2S@a$gPS&qgNh(~H5wOTNp4X>orwm=&@EpAyqTTTMyIX^C<}=}Aeqj1@~Bp8o`{OwGr z__Rr`NRrLFUD-{CelRgD(uejRxh6p$nGXfYx^?c^4$%cQ>z8$K4+3bp?F^l=$4k_WMXKZJ!_NlX7~J@X*)l=)aPrn4@gr!?WH$d z%t}}c-OADBY5#a3xi3)~#*gStm5O~S6Kj)kqq*xNWzuwtEnV0MR96J<{FrGHiC5K0{5C(PmsboE`U)QB z?vC7x1Przw(Jbg0#PFfazt?pU5e`+NuUxX#=jTt~vsKA+5-FJit4rcytV zlnEzCY3(M}n`3OUrWNCiMMTegBCAM*GBG+^6zs?o6xf7BeHywTpFpu@0VLu1!*!6F zHf(?I7)jSfi+iR}&S<~EqIo%T-sC?b>44OvdVs9(RDUi@AhU4QlpYQ(kfx*IST?0w&l<#yL5iIs*?PguE0{_3-hGSzUA z)-6!x;9=+Bp||i6_$K0n#!<)g<_Du)`X&?yc9yVZk?k{mM-P(E&QRRVjyIN({`<5#ThR+Fic{X;YQqN9i9nvZOKZijwO zyj@>fFs_Xdsgyz{KtvG9&$oR7gx5I>Sy?3M7{82W#!?by-*N~&dlve@_UGulpRM>h zWlyP%DugL)R+dxGxasP4i><0G=6SK{{2ZpdN;L0*4+LtS=A|~TZ0%J`Sgiy5XwPl{ zoMl1YUAP-0RqNl;yZ!Jo)8L=lJhC6J6ZPwY4ex76@7(_`#CiLk3TCMd@c1?l5S;#g z<##Gg<+L3%z5Iif)@!T&Wt*qc=PZsM_Ux?}Hj~W+fOA88-B*~^_>Su%Cl7G6=qjjl zYi9n|x*y_admZO9+4H;KG8($YQ|5DuId;S3%qN4Fk1Q~DY`V%~O>a#}J2#)?3qX=KGy+IoAG4qOLUK`5 zrT!5#T+m%8Il!(aMxi^g=jLl@Z}r?LtDSo3$s?oHIXHf~y)l`J7FJYYaE2=u^9w#?QUTAd@c;yw-!e;2ANX6Mc zWnZ_>tLCx9)pH-)AAplSr}>nNI*a^&xR<}D*Yo%^gOH1!^Pi(6ZY8)_-;7K)=Z3c# zOK-Woz$C!2^nh9%jN0s+XS4)9S1yT*N!fAAq?W#kc=c+AbdH+bOFCRu3Y5;C;zTR8 zULX!LKRBx!qnUT=P=e&PV9qd7FT`XnznHIG5j_peT=_2h!Kb*+D$MNiJ95|@_GN-t zI=^3)zK>h`H|lzG9QUjNjP#QoXfvukJwzoKxAq|TYh5@$ez2@4#09sWFjKsZ0#}l6 z_jX2^gleC?e#qocaX<(xC0%tvtiH-Ec!O_X3@FB6yRQJC_t@f%GRfCXx;9SFMS)(k8@j+yWDJW!r4ddX9PpOG{{Gz`*qqe;yg;g6TD(~Z+qyuvQY5=_Bz8xgJ zQ+|AcpS+tJZ19>GA`>5Q414mJu69yPEoST_Hq+;ST=V`I$7PiyrAlYH9dA^7W?toU z$IZ^b?vd7VN5O+Bf)X&#p-F#GfKF<-7G33E#D<9@Xc5w(u(INjRTwfpis}%j4wBGG zk5BQ1yhm&IvGMFH50(hXn^SGpm&)%hW_#}6s-;mc-61mfh#dwxbl;yZl#^;wWAXL& z}lt^g>Q~Lwknl#8i?9n zhsm{!wzzryvRn1X-nK?ks8fakxsBrNWDJ?;_@-a{4QCt&g0_#`^oBJ@WZILX^^;h` zQn?7>ynl>gPJ*M*DGTw@os&)qnO;GY+hW=)BDLSXiwY_gfD!gJZU$dur_j$a23QN_ zxoPHas_?p=BTb*Cj3Cj>^gfje-X>2?OUYQBb+ledwEeJ86$)^Xe^fxgy8UKk78PW( zP7R>q?|eIqzJIvkYIllE_~5Jrn#cC zqT4CZOBu%AmJYMh6R=pIA?3PP)ER1dE@7cyo6&knZy#R3c+;E1 zs8%CwJj}oj1I5&&Vi8044c9!$s5Uy#;Pr>GOP|epfbr)jL}#@NAXgv#L9)ZZb^LU3 zS$G=G*n#*}dQm;&h7HZrEx9?N7c=){S1CgonYxOlc;D!fC7bFKwh}FAU2P7vLi@Bu z5?z0JqVJV+6Xf=HwrvBE3o)V&Fo09Ib3TG+Gk`$EM2sb2y>}Y{x-6JLB?hv1puD@$ z{>bz#!K&g;SO4QtE6eun3%*ug>IQBPurj3ZKnbSvjV1sK)gXqW_WcUoos_KlK>`q` z*42ARB?lxoJ0#>@2rjqM6S{4HeESyQRf~~{#Io;@u3BE4tp4R>4D|WPM$R%}iD@)^ z+N}wb0uj0)lIhnEasIm6sPd?gNUa=@D!?k;_FpF=%m|G>;BP4li(RtFT>6#$K%{la2AlcB^JFpR~}rmEMYJA!~!Z-Si)_%4qWQR9@d=e$I7 zk|Na6ARRZNJ*VSP5G3xx2c%NjC94S;bwWpzsiv|6selDpWJ0~B||s7 ziV2|DrkgQyy(X_)?JtHgfLxN+>f7k ztBAFMQ`Ye2&((NIa&1sTyz`z7hb=$!IHb;Z!r7Pvom%kwuv}SvV}G3U04gOlp&A~! z$m7tmxfiZExo>zc9N~nf=rVT`X2xN3O(PG_S6pgvB3b8Oy^mcu@h&sCTP-p4XGU0& z{K1etE;u5IX^|9k+M16rkF~pwmHvpo69NMP8Jv{~SS>}9Ln!%dHX%1{rD=AK7y6U# z9?~AZ)#sTEzlS)J@1zBsENA^ zZ6BmbwmoYZAr>>X**fSnQ8P(VL9ZTxst-uQvIDQVYRZ`uuY)q*f{3|yUVp?AB;FN9 z@^nva9QE4nqsP?dJ#Zj9B!I<`b*(nEw! zi!+XV6OChtR%vnf>Tz}jEFnI7C9bxcJ<3$x8KN_i%ctCgWib=AK7R#6BgsV%BJTrG zASDM;YQ^^g8QqtRV6_E3JW8z((j-1W?+s%#H1v;&S$ZX?!B{X%M1^LTGBgdU7*u|Id7m)>yr<%NUUP6cmro2rwBb?Ba{tpH z#71L6FrXSIcQV}TV3^5#nrp~gjhT0*ApM#gEjtOGkvkZ^7$jru9+i8pCnQ_+Vow}9 zF<+k1kz0p)@*bLTE*RKtGv%=?GNh~?68B9hBn!%)+0hQQO+c4Kiflw-4#{&7ck0)a zstP1Iq+)#nZH|Gn$c|GMP=(ztdo@aa3d6#Ms@no|prv{~nOd?VbFU*i<_=R3X+b5p z2CAFxwHf0-WX#-2xwkD1=2vi>+|L4u2Z-roay&C*rc*CznkW5Vr93gTH(Ov)Yn*b`eZr|_hNOo!z}rJ9)KVbRD7^ZdR+lM7(gt3>nH`Yi9=n! z6BaW}aHr%33{P-zre%Z9&DX7q6=nHj&lsK%I6XtFhAw=XHDiKG_1}sTXF8^+R0mGK zHvhfT`{SPs|7S(BO7>qPBcgJzZ5X*Hj(2x|KWKhEaS9jtNsNdina7xZUxO>ZC%Ul2 zf6l*%0?Jj4b6w@oJ1GbABebc*)kU*2Kz@>_fk?{-j&c?@A&m`@$S+It)zlPEpyoHX z^ii3(aIJ?+7V;-x1rMXeh24Ut3_hQY)~P8w*S9sV`vM^xbM|gLQ&l9!1PmKVN*FdQ zh($yCW+PJ0I=los!D}1E{SBGS9Tv%^hhfG7MU1V4ipXe(WTqcu9j7hXOTc9*7$;gK zekQTwF@c(DlK3>`wRR@aB$n|IbuFqVaGOpdEd+3@Yeg?bPR<#uGI9Mof zy;?;u+u40f?}anx#r+DV25%hE_qKP~v_&m@;n2Cw(seO+0>&!vuFnJ!GK6a!0K6+} z!!wcv;=G`}nfvA=PSoU2D!GGB4HPjhPNT&JY*v1L$^m;_7d!DIF687Y!5CB2Rw@>}S3yB-e~|l~-s7&2k zY=Od=SRX?t)0gwKCJt(}e!M++ZM3|mkbZ)JyglB+Q2f9%8_m`e`g`qOgXOnG)|1*~ z)gm9a=tB_RA-7P0!}o_`7T zN%30xWmhwqqD;rv@6aO$7U6)JMX|phLNVg3I+Jw&O~jNoI(Qm{}#;CZOi!hQt2QIU>f>nfBe z3=U_&KLW$r&E`pCX#wIfvn$a$b@`S!7Gyrn3|O&<_Xfi}ob@ZJFsEMH1Q{q zWDfW*iZU+lznYGEMknTev!l$cYPG)(vD}LEVI9u0Be~|PgV-Og`UkPGXIp2NL0ktG z89Fkq@53vN-MMx%$HF&VBAw688~AM8AGW+_(p@DVR!gIl8E?^{+dC6gF3DN|EdxX^$MX|F?@~Av+Yk0QRf1e`@J>|heQTJPns+AGzJ8~hdKD^t zBkXO1&AEP4vpFwLjM10JqR9LtMf|S!m1+5X_o1qY@JulF)P}up0-A3ijq&~7)}qs z{K{?yIAvjeoR6ciqdS|EnX)hQ9mt2f9*U^_c))e$6gB?AJMz?yD$+XgNLtl}T?3}K zr_jJWkrFLN8(LI!9GZ&OGD>4l3&uxhT{u*<@DVJK<`dOqUZcrmnmO!a*6k%a29b&* zhaHQE1O#4wbe#9fbI#ISD&N18Jmvb_#Zq50eZk>T?6eoFcA%9zt_n}}ty)%mZVIx* zl;8h?Lc2?`436kv(#N414)g7{&sfTkkIq98hsI%vgr;<;O5zjIi3%`TrQ9Y-F$Son z2A{ChBaK;9D-fxU7WIr$5Q)lv-}ETbt>h~bEKxT{q?5SChDIoUF*PbP(*91quPx@H z&S~w@jBVsWkq2tzZ0K9usC66gvW%s_4L3^0`@C&VK}*rmG_VWN7|rvS0Z=#ZuMA7^ zOqz^8LETx&srZ|#%r_f-!^J?v)}iInW%3b9?D^xr7tMexvS*L{u@xs#IQA$1qxGF% zmOc9fXkah{TyZ^{J=+vvM-JOoouY4lOH9FQZV1AmR&#yLy~CxXsaSwmb-9jcxOT=w z2?J$c)whBoGlkn@$RXX&9Lx6oE}~^r^_dSX0jFRw%87f!#4TWH#dPq3ji1E*118pX zSWPl(q3a0Mqrl@~5kYaw`|x&BDZ4jg6Q=|nlx@=sU6(xV^OAaqZU>NghW3PtuYDd+ zRgxI#)eN>+dDa?bAT~0x`gy*ZD63W|;3$fZxL@f)KDPg3jhpcG~jzz=H zv&QaP4N1R31Rd5QDeLaOOUi5G=kfHmq4x<@C-b`%zwn{ls_lH6;6p=4-9C z{tT?A3JE{;HA}Hir$DD2pfmJ%-eK=ZeNn1}(AQ=8`*4E< zR+F9svpDp+V!}N7vvpnkY<89PHTW9y0X#J6CR>o%y-K3%sz%x;hZ^l4YI%v%*LOF= zBsw^>mPSZV41@WEdDCX}wHo0;xK0aq7#FfBeFwL^8fW2eLY&WGf+t$5s3{KW2$l9N z4EXvcoWawNARuF%Z^tZSg+5wDk|?4PVc!OA(>G;>wGwppr*dm^j(tIP5N=KsW1M@j z`ofkHT!u_AY$Mfo;>GE?GYC_!kNW7Zsbr73v1*_o1y69Q2c`OS$VtO}(atBnyx>WS zIEtoFbQBTlfN?31UQ9SeP=^VvBy0c$JeY~Y&Jq>b*QNo-{0?*)|7)OQdAX9cU=kM| z_AAh#a!gx}p@U8?gHsCQ!sW>(b0|jA5eiRZ4SDIijN=j>|1-(avHB~?v0&Xr(w(?t z;sl*VWPMZ;e2z-qRi%Cd&*XRO!w-A+ed^l7Njwg#Z2wg1ST6NDM!-2tni2uYZ#RAnK2=7erRJY57t~5{-O@Xg#& z9EDRyI9`olKf1uCI`VDI(s(zJrh_FR5M?YQbZRcOAXY2Qn})CN<)gcCrzsA6m3IHt zB&L@D;_8R@#7{=>dzBF$m;dMQ%&j!dKU{CUGg9N%ia59 z*`POHw0M>?M``2R5B-WO#SPa(mQmJD#!p(4-eIaF#D);U+dxq<5*NsE8VeE%0DM?2 z>pe5ec++U!uEg5#G&KqB+!15UKk4C0YG~j2-aF(axaNtD*xl4vy>J~L_#p=-$~ z2B_L*%rB7pxDL$?`PRf4b7r>8aVa6kuopx&e;yM|CyJ}L!rn1fyPy#;4Q1|Eh7Um; zFg7ecy;He$N%zKl{amLc?JAYuKxe}dJVO}3$m}6$7E3R-Qt|3|MZz;96zUr(Yyee= zc%5(fNw7`bTl#{{h2c2e4NU@2uYb+s8=6FVL*oJ}Pppv``5Kk9Wm?;Le%keUE_Ce@lD{aWpQukhz? zLU_vG5Z?FShVXp*{|&;6HaAK2>gtXVx<+q-32Eyo6f|iXWs*)9DqSrpcv2{p2O$_C zO(7LwXcNCm?87ICr)I?9=8vGVD-Qg30)Jp}o9%dyA&ONqKL!$otG=wkR$ZEMkU}Kc z&NeW)!k7jEqh6+=*K~$qJ!qcbTSW`Hfk!R#jA>#-py5bEoN|r}on@ zU~{R>2U`#Ac8q=ZY2-*jNq7R*$j)%63M|5D4f3N60%JHcVv^zN1j=j#IUyDPn%)uP z#3hW<9hL$WaYa=YrDWrXc`RvXVH9;M`-_&URFnL7*5w#CxeyxPE>}UfDbbG^677XlCU ze_cr#SoD-s;#|4M&+B^rDH;hWPjVjJE2NMKYz$ucfhgNXmMtA1eD) z7Vf3adgE^D9(HcDO7KWgij25*!*<2oP;PUVc-} zg%<=WLSklON{%G!*P*2>v5J+A=RArBCMsVK78q)tv!-_ybScYw8rnIIkyk1b>y$tZ zh;nIKJLOZsEr{!qS!0md=@@M4bg?Tg6Tr@utiqj~>^H)Kt*Bwh$#H!>VfvWcgJWs; zE7>H3IvvXEgQBGd=3tAuJH;EecmVlEd~xLF<>TSpTp%9rP~SjSDIWB1FepGI9UN6x zXMZH#p5q9XJMX0Qaml7?=OHLf)tG+g`~~872}h|TXM%ACC~qbM*hyIK47YL;j zu&CHKH27Ukk(@*bS!Aio-A;Up!H&khmV_JjT<6}u?jqlh3E1>#{=DGn?5Z@ordaj~ zK^xi>$A54%j(4_)`XM$9>jh+HRpW?{?s?V6 zY{+n{g&81r0b0t-Y5CJ4H1%$6WkMP5-{V z`ej4K!>X){Wa;0(U7oAN_s2Q@oXH+3Jh+@*C_Lx_e#H7`a?^KQKNXT3 zk_&D3$B>NZ%zr#%`743X4=#a&@?c*=n<`vg@P9<9{3fJwAz}V!3*(&?)Pxeqc+8DF zl=@EXE23jN-Ec|%{V36(SHQ@94<@3tiVF{POw4LufO8e@3g;_}M49d%B1s6s1_h!2 zLaE)qQL6QCluG0ddvE;*N(Eo8q#!)lBI)UOTl*8G_WeewG5-{$KG71p{6?u$dCG)0 zSKu`(AHB-aC1PfT{aars5tArl+ z+#JMBxlz*VPEs%DQatPx=5bBPpVOWELaCAdx__cn;eSA>>%UN{+C5wGBSJG@CWdW>79s(Nhj0^n8V6|+{6Y3S}-sE(`i zgRxJB!4wykqQae}4sWYWUcjAjyXID?&Ri9l0KavSq)l1iV12+zi~$&##5Ke@6o(v? ztDX`t*Kw4SVMUcM_+9#A2)ATX>Y4%)%BUPu+Ms7n+$~Nq9IvCV&hUN+Qe)5dwsuAV zGZZ)D5T!O}rtuvn?6F}u7vE~JSK&E3VOHM z2a8UJ9fN_H{fwQk&nu_@fs?P80lLZ~>J!@^p$-cFIqBtkz4W^0<+bBc-yh^!3g}S| zdg;gTut+o6Z2Y>{GruCrlVBgTWa8C4uI5$gN#p2det_d+)xZ7`ng;8M`Nf^t>`%}11pc4<_7;o9h-4T#qoB0|>$HtvutZ^E8=H`iZ7S_1?dd#GPw9^TD5|BnF`tSoaT?^;(8yYVgi-vl0$BfI`Dn)rN3l64M?}Y`Au8DVM0UW)L@do zv1>cXQJ#q!qq%RcR!8lB1!?3$w^9Akh?vbBR0&;Di zf@@1Zx%Mm~bYxsfoA$6|;wf;X8p@!ia52Ls0NC7YFIiP`YprXYHw!3wMC}Vc)WBf3 zybmhm!rXpn^|TcpK{X-ywy`8CV^0}hDBLIi%+)o8N4-QT zzxf${#T`6wOVM9ns3jOF<&fn5kt@R*0z7B%7{0m*pZG3Agz;u|aVaf*vueczeAq79!a-R^37b}gV+U6&~126+|RV8I)eae;lv32pCuiEj*> z5?SV}mONDG8}z`{oVM&P*S!uCTl!WM$c#iw-{KedH-+~ZqW*zy(fnR|ONbsL<^5gk z78}WUK#i{ON&^y^xqP@w13FUPF@#K}c;Nm!MUS>Q-ORQ!{9fvJ`L$vw1HJkII3*$Y zp^?xZWe+whxGrc)Q$0FWwcix$z9p1qb6gaIC~(FBU9!%R)w|e{h32*BEGfi=B|?nY zX!w;+0!WOqrQ|;7vVNzyk*DsxZqOHKh8uX+aDGr84M{o4$q_-xi=*w_14P9+`wB9q zqr6~0Es1@#T~r6Q-&3Qx2|-UhOyJNc;y@igkw4R{z@8|6D0i$uF7d}UT_WGE*#38m z9bD*GqXYpJ$L&DQA!tOSM8RLeq|KrnEYa^!`dt=~Vy@iL!S43?AjG!-CRy8XHi58T z+*ri|GtL;islwgp3){wgqma@)KJAUPK#&Z+1dCUX~(n_tK|?Z{py%Q zbcD!^&PNR}SN|^gVOd*R!3Qv7f=4|7#?95M$P{zW{?o+2*!rcj6?ZTgW=XWSs1fL1 z3D$rvS>ddbD~~(`e@WY$KoA47trn9ReVeVX6rCShqzuf@7PI@LPo6VIk_n&sA?8Sw4z2hD2ue-!Dz}+r{6o&Uejg7*k#ogw!17EZ zv7LT%;J|K8*iQsOhvgScZSSij{{>Uq)64pHYaKB-h4g7h4o)0a{XVip_wx6ho5+rS zC4=qGVO$(nnu#EdP3y5Amrzzc;7j*p!1;@K9d9J0N%kx5g}-qso*+YCr7G?};?&+> zIF;=ePF=0*68sCNF8qa4i~q!_`oC~$|1X@HyaC5_`wOSy{d1gZDfbJfGVuM4Qzg%Q zz8+LmEIG%|ro*90?D9c%vCtZQ>`Qm*@bCQmYXq?-oW4c!-_!t^1$|FPl0sqp zmKm*F39)xt=M+PumwJFlVmYL0Ijl@Bei)o%E}V}5+5ae%jp8&!PZ@2Zpw8v+rzB5! zivHdJ?g2+k#6dWYq^$-|8-!hg*m(3RoS1HD9>zoO`mU>at-An}Z>dy|J3E#fM*TS5 zXpZh4g2`e)uGz}mt*M29$Pp3SO=q}S)<3|&!BT*Sz}(|n4Z26dSo|M;eCAVn&1g}| zRU(6&9Kad%)n3onUhf(Y<2IbJ<5R>nx_u`$pUozTKbH{O$4*>X(hpXRG7Dl%49%08Uwcep z^M1?m=D+3mKtQB(jzL-PMv+8PgYr*Gc4H3D%Zbe4hHv&Tro|)N0WjIA4$k&PBYqjUV_~ffI`?VyUIl zXgkiQJP40&^qYYK$>{be5rf?|b)rI$pWwLhP;LA8EBXjS1;Qp4sA~zC+Y2i?dlq&0 zEsRuq7W+c9y61rHmf<&+XeY8dyOjx%If>78H*24jO0Ri7&@M}6C3oR*!oDc)c|+&~eiMGmDOv{MV0TR5OCE$D%=WZzv%)hv zZk?Lfo7_5SjGrtqA&y4egAoQD60i;sl%c;l0YybKwHtZfbFGEQD}ztR zk}s+Y0!2o5kSCs?8{CaxEeH9Z-a6$@em(Fde|CMsvpaq}3Nmt9U4(p6P`JWSR6i98(C{=2g@`nURu1j6QrX0j-K(4R>^dgLfnAr24(re_l3s}CnS{u* zKJl4RSAsVgTt1h_94f+n*JwAQGPUcaPK7k;WW^?tp!Yg?AAzm#UWv0O$tN4yK}v;% z9cWG1R77+B=Ai}{Zf)hYPz~BwGU$pU5pe=31O4nb4CHD(G6YZZiDxRw?4H zHhLXEWT&s7`=JC%#OAkgmt{gQu*_Y#0PNB;t7&^g7Imp5u>MwxI55IOjQt;_2vmIo zIF(M#j3aps?f%7C;D(@y3_;jK0&edHnbf@s4;iop9pwEEBu3iSi!7y=dJi03bVS`U zv^Ur~<{E0H?t-amDG)$A!3!@QH2^jpSG^?H3-%5%W7o2RHSeQ>MI$|Tp!cuesqPgL z^J-fOP4s%~mp|M_GFZk6%1|4x#A}G(%OCE#bH$h2E^X1~J{c5%C`YURdTXnqIE{L>e~ z=hzXQZe@FUIx)Df?%69xBQ>pQtrP13oqF*mZ60@J`3&to{4R->jLt`0`>#tmeUXz`os!&o%fvZN~AkEQ0y+_@^XgaiZl4u0*0=G|-D|B1l}w1)hxipQs`- z1fHSTQH>Y;p!f&TIsTCDFUMIhS#buj2Px*FcsdPIbX1P2?;B%0g;rkBwQ|S-Lw0Uz z*2a>D({`fs^bvCyL>M8`yx<_G|MJSNu0~_n7i7E*_Zs2n=EjXR*P%g&;>~Kvc`XkG zMZnx`+V@=1dn4)gf%1}9;R9vr#sc1FqSL{X@eY$q54BfRD5?3TiK`tOj~?8bA01(! zkV**sF zek6>-B#p=8^^*QevDpIbh^pp_t4v4chp~`mk!$WMt$wIF zjs8&(z>*=;Kb4yq;l0QItJ{qDMXm6EX*a`L-`cMC`9sFd93z`Il5uF)uu~nmykBp9 zYbY2Sic?G4=A+WG?EvyPSL23d3M8U;7+95u5A@KL)TLB7yP(uT(gB_YW@V{}NqUwT zt4k|5@G00s(uT(F+fpuZQY~j#<#=rnjMKyPrG12<7Jf0LCmlCWBQoS2bQE~OMm88G z*hr?=xfm?&$*P0M{}6!hH(wi3sk#lk3oB?#Qps5?qMO;q7`;JSTk?HWu?DdHz(E2}txCu;2w z56VH2?dg0Dhn&h!PF2UcBWFAC{c`0ste7>K`nro^&;tA{2GAn<1n|MAh07@QIR@B% za3`sj&o_Y1ivCIiP+}uoFN%<*)pW(3X}UEcqQS9wmRDN^+Y?dh%Tb%2UN_Ru3D^$V zSLjc;vi9MXkRMOo2&-}9V{SHx#LX;a0RLKW2KC4+>yTF3Bq_c8IsZ6(@@jDJQS-vB z`gfV)r`q4Wg?4G=H}>Oz8VtlvUCpj70&UD!F2G4KrnO?P#lBmOn-`q`gLAqfB^mwj zpc6rWg6Ga5Dt_i(waIG>RBB*+3Qvlb+drNFsb#@Ihf4))4*4Pz#Fbgn@qFc z)~egJ^3cVQ`hU8hjN!;U(zAa^s@7wF7_02zuK#JS{)098Zx$6RFrafCXu}G1>lniq zWJ|Mt@Bb2EaYS}^&nDz|ciVv6G5@-E?*6)Wn*VTRrH7>d@!A&NV|405<*Z&sB-@d6 zqX{FC2`Tj>#{j&TQ&nlELVpIiLeScPg z0p5Js=<;3Sh6X1dUEwAk6o$;wK^*3GCx#A7QINlS3g)j#lAOEt?ZI)H3;h}Xz6C}2 zcm${$)AJ|;N5Tns0W9Zu>ZCN*C!H6@(!%4+@ELeh1;>M1O`cEVaY?1AmLau3u^LKR zt+D8p#oUdmH+DxXF$h>JR>^yy^-5;D`WvwN`~s{@1f3Y%5_mnPI_&|R9kNp>>C1Kagr_(EUTQ?iO_|Nj(@(a*y@ea zU8Fl3=)WbCe4zrJZU(tcFpMmhu!FRM=9`E5rN0cqdj{unL_-%C0hjXUi-yf?#o4|^Jvn!W;e_^(Q8 z4Yp2|H0>cSJDq~51!1{WN7Rf}f_O?_hMdlge^U zYVv)m$x;k6-A>HY@aIP#hglfxgAypaI_w6h@mZyIhTY=Ba6oB&yeH)`O!eZ2ZEF38 z<-69|!_ou~z-H*{I}#ht8}FAV*M($b#a!)egDmXsTr9Xb1pUWaUyo-6E=HMKGA=Gr z53Ma>bN&^W%XLLapmt!dpqf%o${Gmwqc(|)B_Dz~APM>)Fr$Mfb*^2nMR~uBYi)zt zli#wc>j2L=TBq?su=j>$&Z>e9HHSRZNb&{jBs1yc?|0SySuPguM zp>_|8aGjd_@wjibPB1%z&6s2({=_KiOBeiff=F7bt&uu7lVo zO9KDtuDV}W2eoHUFi-u1vU-a4xj*^jam%(-U%L#_f4$rbNDPzq?`o^%{~K);c<*m* z_42=KtE>N>wmR@jTc!F(ZPn?2udS~9|EH}c{@>SDLH@teR(~kLHkTvq*j^Eq@R%9| zv@NseELT`sa&K}fuFc{7EHht;-BUegER6`eq2ybPmzK)p-fNlQYk+C?d=XyXFMG>^ z8ik!b9pu2dtZU~tx2V^D#LPzE_5u}aHlQMwG1IXR=bq($Jq;nZ?z(+8E}hbyyo6PZ z@JqYoiJ(QA_;f1`Tu#Lc)`j%}dR@G*p9j7x}$dBs3)+^c0XZ_kLlAm?Q-k10Z z1pPA-{Is5Xlcw$CN(pQRDh42|5HF*?j&sL(?|gaE8AOnna{kEJJPUb=?2pAt{LNag z4)YnH-SJ$OAc{Fg&%VE>m9A++*6BM&7Ntvbe`WC5W+?5-WTPg+i_rR+ysxJM)LdJz zX_!4)+PBw|HWGie(_cok!+My z12p6z#v>dzNnb(W09ktdsbc|c|Kwp9F}wc7L?H8=AoBi*mx^hl>9f@x*zoNtWo7py zcD~}&e5xTvyMvrjk2|VV5N-TH=w$K53MuQ-MUejQxdzsf%PeNquVax>CPV%aRa$3X zpTWmVB+9>->FxE2-H~_}nlqFTzwL*|#eG?YKRsF5Xongq_R0jt?E(RL$GnLM+*9x3ShSFTSx(XV)egTh{VBc zHTjH}+|=lKPf6jW&X`SMHiO$+PD&(YKTz1JQ8mweQ7~zEE+vfh!NrX;eZ?u4Zxl1~ zT&a=kqG7$Rr%WiM%-YG_S*$-&7_PM?M_$HI`X{SvelyX&@~BK{IoaO@xKNRz98V+ z#2F<@k_=%pmgUx#Mp@BTl;y<>EpZP>0GG>vWBZrC_YqsF$`*ml|&4I10F zZ8f%S+gLO0`}W0${jI&$*!#~t`rOaVGxMWkj@-vQ&*R!9Msp`6lf}`rt8s{DDc|F^ ze?o0}%VffIfYd@Jc?p$6A2$+n+T&;a_6fFysCB6HZo1Niz6c?)N z-zLMuZfLu{xT80y9^$G$)tsxa482MAS!~}0a)zM$4)IAy^9hJpFO*zDwifCO&dH`? z`42(oFOpb$WO)98&;oZyAszYit4@Kz?~4%z07a-(nHu#L&50!Ov zBI!R$I?<{-@(j=dS@SGIozsN0mEqF~lgJ%I$?fm1w_0WBthY=S2MFsOi;9pH2((&j z3T5btfF0ppQLBI%C_KqusCB{S6}1vS1Tfo@JRHp18>Nkl4GIJcP8Jl=_nOPfR)YtzIgOI?LL_l)BbF}J`!qIvqtPrQ<@cfAr6qmUxj|z5H>RBg+_gEvluI)@d ztYQnhBm=b|ZDZ2$#BK=I1p$l!)i!O?_54%P?<*TGzP4Z)=X0IXtpH3HdPWc_JIBzu z0ri){W6z=;^tj4*ci$vQPUetrQ(AntKHz*KgnwdQXm)YDt3ZuN*mjbJf4^^8_i*a? zzBncS_{rYb-en)#`(R8qL#!`Hq{h2fCEMZ~<7-E(zoVn?Cb zYhacBM9fz?`B~^Y>tb!?VW^l*q2|)m1j>*QMByw6WfHP2zG&~c>VU%E>~i%R+eXG# zjad}%AhamBzrjEqLwP8btU|zcYg*nKr?{BCM#}Lai^f$S#&IDC-@1x=s)Lc6bLEM< zFDRN$j&pBcT6%R-oOrcGf8=fNbM-2>{#<-cXlC-63L!v1`QWA>s_U);KDA42bV~4D zuP|c&H9c}V74!uDq?|_N@Nr~TAmoI>!wIG9GDBj8?qUb^8nk2ZPKs?!g_8v- zgUsh7R)m;tWB3Emv;ND7U9s%qC2*I7*`|;Ptdo&*B_Vw=_Xc5oI(W>n40RB>)lzmlKOdyPQi z=o=P&!&i-|?#m_#ND4F=l_O;3G{7i*z!m8tiQpH{PE==EFglYPT1V2&&Y5&pa7c7( zzwvI>44jWSJx)Zb+QyPO@s~zMjyBSY7Fm!XUR2!vEt!z!HrMTGd(5lTa54uxv$K5`d&B%%c24O|&Ej%8vdmW=k=E(3nc8Nd$hQ2x-Wu<0Bhz zQ~ASj2mM*bm^m6MnhIq>V3;#RWp!_7wFNpb&4;Et{m^q;%jWtkX?DEcwE05#EEDZX z>>O8=zZoS4NGDJzTJ@ilo9Eb$nx#zfebe)?W-v9mJftu_qE$PdX}1TlNnFy}@8Q4; z%Yl&e#-j3W`Bi6DY=TD=#&G3~D;jL}OVHN!ES#E^VIwrx;fIbgXv`N$6^5eLn83;ogzP4i$5w1)KO6$ zw1TA_wxPK7fkDWXv{zLT*&-!*(qSKWeiu5wHg^WMF^Q){+czPQOqC*D3yQbH?V~1S z*}C})sPps=KFIAk&-;iu^sV(*evRNqPz|&9mxN`C3|MqiRjwOQRR*}jX*V&Aeu1Vw z(|F++i$@l*KsCqHiG^htio0`a3gM9G6xkC?26ZHb6Fw<3`0#K#rUN13`Cl>dCf7-K z#71XIwl1Xgl!@ewnz%`IX3>f6x<7Ou4}&NID>7(!*=}G3# zeO{8Wfu7iU z!M6)fS&?wOcdSgcha3m$o%RXwwUKi9 zeM!`@X?;Ibf9l|9c3xzl3}mp#NdJOA6M%@7Rll0MI*!v;Y0!TzhU@zzq~-8E_m@J# znuyj;*KpmqlS_St7ICY18RO)5w+S6_Wsy)`-s^`Z5PQf4O%Wg1ETBMc4Kk}kdJDyWh8 zyFKA}MhW7L5AKcm83i5T2X5JVRt)5whT+mAqm|no^v70s*6Pu&#UgHpx&UB~N6SHd zzL1ohD(xB-rc2*j8rlcZ4ZjkGSq|g4L^ThRkByli8Hu!Hk}2u$x<7_`J&g_Wpnz{Q zicl(im0xa&0&p))WxX(PDxzT%Q=<5E*kjdZDZ`=Lqi)&>UxVx2+q^^ zG|8^Q^B!Gn&9%uld5w9F<($rEmkKd8|L>Myld(1XVro~}#rNZi?w<==suZ;53+Tb5mvk8p{Zl z`xSq6fpQ5>7fco*zWEpu z&>>cuZ%tJkH;W?*m}S2U6^x50VC4tlkABXg3YE|P`{pNNg`b-W@yUO@?9Uy*%SaeU zu=4+Q{ZWHOc53=MLZ~3}q5U6s0Pj*o`qx{%{tQIIN%jU{m9tDo_Dvfz{P3EfmMr}$ zIVf(NMOCws_OD+fnM77WX4>>7K&6xjBBHC@<;zxKgvu&?Kb2Js8rS+=QhMJK?e_|s z9$R}#m5R6Jceh5El?PKo`e@;y$^?gQsa$R9O$0Sk0zUZ#HR1XBV;~e5xj8yAQ6^Bw zxH2Nsm@>W4P@aqJc}SEk9#(H7T`#@M*q2=M0+3T8EE+`y_{}L9&$uJ#mJOd*hukoh zX^cDJMT$P{iLJPb#l{##T@Ado<)fLo!q1an@Ik*Q>K{MjGa09jbiPFSy!DaGKC(obBRhVRSP24?3>l60lhDQ zxA4~BPGt<&$fn5B0ygpI>UMZggD+^12U;b;Sv-cCFI_IHUT?}VCcbVBQKsK0>vyDR zR0t~__DhKdC*`VUEjUYPvw#Z_a=h3)VVMy(J3iVw@w}G623}<4Yq4rb$vwrESJYn2 zc|ptCF(GA#=$A2sB1Dg-EM+@cwtF597vvYwF3@DBq5Py&bTF=QGneptM{V)-9dtyC})tG?b43Os11;k``;jb_Jxafa0gtLb!pOTT%4k;SSlQliIA>>&bmyxxTK{B_In3?>t0yc=3p*jio# z5e{yonr1W<20J%1h<_Q@+z36W>f3T&Ei@iN2plVm2n5`B$gfjCr8Nx9k#0B!l$zgQ(MV?J*ZTWB!mAfr$m{>*9*ADSx;GnnII-q-<1FUR?rZ-(Ot< zA0F*qT>=#&0GEJp62K*pZY-1>5t*=PuJ@Vxr%E7m>ra({4&mx-kbNLxs^b^f#fy$# z30OUlm-g2LENnZ7^byw|aF!-LFF%zCL>!erDT67VF0c8mZafRurC^Bqp!r|5ZZ0zQWp+xtfkbD6D+LrTqsqC9|P&c&fQtKm@ zlIEW3nYwGN8O@FP)K3P?B~P}{CI8x=>8(Don=HFdoG3dd2v3&kgbQhR_CD=0BDmzUjZ$s_bZ^qdbuYgt{#B@``Y>4$CwKMWw&*w+Zob zSn~a`a|%9!Et2fF*W|r3gpCpI|MQO9%bFoa(5WD6VHnY*%omOztJWy*OkqU4AO3(R z{>v#a8KSij^raI_%jn`QluvQ5P~&hmvH?IX;C1zfTEId~VNuUnG-B2hp?UAy(Fv)( zYY=ja8lkqUZNvuf)4HTWEBpKPDZ~X~2t2gpv?5rCl3ON6FS(Ezk1;CVe&ZuwW3E;# zb=Uo`>$CFyO*_0$U$K?>Bph~Xo)fZnnx|Z+S*0{c=X+eE;^7 zmM@#lP^p9u&*ND9*xtruwhC~8J8f9gLqT7F0F?2ZqCO;Icdq(jSxQ?Dm9DOocj(mi z3^tSnWvty0SCgu)Lqma6YEj&oMDOUFH?OKT36>@JY?7Yba}1MQ!$Ks0 za|VFvw0mX>kSX@Z0~{;Zqj!lMjn(3?~{)sPDk{7N=;7dTXPI0%%w+VdMW2Iz?O$DFGzbW4qP#7cgvcsJt+P2*&*K%p{nC*9 z2cx~6Xh+I^Wwf96X+ftMi{RTIAbTMk}@ZlhLleGFr*oS4N8n^dA{*1js9+4e)tov_d$qjFuSbmC+KR zy)s&2tXD=$jQ5k#2K;8Uae=RlR{kfWJtq1$qow)DXm3LRj8^z9w#6Ek*jwxrL9aEy zm!x3GtslEmw;Ua6KH{Zb^$0mK3=8`9m&X`6?GsntXGp8})}= zfLWY_tZ3%m&GBa-R)pyz6pgN*)ATqXsuEFa#Jdp)A77@Qky`Gps-2ruKclLGSaQ^n z8avE<`gK!>I_sFGlJm;8#Kx0$RPuQ_)z@SvN~%p@Fz4gYb` z9@}CfbKp>}Z`~~BU9i(Rdf=?P^hTYQl3A1S-f%!j_8EcD8a4*|t3sN=_N_}SgAM^J zoe<6sdk0DQ3NvlI?;m| zS3;xcI))Vj7T6CTJ%Cx4i9Q>bH z!f1=D`LtPpFgom~Um$f(2jCYdL!AEU7f^Zi3rM{B1)c$Z0dt|LKl}o&fBFS@Hnuc= z`UOBy|LGU-1^5M;eQ)!A`2~!~p_6CuWX$TM5@8RDg4=O*v!ughE8UI zL?eM+#|=0AL1gr%*9NjgR(Dth2H`K?GsAR1w`yP@ia&aCv4)|9nTwQ$=hxEqkom!e zFQtLV%|3h3+m)nEaK=JZKTceZZ(~A%r2Pf-;py(?=&TKhg$G13{&EIhJb?#3^fjU{2M8A3__?#`j62-f^4%&f0)yAFP!pzL@Kp$hn5(mP zx(wS0@VFFv;ZibK0t8P@H2LD*QKHt0~S@K7d(+9D&yO7MK}y9wmd8y z)@WJGV)*GfqGlc8JLCe%7N>DUr!VxW2tX+C$nrO#K(Etpp+NgDp@8W>gaXO{p+NYb zLV*FDpF)A9UqS&4G11GvgaRGEgaTjwCKLesp9=*Z%iQn^ut#2v0%wb#cGJh%%?W6N z$MB~8=l^XK$oRKWp#5J)0q`Eqq@PBC>|aKKa+7}>1weCu8U-wW83oqH1Aj&}Y}5G>cf5Uk$pzY%QO!+(ol zasNcH0?hw+5bXE=j}feO*N zk0RgysYbv^;GY@+)xT*3sQ*ti0@V5crAEM`BD~tJS1VxSCc_}@7MivBZ)K*0H54gm`oDyp^{Y=^@-HTj8P3P`!1&`&-{}?sn0XajJI#;Xbn&z9SHl zl2c_^D8jtwcZ-R6%CZ(v!Z5>S9vn*MLCRQ?0UjGdLna@Qj@Qi)YI`;|#1Ha4)5wZ0 z_&{Z;C7SX%Jadw?kwQ1A0){bUaUdFTVIz58{w(X`2j8U+Ii%&Rs#mDR_d$y8 zf(QBXLRw?@fRoW*dxb3-3R+{TFF}fxGqeqv3acCT`ybBm?x?0uV3#FIrsfH%My##( zeNiK;d!?oLEg7rwkRiJ^UWjS~JYa%3dux*^K?hSRLDRDieK#65;efF++jL@K5%Q{l zPT6$j7ca0JvvO8J)*8`0X%E7hSbp(*&&eFEn}% z&GP|+>*a{hUy@Ivz~h3^e^~{l09FAOfK^~)l9|RtR-)aP7^p%3YWGw(a>%t(wDFEM@2xfi@9H>C)zUOMWH-2tbp*g1w7XauQfL22ao$98r zsBqwkNVwRL;?Q#EqbIEv@g_A z`yF~^0>XYZv_7tf>Y&6;mb@>r1Xl;dgGO2;y3H9a2@Q(1Z=+HDbS$wp+6nw50g6`M z7!qK1FlG2J9lO}>4wn?g!mYMR+dtCWt?Fn(B<4FFzNNb}NW=R|dz(1YJ+5PH9j{m) zxIr#nD1Ax_e`$JK0kW{h<%@3f*OZ`wYLtIpUGZO z0s-#7ql&gG6@?7ZCxJvdbN=t1Uo_&7$0he`CarI|B_MMNczYs#y>`zU3|6^z+zuCQ`!eOV|d zL$EUIZs-aa;p}*O?7VhbUsjBI%;^2H${ICu=BEvu=aBMCD*zWGJvk|b2%Hl{AUXC+ z(AwBB5`^Hy@t2^rR-rtf@)!xEZIya(YE&u+U}(+k{cULVenXJ_)P2tNs%Sj}<_RAE z6Q-J~yM~$q2&+`~JFJ=Kda!@*A8gD69IeU^7OiUBeR?|+WxjeVo+tinQu8PyKymn4 z-&)qUi+q`0c6ghe_*~ChdC!*T)-xNYyqBkZZ`v^*4q|r}6WndqOpapl#To?6@>&-S zi(5%s(Hpt155wDP*K<4shrw5_z*|!6w^gQgm1dtyg-?xlfUde`pZK)3cod}GPP%;x zhmcK0zeDKUsJERW;;=+#PCM+u2`&P`=QxRUwHfmvlLxNm~v@A!gg6Oj{8MEdbY+K(+g8}C0v z$XAMfiY9fX!Z*~fP*KoW(r_qaM)~RwK;(8OQMhTAAT<#Ge?5#Mc!AT)}ZVg z8zJFLJj1uI|9H_gdc^7{Pq1wn?tw+&R13#~0cLjqKX5$ZZEp2w-6)suW{R2F417W# z!)`EZMTtGa6uU}%Y-CS_6z8QqhU30U_MZ?Ljf^DX82I}agcRAxRMaBEc z@<@m|Wd*hb9e^698soZ5N(~E1%lk=@+Vp2}2o(p;3;-&}>fNW(fcfXrUslX(KjEY$?#!C?rmvNl0M7^r%Cd9f#T9A+$l%(jP3 zw)LeXMAJ`eGFdr1`i8El)TK>>!Or?wJAipsd1;Q5wg{TZq!ws3WO3od#n~zM4Drn# zCr;N%u!Whc0?e<-u2a;CleuDJ{qiKO>yRV!Jw7&nL$is`lo!xU?>-d|*cOO@XsGNN zOf5-alhAKKsbYlIpk)N1t=q6%=7LUm$qI;`E7FPQZ^YZGkW7JX)TAfPQ(^R4!`2Ww zV$kjwW9Kem;TWObVb-p(>C{z)2y6I^sH}R}HW@6a%U|#MNF%n;-SvgQUjhXWX`dv| zX>d9dYzR6a$D|%Aeq)4$%6EMeWG#b%{`L1_&-J~%E>8eD?Dx*kdkVaC1-z`if}vzn zxSvhmmoVc&U&UIdGSp5y&};E{I@8_c_JCxo&yRI|(#e~2;kQBP-5a>c7&&3p*eSqT z%1LdNsjY{#jMllccXm(RdRod=It?#&C{H1_>tZ_;mnBs3hn~b#;Wq879`WRs1H)?a z=2iZh(41~rfEBv9${WsrYH?eOu8)rgWcr!?DlBUmlR?Fd4)vwlSDrKlq!GFdJlv;; zQ>+pX+#jK|M7SeG-)vZKE$vg${+JaXt>UHAY5mL_VW zNELZ&u)L=(42OG77#j8G=O1MSw2nXWDl*I`dG!t&4$<0K6Yz+9V2_F7*3#&_VWUKd zkcKbFIh`ZSAF?dfoB;I#%(CFy2uH926BG9sZ@7HsKgbwt7M!8 zS1Gq_KB~elHoMT>y6jp>5gpl^9Cv>)xHnl^Kk(E_bR>SAmz*llG5Ci42Tg|6@m+M6 z-CfKeE`Ab0UntW9oKY03b+=twQ1Z9desa%=z@d;{CuJqG6ytn-Zpv=SA)zi?sote_ zCw4qoPFw$FyZdNKj;J%^#rpVAqvkcIZedq*LKth3_rH$Sy*(a})DO!-rmvN!jvqGsqA> zI+EW~jt&uRuR6h+$Rt-INhdx$#yI_8V+^E79Gk_CWg%cPIi${bqm%{8U{%6?UiM6`UcLhy z7;jw3c?MYuX#3YPFtV3GTXMC_H~MW<$M;Lo3U1)wiS@o)1%g`Dd^@@loM0}t03~|Z zC1H!@&p$V&-;qUx78dQ9f>-;}rVcF=P7#fWChB za<{B0?t>MPh6wZzv^mp*giCt3ZIgQ2NefcTKu4Bt&IVAoM0~()x7WHfV z!rAS#*oB(DwFX^>BXMNuZ0#g}_i|g+EI-);uhEcJ3U$dPYvjy}m5e+I7-Y`Pbjc(4 z^q=te-2Dt|X8Sr5jg5gkyGZy424-<0(cN5}F~EU3g#M1Kn$Dj&v~ud*U=m(UOF;4U z{CI#*{D;U$rwP_^ImYaSq;K^20zw)snr9cn);=|tU4Yo(-sl3!yG}99am8Bmd%lw5 z{Y><@fSg&+ix|gqFR95!bu2xu9?91^X63#I@s)TKO_Lp)T!5PXjV4S^IwglGwV~FU z8~bZbUoFj_STZ&F3KtwWV#j8@?qtEF`t{tG%N1A=EQG*rNTbghsDEYS$)6lAV? zl$+??hawfvmOET&3}(U2;oNJeJgl3W#9$m)N8G~!G4(mCkH_>r5QR%h*G4q?eSt(T zvUUu5Fgkm6FK>W|=w6OAh1T$;DsDdT%GuB2^y6p=HqWxYCgl^wZ z5|3?>dV<` zwAK$E9%p+S@WqObnZYklXedKu*f;n?R;@@<$n?{$J9~a)j=yrF-3=4W;YS1_bgjNI zH+^;(fZV7!AUB#}WQ|@?Qy(Jz0hhhBOHfHN`+x$5ZPUW?XdTHW*YGtrdLR-POrcJz zZ!YEpZw@d{R)em%Gw^8LM^_o7YgJ7#<`c}Iv8TWPB9>Pf~r(q$0?_G-F%$g?4~3Ret%#8BpJz&J8+!_zU4agI`*_ixNM!q9iUq2)5}s(aH> zP;d%o&sFGF+^=KZ#`bH2p~O5*CqDKnL0l*haHW@=5Y<3JT9hghv?>?Zvf&MU?d8dX z+xG=hU6p5p|Di@&U0(A3p!e>!n0`k@ZfqmyZWYmlr{7KhJFo;9G1v2 zfYa4(HVhCR#l702RezmERsxttMg?O!qTi4G8Xm0~`xPEt%_$K7eEm#7F5HmDwUoce zYGq5ytz9|+L63m`hFYWsLDfTnkGMc%n^!LGN78P-`J>{oY9g{B;ux45Ta)-OU>I3h zDC^H*WKgiuy>fEmllJm}VPvJV^YKrPYy4Ij7$zq#+OoZFY?W{gLyD|Qk|_l_^@flW zt7wZd8dxJl;g*WS?GKmWH8{5Q_?P#BHg&MrfWp4`8>_{NBL_m*p|i2+^S*-ktHQJQxw)KDQr^O@TwxUlm@@ikxu6= zdb*{rviJHaa#Chz9V;61Rzpa>N&Fg2&g%a4D3ndtd9*k!I8+Ls*r;8ovp)V>Th+U! zq*LXx{Y=Shy#d4&UJ2&euvW|qy!K#7K{CoUH@@a+74`PCYhN; zd<11R!-f!`so&alKcDS^XA&x=zc0a-OJen)3)QUjA%ANacL9uj>@bYh!i}2oVh3TI zRcr{$uDUnTnuS8W!`PLlXOv6O)EpYivbX{;@pfJ#q|?75 zq+x?XiLVh-PdE(=3+IX{_0FsL_}T=ue52P0sqDUK85O2%0aD^+l&$=RDowodMIr4{ zh^lB4bxl9g*d=ccUMbsG9g>mFEi>2chok)!k=Ckhmqhth^y?LhYrMRduA+>bYG%&H z%wwnSsl?p^w%Lkm@93?MYgAV6=b9#VJqj466m=$+aqXear^VC?->U5G9*mEs$MZ3H z8?K9}?)D9KE&Dk)HPnMYX1M4zwQj992i$U?3&{XmFP9ngE~OJ7AQ_-RW%?drUj9D$;JW`w|`hslRHJb!)f-h z*lHu;mRm+?(=UM9c#fI;nEywPb)-RV6Z51%H-KO6RL;;W1-2(__MaCD($`H%FFTRO zye3FHGw6VCe6()NPXP&14Q|Y)4hvgHWozeRprP~$ZSPpI7mLd?3dI&g~P&{xfHs}JpKpkT+Iv%Gfi14O_1!|Mr72Hl1`T&Fi-tO$K7 zrm8xJ3*D^0uCtxJ-0%YU|Y0UwoKJv~Igl^B|0lcE5B>T?FFWcz4cz$)xi= zjB;VPt~^`XTFO-aMXVjH;zZNEqn*~7SQeE?f$-Pzy)I24i|S*+hyP?L7=()`K*)#s z`@+mK5+MIoMB$Hx^dLw?0lQZ?Kt5Xw{O`{Nyu)WTkiY*Vg3org9oLt%_t$6~?;x<4 zk&Vel#c{NtapU9pvZy?ky?#IR=i}|8MHB>ON}IWbnm>_$%y7Gc2v;J$plBiw?rU_M zB}N><{4u*EOGz!vr4$>PuK~?gLS9ScbGHSOk^@=K77cV33qMOvvuV06EuZi0Tc=*T7K=EE+=p3RA|)=;Q}@u)`;yPolZX_vDDvy zkg;H*^f!%cOW`5iO^PjgXmm`%V8|CK-azYygZn-^y^DwInMeuPiZuw#gG=2zx(K{R1M}3S!U=$vSxpEUbs)hj@3fx|3?e2Us;rcT zGl58?bq9}=R%4Lvfdor#D{Y^5xjoOt#))zd&~%7eNX^)K{W{Js54O|{vG;t@OV%d} z0e=rm->n4gvleL9COzW1d!9Vzx&mqYA|qudXtk6Vfkbiag&r&buQXKCZK_!z1ZkV% zwc|*RzhqVGcIKurw2>-Lv=k#Ci?|Y65Q}zAgAni#XfqJj*9I#-p4ssh#{l0UP^hd% zRsmn6gWjzwh?waRC@g+5NO2|0zoxc}(;B;r2-Bi^^QQ#j8~SpRIt zH~S4`p!@UteQ5XvByT}VuVAIDFkPbtqFZc4U6nL!ToTEVO_wIzzG2qa8B_h**cb$? z9Je89gzT&UrD13Nyw|WuhgC@S$FDU#*Azl%<%LASFu4ow*pwUJ$kN@$^Jt!BTP?_| zYj!6vGC3e;C%tsRRFR!xKWMC2nz+%;xEaB zOzsV^!xbr=NIA1HNrYd_3za16OwZryK&#c`mQS(>FZyKCVelB0RC;BS)_9yQ^qbnl zDSKrnlRxNG>lb&PMDa~drjDQe*kn)2uw?;!E3r_BY}%b+Sde&TK{| ztd|hBVYunpvK){LP99x_>Y1O@@+T@~20V-S1`m6lol2f51bH>o?ku2wsT5{+{k=Ts z<->H$;j3Ex-uZd&;oj=HIR$aZLl%6<<6xnzhwwz}eru?bwHw&#JQJlY)?}FD^!(-7 zvJ|g3<#B~R!_lE@_xMuz1gq?34D#h_fiT=KRijRIXX_!dBoOp!W})aReA7|4wln?- z?^cm(vb3-MOwO~1%}Np^7wZYC_vH%W_y{j81!F-A;&32$f5%gXad zy-8Toj3aXfmrR%dnoJ+ZNwac4?TPXFVV}n!p=a1Vn$aUVH_K|s3soYjkz3N4br0`0 zrl)ae?Pbq!OQnYkhgSEG(`VuR+aHY=oE#5uQT4Y`gSRVZL7bt(O3!Lr;V|jwE;F8F zb9sKQP2bEu4;9UF`1Y%>IS)54zyweTZ;@MdRGe!dzWEqy6_803V7S*M{zVIVG%ghp zcsJ6C&jVO&RgN4a_6*iQUH?TAIOM#nW<^p&G*JEvk^#(|3&b=bLgwnwa>Wk65u!8v zaAXkgw&p5B^4mkXeKI1>53u_Lhpm;ExlndIDU(z6_Ilp)GjTPPFjBY3Vb%mPkP~;{ zDgCFdOsBP z*{tt$S4{5TlfX&w0yp~9@5mVn#8~zx4Oyn40X&+%%AA;e6|<0ciEig?$+N^i@TTDy z*S%#(RX8^t$iAETIURp?wjH)~?XTtBWfbcx8A#m(72w9u zjFymCOsKo`zFz~;M25h7bAZ%Jx_mA%$m&1XR>nq$ZB*1+UK)U;9s!qjQcn#${mi=- z#BKB-Og4Wg>DFNyeYZ;+qS9->7D^sxLXYljZg?&yHn!?DH|`I~?gdiEs89S@QZ{FD zL%w^>7NaNQk)Nd=`pRLHvyJ6+luurizceK{AVq()nBCPrM^J7-_!iQ1N6-3Bv5de& zjzGWEL3M@1SZ1*)XJ*9&hpb%Jt{>KtCt6kzl!K9)SnoDy)79@(`$P&sHcXm+HI}&O zN69*z{klP~g(S1{9-7Lqo>_l)RI3lIT8n%43PCK)wtO*86!=I#T}IF*_Ay&kjFE~% ze(UCrh#6Rgn=bvV8{&k3h+Q|25eT-<0XKyDg`gcUt3u58!1ghk zTa3`K4eztqsruqop6$kUkX${_lLu3op;XEZsyOOufSCA9iuLd%v!Flg%n_NJYs{>| zSOxrOhtuwe^!u1xY4Wug*)_5HvoN-z>sd<;d50-frn|~iZ`oWd5^JIuOsbRRci}NZ z4XqnuKs-w5^KP2ovAB@JiTJc~7{+j;f8Y4efh+A|N6@_(GY?8*&oXasS&JSY6^Oop zbJZ|p;Lken6Qb^w;v5~PX<{(0AjW@|6gIT|{<3>wb$<%aUF>cCT2;MzyRE(HQWYY~ zYA;8^+a_i-t^mWT)rT?kI)a@*$!t5Ik`&pwgf^5St{EjgpUs?@8&xkq5X>Xcx%jGo zQjql`ToeRd@r1e#DXms2p@_BEV&T$TT@8~-cshot8?Oy_3piE0TZ1Z;kw=FdFlnV@ zw*6{Q1zz952n>G8S=}%HxEVuSKyP}`JkENy`?Z{ky&-#f7vh};DW;O6l9at@h)V4cprI-{vE_#z&1*Sl zuED6Y)(fb#o#ARj?~=wBv<3!SDQBFzU?qExe9i zS$HSJy%FJ!OjneRyd-N-y7plD%(v)s!L0ar;=m6qlYBm%7rn$2Rl)-plfLc9M>>iU z!I?Twoo2GQVo7Jiyoe0rhu%`LmZGfn22qjo_?h@OZxGjbl)t zCrf;>&HYPAy;*(Krv4|q07kteU#h}DXsBs&x~Lj9b3Z+dK3YdgfeW1vVLBDci+%GJ zL+?eR)=elVa&b4B0ku^b!7yUI>)S*I^-uHzDBfRgx3TBA#pV3sa|Rr=_*}FHk2ODH zJyu;^-q%?7LSMcMTx7DyFa_7FcDtF=Iu|Tlp`)TnaM4cKy@k?gf%?*jCiUF4tX0hC zQLbuf$rTM9?kIQnyrDSdPJMxHCC=jHeJ*w#K9%UcwA@&A z&4V$YW1YN4`goJYzp3eJ6b`p=mJ>Meg^8J#&&FNl4Dh+-N+!1astPO*{X-R4AH8$@ zQx!Nc0Z;{kvdxsKo(TqRyg7R_PAr=u?@!lCwF)~$cacgtXdrnx$?8GvSUdztEH|nj zX&fu2jr~g$h{}-?mYWlocaUeJQQ05TE$#XO9>uZU81ECZc4u=gZ_iY|L`S(Wbhn{a zqml5Tg?YmP)p^r?NoDnUvuh>l@r%JAc_@ihX;Fx#fx&J@wk{mo{~k^t;bLi@MMDDM z1lF9$mBcR5iW$Z8gCNZD?5^eLhj4lnoSoUxc@a3y{{xh8Tk~I`ggqp1%RkDfbK(QF z!QEoVvC3MFlOqDf)`8;9d;GQ#mQxU@uOrL*4WCDj)O6!@ahP=QxMo9Oe&{nKsG!0c zl!qPlUiz5#MG9vyg|f<3v1)vk`HcE$2L8Y~+PrI?-_jo9_-F8TIEsv$&AE=`6tdrzKolQlD|lRF;k1>+&tfa4N*YR zj{b#Y=0kpmyc(Fmrwcu^^dXnerc(sexK9@CTL=k|uZOs>w69@<;)mvOy@iRcmMV@R zH?``3E~(az9|aY`Fm}yh9k%>LA_c76nQ9sHrP_)LSS4qQDOpC$E!BIUmq7^GKbUBwZrUxY>h)I0Tk~~(C7FsX-mmBon|#Hd={gB)AX56E4qyQ9t>IN!0n$Fs zt?YC>Dzv+u_o>Z>dy+7((@?Z%UD}KN&U>iKaq^3xG12TH>(Cz?EPaKoA@}wpf~tX2 z*;j5n(7F7ld0RVPcp4^wkwLxOm`2l=R(*{K$(_!vCDDn7~i+dHFfTVAhal&ZYi=z!iA{u1D)IP>GC z(JMn7hKCrf*G?$+3OO6lXk7@`bcrUPa<<+;4U>f#rTpRq)}D>5mG@zzQfj&p;4|Ux z$9THkf1UIHx}>W7kAMI$`sg=70G#yu8;E45dd?7u6!vD?|NdOSNq#;CaJv7CFMLUJ zro@FOG!AS28V2L@cIeIPf1=)*55k6I2>C&&Yy^K}6M!eZBRb!}xst5E*TZa7qcYeE*x8po*M?mWIvXK2R0^){Tg1mMWUKSC^UM8YrtzUn-@vgqGQ)V0>4YV=FtFO zM5O8V;eLsT@}WBWOWVyy4*S7J#yEd7C)?am2BJ^j=VNtF!S_)>@6i%=l9t?4cx8q2We*Q%cJ<50{Owpvn!>&;N%E^BFUuuW^toEfR@xR- z5fy4yw*jb1ot5gIYiWM+Z`U8x#UcY}q0;bxzA{$$am~soh3nM5-TavR8eM{@qdAqB zZ+jR`cej#;50(xzaip5*hT1yTDzI-6dfvk(9`1cHG}ngPva~n74gX@8ux) z*$1rx^g(+q10i1fpwzO$;pyum_A`mjGKq%xlVIGfNq~Sx0{wR)LdYe#ZPDOX3KeUS3 z7$`gJsoS$K3w26@{#{`aYRI>kOA37!bv@VrlP78)59}USID6E$sSjh~F37|zPZgp5 z#VAdY$>Sk0nJ+a{)Z~jS^a?NG*)ft-MgxV)m?utujl^tdBC~< z_s-9I5BGJi=l*Gr+2Xa$@+))YjoBOer}J%<#C0IAJ3u~6jKv5y>CW?|Rter%>iGnH zjFVH>&e5gF5q9=r_sh%u(Kq4B5jyqai*t9;nJ(}91M}&7;d9RNg|$HscsFXieWlIC z+kD;)Y<6;QxloU<8!s+zZXDpHr9zJA-#Bc^T^Y6w=3WL7Tse8H|Ie~x4;y4`UC~HaPTn<80KO{UnlNIV?mfi-Opi11u&elpa`1SAmRm4rJS0s)lGDkY-Ol^9f%su3mfSNWxb3Wi|d>&#f%hzik z6NVz=LDdy@0BM%UMdpAqt6KDO?_FV#|IMyj$q6tUtEky<_3#!PyR*`YzZe>;40huX>e(2$IZMnfcs7IQ zb2CAMPgL<^jSDj+&-vg-n+qCBbCjHrAOk8b3Y>QJz)zYRxWeUjTo zH`I?-{k|g~@us0-{6|4!Dqzrb4`9$VmN_k8&~z7I(6khI4sf<#`By%h z1Yr~3PXtp}%o~OkSQ;dFJu@wAv6m@2&kxS;d44=JN|mnSs~zcb3-1P4&c;&pr2F2nkup-ZbRp0K3r$e=PY6Sg2!+AvYWxp{7Ro7w-Pqq}~qx@5)n|YhJ2FyJuy-?-z3a7jk0@62uOFAbT>$YbV!GENOyNicb7^?cS(15cQ;6P$etLFKF|BU-?#U7&KY~0 zKXbrbvRE(}YdG(DU)L=H%%Z&ZDZ^{oy^`RHmSC=@u#Ys7c1O$o){bs_V~RtqIC>Ya zt)O-gC#x?sm*denX*WadZN|nW_!Mhih^~!K0~CuiQjj=hOWHn2uqaYs-H&+hU5VIG zT7ew;W``bk7pSFwk2BrLsgSU{P8sg=d)IR(-7v&iewWNH0%U`j7AoNv?P7D03< zE6#2PzS8R?1^w{Z!efT{@fM*L@8hjQ9mX`L?Zc~hn}h<$U+)3m-weVHIxXmMq}FXW6tTZx8aM?T;$ki6FZb!(_l7=I*P{DfUc1!}__MV3j^_76 z6J1@JL^OHCDnmIYx@BoZHb8R?33v%zJ7{rJ;L+#xt-`=>4|s8ZzJ?#atDy{`U#|%U z_+9T_ynS7kh8ykRI$B*Q%7bM)mHfOenlSPZht^Yo_s6Y;?OECFTc%q7)3~!Hq}Q@Y z$L*xxSxWTvcVuI9J2R$DEXbdI;_;S5`DW>5mT?)0Ee}#X9YLHNPAKQEA}Dbs&M28= z0%ph$S+=QCNcO+3Y92PIAdB^^NlDy0ZQAZmsc(GKjI<|p86O-X&^7=~(MOeKyL1)P zsdW|K41x5G(|(|Kzmrom%{3y|<181HniTqeD=n{Pl)-$rkH6?v9rS zwVj%~5B6G2u+%0lt1J&Y*xD*)s)vmB3ReI-ZHUTe_dRekU)=gdn^db<53Gq}K&Vhj zxE@H;;vJgF845Nn3e-D`iLVs9CT1I4S?pHB{Z#xGf(L7$AFat#DW1hLrlem(m9M1> zRnzaiwK=pW39m`q6htk>D=wxDWa`OJ=p?q$&Oi$pfK7Bsg!U#$QA_9Vx^FpNL8to} z)+Qr?KZdoFMPzwx>1`3DJEQHv3M_OFfz9JE8;HtC`o;!#&}pu9VC5C{KH6(+jB3m-co~U;O?&9?u$q9ln14jFyeV7p#%oixK-jt&t=xj>ZPRb8R zMboFA?GhC;saL*JFHc9*640@y{8-bp@-*6xXZzPb$9=Mb3(wNUuzUh;Nei}p2tF`5 z)ZwL6Ss2kSHP7_f3Oxo#l2n2M(W{51Q8+OYYB?n#_RFhVP*x`Jlklv@3cC*fZ22{MtNacL1wCria-okxk7v2Mx^xVFJI&D1_+@yI*zIxXhk8?85EbukhM!AaUWwYZ<2ykC>ro6fnkT%gucJaVbZSZ0z*XLI4 z>^53J?iuP7R5QddZH%DLeS}t13gfgl&q~gPOe?42gpvD^qhi{Vt0L2a$S2l)U9Zs@ zc2CZO(s_cADzeCm2A0JF7D*#9-kwBN)tZe#TAL~0H8cwXQ!UBW_0f>7p8#`N4Y9mxNJRX=MBgs0M6#OAf}lpKFO5zLJO{MQ8T` zbD18CWplMUt*zmGTOVuFf~vg>2j7f5%ah&p>VCFY58rjpmuY+R`b>Xx@&b%oa=$7h z5+lDC3T<*U&^)(n>gb-?1HT^K)9b2ELxxxWb3L=Q$qOgk94WSqq;>ILG@XH)(}6?J z)(_-_4zDVecqeL_mekjcYWB30-mdog6Ipv82r7SVEaTA?6_NtnfuDRZbe{q4K(Z$< zfVuWd2IvRJs0Or~#Jsl6*EkZr&gVC@B+H92E;9ZW)c{Z%_3DEkiX zCNIqgTfvJZ_7>hO&%2Z}UbY11Cby@bu*5gbCDO_x8-L|pIiXoF4xGC@4VK39FsiJ@ z(zrXU{$Rv1Q}bZte;ezV$(&QXb(nMAn3L6&m(?4I21D3F_=|0v99Hsckkr!o!wP^ebVKW-7V2bQ|B;Q*! zMlQ5H3o^n$?#yg$?ljRqxad9igV!-o5xDFh7&gW)Cd39Og({tXMOV z{HGWegjGRbto#y^oqZI1V@GPE$}8Dq2gD^+*wL#7UzxAWZ}=o16jSyq!$V@L`lg_? z*;=*r)NBe}@Ozqs+7*54MtK@9vx*(S=9DLI zYd36GRrUo4Wtj(<#SxI`eH!nxfW+u z4fD<@EW9dCYy+Z`lW19-VrflyS%8=> z6nXme;zR6Rt&YDfd8zQmw>22>E_RlRSy6HlyK4U1Tp>%sX)1ND(j7`ui+Y4UA9HXG zQ`Z}Gb{H1S!GQ|MG3W|AoWW1;R^#KSTaw8sn)6c`6LrEj7PagoUUO(~wi^(|s2vWbX_^BK z989g&)B+QE0wStZ0F9u@+rR}aB8VorhCbs|_Qjb>k~s2CdZf)3pMmZY35bkD1utRL zy=iv|+G&3(Ct{8_5CM)n3h1$lA8qd=94XcQyIl8(4f6HJ=`w??^Sm(+dp(xfeX>~F zE1PX=o4)A6P0XUH!TO1LF>V*#iQ?$Tbhjr$E_OOIJtYHkN~fniNz-iSkzv&+m5h6z z{Xl>2*g*cA$cdEJaE@`wLg_*HCX0D$E)%q=0EM|QYi0(=?s2U}P^qCM zt`IhpiVRxGtFLD>RrvCaUv3q2^2I@pno;@NSykq4F%ivpf4Cp9oyh28Y^^xz&Qkvrt9bupbhI(8R1)3sk)Hk)M?i zYZf6R&G*bmV`v~ZlC>aj@qO@72P>hQn|J!SH^8=hP2KcDtoN03qqO;x4^|jX*f)tK zVqGz2hV#>MIW?b|%O0|pL1!F_U#%?1)g$~->k?BR{@Dim-3$Bmk%B?M-+Ng=q>Gtu z_&d-Q%!{%U%FGL0BNEITE%y2Id4b|s1+~|oU;d2mRE`6ee;C^Z1_$FQ?9Uqr#g8`- zfZ&(M;%`y0U>=89W}blHf6@QiBuvW}@9|-NPua;6o}fWJNoeC?+6=mKdAlAt(BaSy z`%VI1egc+&$!y>Ksws^`y z^;f=UbwYA*#^O+3hk>@c3D>%G@H0o7Qdru8F%*@wZOb?f4xsS`s5Fd_?Z@{=k+n~` z90>-K=3PLdlb#3ZrE!V;`{Y-;Gh@Ya7B5iQT_w(O_bAosEqEUiAOrN$sHXUcqBi{0 z^gRC(f%F7#8Sa^(_BPqz>_`7~!VSOeRutvCIFLO}+ThGZlPP;#aC|RBUHh%4)iJ}6 zFReS$Q%^+>ucI}Atrp43?hg-fB@5VC(0yaY@fL|@necCGf~1R!h8lS{JWM{AvtM)G zd|SMhzI@UQK}Iab+~lgOB1CF8pKk%_x;I%HVbQ|((!0>*QXAIFUUT>2%)L|H zJZ`$amsd;GAqBp+Yy-`{>h6tsp-54C(vZHeq94^$;xZbKN~jT(V?b*hg?3-sXH$AN zArQoY*N*V5o=FsS&3Wyc3PhrgCO@z80@2Cv8G454t*eWz&76`CyB$LOyh~Y3-pIr> zTt^R~j-ssFvXQqG@X(bp(*b3dG#l`aXI_SE4Ttk~9FjiU}Ih!pfpl?k*>|@OFs}7;HhTZ~_Kf z!kKEe@6g~6k%3w492b{^lyJ+7XNJEI9#pY>Y_|Z5_V?48c!P~oj2~tU&D(n2II9|A zO|VbCWoa&QnY_V%LdGKo;+nfz07m<8_;9gnwcqn_Pv~qY5^^9FeqIFPf|q)v*@Saq zbTQ+XZ}+y5b|;BV#-m|C_2IQUnLTI9%ptIdEpQ){g2i)g=nA$)Z27o|eWw||ym$Zt zEMnjLH5a+&Ej~}Uj(Lla`HH96x+sZg>l`QarF6_%gb;GspbM>{bsuLE8)q4wO?P@m zV+R1NO2e|PHT4>F{K!bdojUQq_l>a!Vy!lcx-bz%&5$mUl56OTLox`$M$X++DP_e*N^j3? zL^vz?rz2FU34uo@Aeg6&gikaO;k#+Ipj>waml+yAh6L{~k$cMGPF~DGk&{OT$$SbS zP=jybc&dY3KcjZRwM|8M*rFnL+%*q_ojvC1Cbl4`Cz8X5<9qMGvL^2}C{pQmT8ITR z-q=|osqNUBZW#g=D3&nDb0p#akm}VWx#!IJIO`gpJz|nIHD?|YW7XH86dU{Y_;s~M zS*fHmOEQ-KC+$b*4Y5)ew=TsXJIDZw)qf`)m(y z+^@)^16Rr<0R6Z*C#nF)nloCAMS$zFf-`ksKDj4HH~h2t=cUvO&NnX8htE^L=`o?R zkAIas(~%NxtJT?zQ-O|vZsfo-3Y*{S9Y8=oO+MT8cPK*I@sj=4 za;)u#oXUC1ehzvQ8oD68@|C(8qgDAu+EjR^c-uI^XC)v;P=JgPw+{+r->Pm{pTjvz zAkkCWkUsJHi2IzjH=ER4QvHVa-V&r3>M6XpUEmU;#WkrxvVegWK#_$qPA*L=2|^XU zh8(_}k9}hDkZ#$LR(?-}WM)tHYK6Ji^$fMMV6FD36G@^nKDeHR@j5rl$gYEFF5DBUKAQ9RJM6$h-Z<%f@MKyY=VyUM(_0cBAZbxji=sF_ufr%ddOSORu6yD%Bm1W$SG7Uh}VU7rsc11 zLoAyjP~)gaCnxP-2cHDgVDCR6rF!>zoIPK0`erUV13tgOQF9Jyh1qYUv0ztsdS4tW zd4R-Uy1u$M!>GKd`1WxNHiOAlM!l7C=j~AaMjR9;7#j3L)pd@+iFJEXExQh-6y55CaXkcbE~BEH>>kQGs0FqlLFY!{gthh0^hM z(5CkK$s4_0!sP2NVlSBdOB8je;W;u%#pIuGSx6$0iFl+A{Bjt;mSwNf#CD>mmqgQ{ zFlp~EJ8u?1GSroO2kibum(iPSvh=g<>nJXD?1x&BJ70+2sIi>j&P=m8pwijDnIb0{ zmB+^?L$_fWGs{8(!i6Ye_B^U6?uFpj=8kF46jTzTLh|eKfo!3(V9r2vv^{gjx(%i` zy?Vc@D52zN?ZheP3a$kFEJ|Wxsa=STO4hMqj0A;Mw`w2JoD24dbi~fRd0{+myDziw z>*GR!8Ae9had-3Ig9h^!Crrw34s{Q0sZiUQ2R z9Qf4>~50Ucgf{`BN90~NU^#t{!%)^XCr%=X_BkB9IeTt~+PSuv`*kRD>844Ywy=)E# z2InDZv&|91d*;-?nHx6B$R<{T8TQrL=98#D9i)BbcK2~&*WC8FY03Lj3&Jjdm<@R? zt6mO{!Ac$&zcbL==nJy@{0?`HFCs;=_@97T<|AO{{Z5ghdp=bnOB7C;g%WE2{4c<) zaD7Awxd^qailjcko==X{eEAiBr+U@As5Ju#e0u`@AYbf6J2?0rQoQI~GE3WENdrL_ zoeGt?o>}!KcBZHmGjhyW*zwy;h@~9Du1I>9J4tk!EHwQfUVhip(0$x&@-~S#`gOGU z+;j#Gw1lwkv(C?rm1>Dgj7J@~pC)2`ev5{n~4Vmh_Hh<3=lnbv2JFL7N zL3a?yrSk;hHBpZIjpMI}kT)5~oQ<)XV(TV1eIv<@7(^@je$!?+(tpurGkTpmISmg! zqBy4u5`3LUuIx^EwTaW_@iAXF?~bYGXe0?VldS53xK3&hs4P9KR}V$qTNyT^g%N9% z6ore+7;H!6=mV0=UcFa1+7g-VwGH&CE@9Re&K_?yCEb|oSS7g>FDTa7 z-TF9LBbdE-_JQ5E+SnKRoF@NV572^KP?t*3hb7X%ocGa6a@K~DR*7yI=8R@ zTdpIC!pY>S$wjR>z?kb^fE`DN2@Z_=QiS`+BwDoE874CX$Euc!rtTM2)0wZWQ78BY zeVI+SxcGiLeMzyC`BD!vku%*90afO^W)qg&8k^gTaUpQA7HYZ0EqU@1W!%ggM#{y7 z<3B?Ie;eE2nT!6*z3d&9EF5$Ek=xf(s!6FpCjl4`kgUL1sx~#l*Jno%oU|!(`aE(k zubo%uO^|g>Uo~vdP*G_d5gX=Sy=?vL=cWJf?@RxN>H^NrTQ!=+;P=Hg0>~&YwqVul z=V9}9BxC$@9jTQuZwe0!yk~HRn2}_~U1PCZJPe+aI{-_qL-N9D8yIn)Z#s4x+SB=*Y^B%$E>Gx%ArdWOq#%6y5@=p zp2n_cAV~8o3LM*Zi}!j@Lei?LzOM%m*~J6ys&hY@<{1vy#9X4;bmSKrc=S*w*s-Dr zm4x3iQr%wCc2-Bq&u?t16#fZH3+EUC8;le#s_zcZTf{Dqs^!y*? zE(faE7Cl$sKJL%5*RMucetO6d?iuXN)e}4m8MGjWp}>o`zc2a+xn3uhuYSSfwSZO~ zR}%xARrph$?)@wdZ?~Np;S${XXnmu~!qX0;v7Q*I3*(w7(c%}3((BJ*uvQ^c9J~v) zWhbxUy;#T}8ZHOk5&pou5YcS^(bW3=Y3$6uk3Ldc&qm!1YfuJPK{v&g)&J*_{V z7XZo3#Q)af;vcS$2@80^)V0Vj0>S5F01EsG1+JNVBw|E*FW)hQ^}A~J{i86%+`N~& zb`}5cSH7~nFY*8T3xBEq*@b^nv{P`2HDS7Q;9RkILK28i(8R7g-~O@IaC(SH8-4Wa z_LIJ{_BR2CA*U3|X%U;_c>h~)`NIBx55`s$(o3% zt&`qGR{MV4oR(2eb8m3%GbM66YE^J`wsX4xr+84~Tj*Tawd?Cy8o9h2^r(e=!oo%% zn|Hl|)kndQyGFhLANpRTRfQiO8LuJ|(RNgD8FZp_vbso8$*O=FzEkfw<9&Y0zV~62BW7I_S4JlO~^IPBV zdL9vwR|Jn)pP}J4l7NQD@uC&K#_5o<6QW}y953T#j8J-EJ-zcIm+)G-NItY zYifIx$R}WF8bVg!?@$TyG17MpT|5xlEc945gic3E2pvPJTHn0H9;!n9h|#TnReZH7 zx28UdS=Vr%RE+&05W`%TvOZc}M$w9rDZKK8OG8V^HyxMaUg60t6EM!YEWxiBEXcSc z88Uv>$AViacO+&n#;6?jZB7wLsi)RaS|=;5)pTHx=neQL%was2S8_3_jgT)Ikv}nT&X!O{LXC0bFhHUN&m*dsUW8Z7;f4FUG zaOQG3@o0L#ID?Q;H>TTQ(!3}_b~j}az?I}?zhayke<)r{3OBB4Q9j8NwG_AjXL#YV ztadEZM7Y%{eUGu!%np@ed`5}=Fhx{T?c(XIW9mUrLYbb&3TE&sOX+Fu5PV5W{^qcg zn+Q=a(k7c8f?vVuVsPyINf@bA_XY7o2YC(p*b1I?;CSSve3kBIP#poaavtLjBKk%Q$gb*FUlp9jJ}7<>5fFUOLI^^< zHx+I$E5~5992vR0uw}u6*3F!=65i;w?_yW2T5IYA_OiYbl&2A5B%TB$e!OdH^cw^5YBIC^5+?#LE8w#osT!|QOJFVCqyWcMW=xNps1t~ADfRo#k!NQwlFHNA^lbd$8AL~L%7oqZ=B72OMkE|8+->B%OP{t)p` z9Q|4%##(yPlD%jq#Taay-JsMKZlydg~6*y_A_RC#H45SIw6a-=6{HRN#NBqTVf z)(r4XFC|Upv$48Zs6Am40vmQwD0j!Qw)KGU<=EHIOqY+{O#zSAZkmiXzq>^8A?Erc z21b_R2D<{WS5d)P+3vw-*r<3baOx0YH5geT7^^RsH)CG!cym7zJ5i!#k01Acp^Dn| zwwjZXGD8VjtAUt{;0%egsR$i2hYc$ax(k^*0@xDO&J3ECEh@_<_Qf(Y8VVO%zMN;8 z@veHEkj|bR1|^q+`$ef-5yymeP<_(&l-&tW{l>XLJ8E8r1h@Wm;7IG$QXl^a-u2g+ z?~mo-p-tc=uYH;fqudCqsKi#n4EMX~tC3Ea+qsXYO>g3gzkQ?YB}ensNGFR<-napu z{r#HlhRev7LvoRgLa6!J&{EFaygzGi$z5%IuvRi0 zJVFbE146&0OnkGyC@})m)^&91eXuK4k2BmD^Z@Z*B3$+BNygMWl<4#61)ug{^TdL# zqUg!z(dXDO%@{yCta}Iz<2n%NV4a;#Y=yE9E)OXcon<_KX#drZ`l}qKCDVH`c!eHg z{XDkiLktkp{?#e_-Yy$;EK3_VLnqy1H=XZUOacX}RZn|ubn1z0AM#BVeGf#o-F*+1 zz8YvP4c}LB15f|AcYz0`q~mZpm2hsOVdlGOoPr0!|NG@J>0T?KD~26->-!~@P6eJr zs;Q)&CZS*pg@xjKt?pm@V@|l#Kn?GEf9$PRS(>nJ`$cMj;V?HwSiuMrrFGL(GIEgX zp(6-3=*?uI9l;X+R2cu#=Mmdc2!-k_xSWGv(_8-i9gcoO{qZ1%SDBO6Zr-IWyd zXqXr1WdZ>ZL_BSW>8^{`T>{j7ZB=U!dRNZ-D4-OrE{cJ&RuiWri9 zpSU1qzQo^QTKVbiYt*B?0gqB)&6Z=i$cTHlKYC-Jx=wg#&zOt2eQo?t8F{qr@5;AX z3>Hid7K+vpSjSSj2`|>p&q*RlolwRS^k_`ayd@#m`Wqy`TM!2er9ZBHTfVY0ZM7# ziC5+yK`JZ)@|~s<9ge!$AH`R0r|Jw@mz{-z4vJ zo$?!GVqqefLZK59qljq>ilJZ!T6(Lt6(blCVI3d!9p)`uA%a^#3qzn? zFaC6&;S2Xp`P#{l1Rt+PY2W3>%M5K?A!9MO=KyXuD|(%ika1uq2Y0t;Y2|DM&si00 zZvJ*}co()`lzeZ5L0EV%`?Wg@=`1ijd+HY=TG&S*xn^4Vobhu&A+1h+Llx5}t?YC*4GkJ+zQnK~Ft_a!qVx_w~*_02|+*W1~N*re_f&E9o+U$f`@~a4w{F`lX(of_U zOZ6M6T+2x3H1VD2;iZ3syU?_ibnL*?!9)X^&pV@_!P%f0B{sal-MWN()NO*EhF4fl z;ijf3oWb=r{whh(Ph)Hp?_a5S)l6TtAlW?yrVjpqdD~>~8{dd?Pmt`G(TXM|Flm@O z@?D?CEli>yp}MQTf}c2-uSYSpOA8W~36+Bv6jt7HV=ICu%o-EpaIg}41qr&>Rx zUs*w_rX)_vRy?-B|FHNPY^CGL^Y*2$-k_g2HVPxve7aA0?OMsFh&AOJUzkj$Tew3a zLr5ZgIn8YV&Fj3s-y{@i(}1iyK~!SFj=T-VZ#BM*y~hxzu>REDgpAXVE}+bDzysp> zzR#mBUiPXhdcR?KNFIkpWLHaWGJnd0JQq)o`4z(_9dUi?W}(y{C~wt&h4Oxj`GxYz zm_S0uKcc+zjp=_!dCPk`??o8ri`&QAgU=V8YCra9P!EI@xT=&MFb(K(K8xx*{IJ2z zfCDkL3>$41=e4ae?^j?(Llh$eIY?8%5Z$&^V{Xt7$f(uRxiQ9yC|w$ z-i+USE+3_vR&noZXn^%fDSV#K4ZbHT zTZ|WxP2}!ZFQ;%dh0DTzO?K8}(2e+gynNQ%+6ISrU)|^`B-c3F#A`Z5eY$a02XS$# z)+CYKMBJQV;xouWqW1cN(xKaC8C6b%*Yili%_M(o3{y54=^KvU{{;gX}lJ&ajmHQ9r?O0dZOrHoc6!cedyg*P!u-D z>EG&2Xfsj4Yp1w6B{V1DQA^)4RWM{{Y%Eoe@3zo|)tk9Ag#_bwf!Qt3tG=ODlbv_W z{geRnLSVqxWy3cb>5F0P6;)6QSqWs}`V#|t>Q*Tku{6)-PEh<%xMzv#W_gE_TvOCM+lJ!PH1id4 zx#g>~4GQWSG`CB}Zjhyyob$bzzjzrZ^|n*nP7ajX8v{Kt>i!zp;P`pk(nkB-^Z?a0 z#6;(@0dlDM#svPuSQ+ClHeL20QcQKa!B|UT{derX6$5goylSUn`w&?4SFw*caR2dO z(Z2-4&`f^|h8ft}0qXWgF5Ip*Q#)C@dX-%#KY1D@Q>wse8`WVJL?<|)et`^~~l#oZaKeD~Ct8_WVR|CqdX())Gni5gUK z(#bnxan=k)#KR!7GC`*M@Z7FFNp18VMkn^Uv}^ae8`e?U!Y_-YC|7>>tU(QsyFB#y zIq#?k1`l#L-&&oM*6zYqeUFZ1YoOJoSPq$L(6{ag3L>Bmy&qpWo_!K#AYME>w zeNP_}*`fgb6Ju$$Hg2)`0Z3C0usv(>#gUe)m#B zV>$E_zP2PkgvxfM9)vqX;Rx%k0QqwX{dJWzZKqmz_lyCY+gI0;uwdC7bp>DF+4Wt+ zVaZa?*O0nPkE47cScO()83=S4E_(-T&yv%^p39VW^9)_@GmAUul#n`=-5HO-m@~() zz75=Xt*_Btk|W;Susr34#T6v}S}9z<0QRc=y797ZnZ4rMHOjZkku11`1loL0O&V{X zuq)We=TAJwCQfXOD8bE=t0KT?K;F0%=pNzkLe(L z?AfNAYn^fY9o&VH_q5<>-Hk5iP>|K@p?_AnR=xjK4)!z2&12yFM+jg)Puzq zP!cMbVdD|V#k%8!{Q10qNz4rDZ(sf_DSq@Au!l{nZFl1vJ^l^xGFrJ(+v*trez7Yj zus=y;0=WrUfEp&;Rp1~%+{hPktjA0QD)TCWiw$kKfsTX9od> zPT$W==uk6Uc0o|RaBq^vol$ocnUCmv%CE5Sg8xmtLx{JXDP|mVZuasquHSkpf~~8_ zOgI)xp5A*4^i;YYu$$L4=?7r>@6pmD+^b*rzB3~yIO2|!!eR7yzDaV+Bcqb#|i z2Agbpiz=$oG&a6H`(GKuc2E=l3t<@aE=x)N)PLZH!*M?gVXjfJeF>+NMCbyd z&v@PyP9KrK>=(Xm#+=dhOW>V_vBDB1tU`Tq3<9F77uaW=dZp`9lCIe2>G~{&%2IUJ z^Lp6J)shMzhoKA{DB|0o=K*q9_6Ip!|AQRP1ju31@8obwgt`X@zUgb|jnxY5bH4zy zz~)cL&ELskMh%3!&}XHO9uIK98f;pdO!u<#=}y!I@AMcs_okXZW%Ijrk~ zOcXq=5GnMN90n!-K@Q73lEcM10|`ILVgH$F=q+NjkVkS@x8OTDJoB9#_IxCV;h6w( zm~i+PIV_U@og981^@|*K@_8hO!<2WE0CHINCpkQV_>&xlq-q}hMGjwzekX^o^sTY~ zAcupV9cBMX4qJ=genA4NHMl_ienp z(`kXE)svLFm*7WPN#$_$cTEp-`CX-C50}B)sW|ktoZORj5c_VntseLG-5E26XhoAw z*NvGbtGxH;EGG9v*QwKAEe)C=8&TlTDXq=##?y~sQ=*%5g_~NBJ-EGH>L7E-Ixo;b z>rQf=8MQXwI15GG)N8?x>>XIJD-A@R-h>Iqko8)16GE$OHK0*`*}#!Z!I=qXUmucP zS`B&l^cf=M7~pPKf9U+XxYp(-jg;F`**8K{-3;%~Y#W2(SMI~dkK-M-9BeOeNNtYE z5|5kKP#iE*i|?v?@i6#l&x#%-%62k~^u$dJIwmnBHlc@X4i*e}1=%ThypZBz4}6dyj&x^b%55238=ic=NA*pB#e2f z+dU~z0_TMeZgCOE4bKtW?P3`xe@A}_8nDBpl`hAMFoR$$1F8LxI>44SbzP%Y$EwVV zn&TGwF1hu{muCeX5;2x8)nhsF`2#1INAl#kJ;y-x0FC6E53$Ea)$jd284Py*-z<=| zAE;b7551wJ%Of@km>DvI6D`l zh6Eq;;-Z8v`f;F{J};*CyEzGTNM5_wH#W+*7*Wy@Cf0d@w%jz-uB7e>I%~yvSh^|` z2yG3zN;P=8>*`*51!Uyh22e8! z*U_$8Igo9^Wx0WBNb#>^c+{IsKwEsYG*+wI)fxk5HX|_5fiPh$ z@aQ2oedrcUUI>(S3}wJ;@T1?Wp{YN9`sV8fVex>3yD>Q?Hl5lH9SEe%6IOpy-z5|l zwXZuU|APV<@-y}V9QWj>)IrHpXE$o0ZN!QpG+$N*0_5_Hc*zX(^`2`+x>m+2^Keby zBKgJ;jl*1RJliY#39Tg~NxrQWiaSMDvp!xg*6NG1&^%`CCh=icpzK<2u_+7A5y%PS zURR0J*rmN@M^y8oN}q;d(QH3^fv8bBl*kMJmV!fr#7?T`ci`Yj2Udd+>du>*rR3Dl z?_&-}9tLe~5XX~ho6x?P?n-t_7Rs+^icttxMBV&6LUnIC0BMI`Rk`Z5n%WdI8yNPg zbqQEP2>_^V6>w+=EKu_YgmV>Kth$*=`%WPX-&!t+jt=I zm^6$I^T948hU6_K7L;Psr#QezW?di1%wqb)&!UCV7hOKa49}0ul&`Pz1@Yk>O|=Cd z*))ENQBC$)fK8**X(VD8O9|`Wq<9$lXU@>leQtyiZMqBO44(0Wnfd6CbXw9QoyJ=< z-H%`>PI{uQhAB(uLeBrjVpiChqEikD<__^xbuT(M*mM&w`YBDpqLL*EuSGhOika#{ z)ehK~Dh7kF0&1ZkZcol$uvdveb@G_HuC0IA$-DOlp>gw0Yo5PZaG_7|?<`21qgyKp zek9XaJF~WD$aXAdx?S{i*XC84rzJH$$GisUv=puW8HwsxDbu@U(Wv#Dvey^3w1i() zoCxLhwZ#~U4vNxtqtMIElm9KAw#wOzIxNnh;DLm;QX;r=E)_37A2L%WUUSUUoGdtX z4dU=d?a$1?xswQtOkG)=tTwCnZQJG4omUO`*1LkMU#WvEd7T@nhFj}*L{03&KM*xC z^yjp$`fc2$jn4=R?C0-A9gAJ^lHhA?3 zwW3_47B<&)sn`5M`jc=e)Q6*mah3>dO;=~f0gCx`BOMR!FhLL^IUY=H+>qWT3;&Kz zb8k>xBpTDUgk7XlF~oSE)}awGyUD;0m93JCZ{xraOUlkQQ$SoY6)fJJnk2iWFjE;N zf+ky|+C3Y0ggXl^npop?`wYWo#+t0BCx+{VZYLY0f+7+ca)GoushP#>^DepwwF5c- z%{E``HoelC$jXHzn+Vd52^kqF&Q6y|OxKJcY?03WV_mz=E;_zM z!@d2$L3iE@TIe%17p{HP@cR6sxxT9~?^bb>b~(ZL=--A9SBF6O&~WiHe29fIG*b0k zzbRY&+*)!W0Wcz8jC*vk%oK#v=Fg(6$%hv3*4JO7#eC+Bor5qh(ym+$M(%=Ig~}Ak z?i%RSX~4(wL&lZ&e-zNxa!+egu#N*J7T0wU#6a2nLLr(M;vuZNw3Jnt$GeN7J;-Zem-lf#U z^OR(!5+qHmfzf)!zjA~I@?SYZWhA!!eBrRWF+$2S78o>X(;MhHEQ|J&4{Cg9Sn02X z2fai6Z5Y3{RDhak1e9<4tQAkU+ksEw7NOq_n8!akHk(S$FF{w@p21R3@`Z^R-Lqg+ zk6L)gH#9~9x7a!ftW(Irlqbemp#3vR@Y#H^n1?_yURN*~J#d#kSN$)Bam?O74da+* z*+yoyKNaJXJIKX$R99{SH$rNf66PZ&+N%hC5-jK^eXH&n?XnYdSGCCg$B zj!+u_7+G<0_FRm8jhEmdk%q}Td!XiU9F)&GV&J;;!yo=aW#~6L<{z`!HT^pUSn%#6 z_$hwodlWxU&(Vb|v0g5g9sHF7!2YKcz`%iPNN6ceylR*i@E zG>&kE9`1e*Znn8#q!3STb8LTrV|32{1{`D3%MLU0kmI#=YbWlukthB4>Tp4hqjhAV zf2R(2WlRY9B?kN66$n-=n`OWJtFzskeHi&~)eyUJ(M=hLhp7*? z@J~!F`9H~@_OZq(=*hWc+}Jk*m-)f_b1_S(n$(#EC|Ixb{bouIRgvZthoLeXUQ9(1 z>jZ=5K=Nu!6qw_oYR)>JeO8+wx*fdP*>OdoZM((GU86l5Jlx*rOrP{^s9lp*xa1<} zGZKPn$AG(h8Fm#N3V+4<_BbN>y4NFL70c9U1-*z!CDlF6O9-JxXSux+B;=Ei(8@L$ zpcVgiC~uCBjJ@0>-|-_P!0-L87kk$E4nle3Q7@(!JO7Lee^?9}ZM_1UEC8}LP^JKx zxcgBrcB_q`74b}r8VCsla}2E~7vbWJe(A+55rL2ZZUP7ih-mW(e9SyUiM_%}rY zBI}k;E0ik#3JF?&gan%(fslZbx{>S;7CI7t_Z684|El^WqKt)QhoN zeh&#K46Q4HkU)ph^1EJ44)#Uu-$H`be})8MRloIOd{ID1z+3RB7jxn`vV@R$;tBPH z4&({xljf&S5}qsrrb4JEkEX&OpFcr*q6PXy;)x6o2yd}r=L6p4k^c;k5*!nQ{PK$> zf`39LP6EW@o_F8H;@9c_&&1;2cwCld=UAc&?(d&$@to0Aynl{#dCF5>3!_Llm3>L;Thg#Bpy4UvC5EHh?AOs7@lz+E&{>TBwZ-wRBm#4 z*ts9Lr4G-cNGq);mEJ!TwAe1Yms77Iqg%N}!LCwDWOJyYIgr;tBU7s1E^UC^(w>3p zoz+?k!m9zp&S<*GSG<;WHaQeryIxpkptC^ks+!s0evqY#_W~cc6&+i!;L;$Pzbw<( zLq6eUEYlM3-P#G4TE4Ls)~`fX8A$d=9G!QVQX%Pc>=1D+HtKC^Z!{Zckx;CTsZ3#x zg#)=03@-Mj?qmzr8Xj7E8rm1mHedJGBk zTyVn5lah_)+yb0&Eh-0&aXJzceMUF>q+`|ubTG`Lgq{m(YrOUY$Q+$i(MmYPuy}3z z)O+gPH|OHl0p&1tEA|xQh7NB(bHGsjSArt>X-A$uSOkq!D@)< z!?;XTeJsqIUB^vzR8hN@ns+ZhS3!4Lsr#69;|TY$&vw46hUgL%a_=;|GDD}KT9b`m zwn44Y#IYD*LW||D#h3Rj7JtRC2FBg2!#M3?$Y4SWuUFq~-+B_g0L?(kM_?DuOaF(p z3~-c%eP%#MvomV>$LZZJA-jOinw*$5u`fhs)LpTuUHopW2S}Ut&K`E>*SlZl)9q1T zZj8o}DnbinDZ)hgut_O3qPe+O?{FwhY_r_oh1T|%T}ffYX~s`osw^(KIfFk;8>8*9 z^NYB)4H5$z&o#V-UK6D^>bG}Oj0#!-tVfXf!{!#-4ho^EzlIW7zYir+0z-*$nTxyh zKZX+h9)}X=z7Hj)I>aqFV`KBz*WyCCL|HlD!ayqMD1`fi8JB+QYD3*LO~*wbFDHcU zb$^<_#&|5jFmaSOE&Pf5S|jrYNq2a+%&tON^iKzP(2xe##CfFEyD>CP#W9b${)hANoh$hR^Ji9`1V*$`>rwjfc#vn z<;NjrAoZC3TT1>(-aXF4`nPsY9ih!8eIBq9_@r`lu9QE6@^>T3< z^|R#A4S_=d{=1)|vPwMr-^wy{wAfAWzaCO>b9KeDlGX2VRt%#Aew5eqWc^=#f!AVn zpPxC?zEpuns?ZI+ow?&rZ7G?eLA+i(24#DC zR>-->-{@C_5;oQj-@0S10R zFYw6lzDJ92AZuz3h5xeIBG|+aR+*4`a^O7)WIu~E-_9441wY1cnRkq*8%TY2A5b`W zKru2L{@p=i3~$YS?4Wh1G1xtJ(5eU5vHs|wQKa7~kg@D7r&?*0I(^EDI?qJrWX3`m z;>M|RY5Qh5Y$1u`Jhv;yVI1o3qrGR(kYan&_O5#2aJOAgv1n;guwTtY`;XgQr`o>17O&-Bv1#98;V7oV5bDEryJi5!+cMoMXDJi$e2LgQz3=nF$t?~B! zb}x(_%2HPD`lSPE>?JVm0l3l)9bzyldj1mD@?ocvt>N|GIuo*{~OFSBf z#|6!)NCQao8!?>T689t#Hr1x-CK^eT%tiF9)Q6sSez=fLeEL*A-P&*{Q>NboiOSMT z&hkflW$Rz;l?X98llbQPf2yB7zpS6xIYNWDWrG|~*dnjmDq!LG*m=PleRd%sKZPmRHx)2w*9CUO*>5sJ)d(l^Pk;5#5P~UK(|f1S`)2{9 zOKY-VgXLSA3xg#uP(h>hxLQGLjFr1mL6aw!whEb6Z~JQtO}L2nrL&2}N2iYiPdfPH z#4!5m3xs#uE67g*d|afGHxhcF`(A%An{m*2q2#9Gmf`VZfdFIOjHIuI962OP(W7zN znMwsWyQ`0#ds8XvMmG~{bLlFmiFP|&$#DUS`NI;Ft`kQ$l|LcT96cF0AjWAB#jRk# zCDCl%12@q|K5lJyi{IzB&KueL0Xa(lAxorMK5Tq#P=cb(Nyso}Mv!kH%~1J&b7{u|+YIM#51BnrH==O*Gc) zO|&oPO*G!~CK~;D6Rp=W=1LPytGY=Nf5YE3NA-SFHb z(V8PT>ypSl6>jz>E1aS6)z19rUaUv?Jy)LO3>aS)b`@V1dj(%+{PGfC#`@Jv zx~W_3lwfIMt1Q7nLZhXW%_FrveDB%p7LTzDlH`jzHs=QYcmqP$ zdrm}VF&%JZ1K!)>>h^OA6|d^8AFk~V(b5w+nTo_K8ohq;7&Npo zKlVJPEU`YXOz3McR{TfiUzzaIojUnD;;Chk+%Tm7lX*7U7l{^Qn-F}~I^wLgTb$v~p6Q{h@psHs_ME<9z#cc0 z)mgN%06QcqZu?RUbkXX@zW%o63cnRF=xVq6Ufp@c$25;0E)n{U!M9fR6xT{4utS1m zTe(~6=bG4b-Qw4pIM)VP6Tc|CSQAgmzMH6L!-6?Db-?XrQ%?#u%UxXf0 zh@k44xRwZ~!mdbRPeD&V(}r%l_aK1bma$NA#}A`hc5l)6*n%e8HI~{$5P@B6;7-Y?_Ce$`EyM&|EtJ(^D=dNZ;E$GD?= zBA8x$Io}_k$2Q(xU5e+TW4?Qwwp@vfXO69%DQ47^i2JOzbq5A~+% zT`n1IB9R5OJ&f!y;Znk3Lf8@*_vkxw0inrL>bKohM9XriqGO|-X#peEWl zj`C#_jSOg_)q$I66QCwq7pRHW05s8Zz)dvnajA=%tt9$GMlnSpTY*!od0^ z009#OYbpFo3mlU5>eg}k7-9}}Z38ruo9~O_(k`3PDhD7|s;bE0H~t8*yAm%;82apZ z$~^+a(exapyd$Q$Q`}vhYF#-4g&ayJ+*CWO=MKx|zc?(-emX4Ke>p6>zz)mt9rlb* zG`nZAD}0a7{8fdeer3>oig~3vW{^}J{`CgmY%f;K**WzU)jUi0p5#T9DDmj0Cg({! zd~v=(B{2bQP~C98Z*J}4Zv-p_ZLawR>=93AsbdO5H@Y@kTZUhCi&V26iRpkC-7mee8yo;8D_rKIdLl>^z z-NW3Wjz{+28YJP>43Y%?3+g0UpU?>r;x(exa|%eo9SC;Lr6)rgBFx1+;- z`FIn-cXB;UlpUkzio{a4nNmd<7*3@CBs0@n_^YyF6Ig;REC9%?;7=ek`%!4Q;MK2k z55Bn($8#H=0`@BQs`7pjOq5jd)ec5y(e?OGWF6%loi}aV1>95UZz5^FEF|C4{FFjo z4fHU2P?V%+_9N^_yv>$(bGT!6Qx3W`_j54ajMEB|!$P6X`P42^~&3LA-lDQyS z{$SpOXmqRBQy#*&=kMQf(!9Wa6A+G(grKawsRonnRX!lm@4(Bd37EzmvJ6$8_Ku-OvVuXzm!FH?k$4T`L$5omcH2L7#(7Phq z$%?{1IxKNk`OH|cX&RyW;sQp+P(K#mc!>mu37OSGWM)6@#Ld>2*Z-4eX7&f3S%_&k zL#WqbGu--StreCk{GxS?H+=cAy9N#g>6dqR;BekNDCeXT^_bF8BhIIUw%&X-AiE-| z4CO`gfEK|%*{5+aT0MjVa%9Apm@b85$pQkhQ3UoK3M(`i+64DXO16KM4Q)_SCe~0(8l@`cN0`^&4ZKd^6QH-%)ZKZuWZ>7C$0JqY*0H4KW zD@{FrXzF?^Eur&6rG5vxjWCpRzj%ts7JW;1S$qTeESwL{PVDpX(d0 z)QfLb{q)xHc)6Ox|3Mo&C=)5^qp+_1ZkiDkc!SLX`J1Aul)#I|sYMEHWyT%%cJtP0 zy0--fhyxH)w${jI6p*U-c!<0rWKJ_N+&FXbrduGB#S0u;S0$-OZf}nD?>aNvSc&>X z^5ItISh|f_1g(0O4mwpN3tD}9T*}ht&sFl(=W9IU?@~(+4v^Fm9wfDVOgL<@ORyqUYbDsH%=dJa%vM%K2XB$3pYdt@X?!Mqb=^d_13XcXYW?= z($hjADakL$f6gF1lzBb`=y_~X{E!#lf;MUz<_uY%Hd^1q6d#K&EZPK0e2?x>|Rrsnd?bT zvkoea2*%jP_lH!9tchra%*=jyVl^JkFUVE3?~8FgsD7#yoKIgFs5an_L02hObchu? zm#U`E74ne`L*^8<#Qb0v-OERvIa*Ygr9OoH_l;YdI2`dEvDTh6Q^q2>`F93|~$H*lX$F`d6>z z&~>jR5#Y6?z4Tg2{f*bs4DebyfxMPMj{Se@wWPV`wS@oWwe$eImQsJ?wd~Zn?zN1) z>b0!8>a{HWgVz#hw*g+u7w29}NU+!P)nC1q4oO+ZPe;$amX}!s9>{Cio%0-RTo&ZD z#QEv9yhtN{c`bLZdoA-Au6iw%|2@Q6cF4fQ2LN$)dL415d=+uVGg--pFki(S1V)@m zT|=B1{z9B36I~+CdX4iOHoeBYL5Q<=m6u*iwd-EX=jUEa@9SPmseklZVuQVw-3AsC z&U^pLYsoT!_$!S7H`F45hMMi~4K-Mxp;oF>_WHb`w!=~2_Oqd8-}AGf=5VE;PRKaMCXksB^E^>Gk`$l_YPu8)A=w;xuxWf>w|J>m!K0_Vxt@B|rKn)ZeY;hhRV6I^_+)0o(}l zRBD5&-M&_|%4A!kDv+wXe4}+wKTpIRW-kRcyv239^Gx` zCmvlN?F$l!Fcra%C>Vnx=a+OGvvk6%~h_(f>zVEw(;<5 zswciFIAK7FdFY%h^5OA%!IO}oZ7<6S)PTD)(eT^f>I_q~$bEV{GmR+&9LxpMFw7rD z@}kC@IKd{M*<2LaIY#nYYtMSx%){ljSzGUc(kYGI%2;G%#UGY;m~=OL-;9PHfW z4&3pP*S+tzENDQ{0eYBuh!hvLk{J!#$M4E&6<7`}Top~`Zr_g_`t4);?yLihv-`go zXF&ktjN^C4S@tF4%oSjqeI)|KmX3cATXu}PS;;yDI&px-mUHJ~OZJsAv+H6@m@uq= zVx0YBI`H>m%l{AQz_p6nAF=_k*pi2uu!39nm)Md8EVd*Di!G1-EVj(}?}#nOm$3^r zZ}Mx_(%)TA0BbEds+G)qk_d>6@KZWfx5khXIiTs5=t!qGwOSDq3C<^KzL18Ko0k){ zdpEE#LR-ELBEV(YOO7};2hlx$<@SU`L;4o|YmdDpmLKM=I9DNMjnH`4$6=RLb0RrK z1IJ&yvx~FTO&5`?u1Zy9q0A>d`~cDHgd6kfbCEN|M^Uf+I5I0k>I@N7*T>S&p@N@5 z3pH=U>HQ}Qt({QBiksUo*9L7VnaKd#TxcN6{sC#ba>#}=8*@;-8*@mN+Y3I_&A5+& z<8%=PwvBcUR4(~2Hck8UD1{vd;`(bLh$@7~p6_@I%AG}iZPYMWMCz#DcsLUxcEl*i zZ}5XxYP`uSEp#}F%#9p@($TXwJxIr7_PiAv17yTXt9gD+)YASiQJWk4(?m@(v@>}g zj)r0@BdYAA!Z!np@qss(zA>v4_NU{WOccZwdx@q6LnO^FDgEepe z4Qo#CMD7ruyLt{e)Bg_T1jd?oUB#N0w(isERC2N3y_c>}5dfM$ z2Y}|eK^SkAm0^969=+E9fabLu8+0hz;Sd#Ipm`?EvpSUbV4(Soy(E2WtoN$<0|01_ zv%~HU2?Cnm#(wrtk5`ASDvJ#+h!htLG}j9Z(e(v@=JjG;Ra79Lc_J8S&ZdRR0RYV- zvaxvdcmSYzNT)Rp&Q$#Dvw~M@I(sTKJ^j!n!uyMfeOl1@J;C+~uyK!CO+$@E;zL7Y zJV%<7m2PRaNt?iQ^m>ghgrix;Ry`Q5P_mSubr?tC_|}Tx*YkF{bLypk4#BbE){}VH zd)lV+ZJsLhD$5&gWXNng>Gn5RxRBEq)MX3@Gz#Wkl~F^CnUKkmxJ2n0?u*!3#j4B8 zkFh~v`sA7C8lI%Qtf;PV$(E`iGTt`5+e=`)(R;vv|DCEv9Od!e-q<68t9&z*p;Mr6 zmcI)$6s}*c;m`I+*Apt18TX4gayECzDY0Alxl5}8c4%ErsX1G&-gV zHN2rp*T3%4Mw>2;mTDhIr+*qPtG4C6nmMecA=0r=Znd24z^$#~CnjLVYQdRzq%Uj3~CC;&+QBh=ivdA&Htade`UhUdH!iN#P4?nD~S zvv40YgE?n`0*c+c6#6K1Cf=NmULn&j1=@Vi@EFPgC-h>i;#w~Y&6jW+J_!vh?S zFiBiz{S?=|gXJD!+rbS{t%rd1lMaJkZQ{l)tDH|E41z@l3oY9Ui!R9zTrJ3tsHvec zqhBE$*k%O4O`)Hj5Rn-~s6vXt`m+(Pll%~v7&n!Vv({vM+rETXe5sm!>{sPQ27{qJc(tGzbd zz|*%yeAoR3Fzob2nX}na^=W?OKW>ZdYwK@JSG}3(L6=u`MBejKvyUg=p z8$NG~u$IP12(|4&ErG`+wCHc>4{qf}M#ty20otmxc7-l(o*ATjm@hMDZYW!uFHPPu zY$lV%Gt4JpV=QPPp9?7d0u_gMrmg3U+MVGb2w9>Nr`|w-m>6a6pNFD0kiHZ}PlW_4 zLXH<{!-8B=nZ~x3`wMi&27u0UW!kb$%Z3WDFST zmjIv2&nw`2gCPM+ce-q3XRyJTGe>-co$+(b+2G)O*1WCPSJlLD3AGp%s@oAy=)~?! zb7~xD{x}#b>rI9@khqsBy6Q&?GG!0P< zqtvowx4Ny>qu`AP#++4Fzn@fObF}q2XHo0?RA?csbQJ7sD>?Tu?zi~h%Qh2t;x zkcUPbJcOBZi3)qe^d6@VJJqIvy31T`ig6S4uZ$>-ni=MrF5H)~4w5l?1i9Y7+j} zL1*9p0d!WdtXxnxyjY+i! z5-90C!*K+D;W&;Te}$d_ZM2AEdcfg1gks)?(k%h-=5#xdvsk+QiXB!hE0syNs%N0B z;TF`KhMv14Xz<+fcqhVPJ@Mw$34+R$IAJ&?@dvYC)R`eRIbQ7Qm&0lMjjb6TDlrzA zTVr~DP~FvN$P9$wWR<|S%g5jIIgBY2&)hh4PI=+eYK`+~mC9x8Rfa%Uob*Xd*4PDF6_5bnc-uOlP<;oZo4Hmd~$qmpR7MV>-`D2(njCKVvEnpjb|+BHL! zbzR*w%mmWRCRt62cU9liZreEX7v9b!sX6nZYZJW915ZO%nmvWbey@)I4cD>jw$spp z1g9o7YC->Ga*dKww|op5Y*#0-y@f3ZcV_wpo!W>~U>nV_MIc~Jcc?mTVq6a2hNa7& zR##wROdZwaO%zkmqwn=13@Wt(onsve$h1>q`**q5fb_TJX>U18yc|QKRy^hY-HGv! zj(oCsr?`HskD|ymvkSZrWT4VCDWg8cP|CARDR0a!-|p6#u$u=6c|_`t_u`S&l@nNPm70;?A2E*9K-wSqjaf z72;m@XsM>>df-4;WU{>0mt~;}1r3zw7QbUQU~<{ORcae(rF+c~C1X*VsfVN^)d}NY z`_1`*9X4G8usfb?DH2QidaqdeD_6~w{?~uiHY4NCn(W9#hMOu2Fa11F;aGH@mSlCrvdnZS_Coa4IpH5G|$nw>!kzP_x z;cX!7jUK4L?PKkZ3}Cc#9WFyvTa8FXfo6G5O17D1l9H|~&c;Qg#qSqb;a>fHK4coo zV#?o)rL6D0(<6PqsH&8Uz;{rTfe}UOAwFf* zK>h5c(xQfn+l<6e>zg}g*1GO4PT~vFy+iX^zJiZ7Yn|KOScWFl$d9{KcaHR-r*&sw zWd=~}9YR+&HHB;&wuL^l*Z+XsIg+N^QHV+@EGIS5?XxeRf}ZQaagSN+X-bZho@38C-QOo&V9!JzUSiLZdo`D*&&nW$LD;i-%QCHibbpNH>TP?8 zu*xSfSgHpFy5lA>EhWgLQImolZra?pbL()(muVq;3(F8x`_)A#-`|N-o=&1k?^C?% zhhtk>YG?yrF3+-5MO~>#+9`aOejenrI4XfLDe@DTrypp9M)zzY>vQZ}2#nzJ^B%K} zVrC^ES8#$$uzgJ3R6M{`W>JNaQOA+lYV(=RvaXoE9DWlN>S79_1hJ-C3#YglZuCO* zap&o9L4h+}Zv^?IgNT;*ckkk64R5K^PkQV|x%V!x2i%hIGV2#=QHJX`Amn{-X^1lF z3+41h;SZ4LWN|NYU@agQI-g_@$X^IB#ohEvKQ|8Ab$@tacUM ztopwmX&c8jJNQLe2Zh0e@-)Wtahtcqk{<>i{@i~g{jXsh9+RZz@wbXE>q z=l@e>(Mi3)t~R0$$Sh*M$B;?-@K}pFnDF}Z)~Is9uJ;oR+jh=*e$K*Zn_@Q~=u>Aw z`DD{j68oH$wM7)C<7W)qJddbC6v@=H!m^teC~aUcJ5=YM8^~1^xg(hUOrU2*WUFw~ zrCrG(l4S~~L(%`3edvCqM~@>TVG&0IBVIv|4g$~(Yb8Od@8v{zPI7%@BFD=%6ypYN5ILtrZ}gcrA+uE;X=REXt` zs`#(SG7Zf!z6ph4sg3O`>3;7aO0jqo0~-^gtjke`=A)G{VNl$SyKX-Em$3Lg$q&9;UYI!dF_(RL`COZl9pV=g z!wFN%)P(AfOJ5#kSiJztGF8(5BFikilw}rQk!31@WSOhErH`OBKc0o?u6rNKbW)o> zkthT-Zo$gx)uFkr)re|1Vye=2=^>-Sx_E-t(r@WmpbxE%%a(q=jFUYyu(>Y=&yOw# z&rzj&Pqh@Re#Xi5l+=XXIDd$fpC;-^)xUf)oiz)0%0ePmzWp%MHH~?TwkMx=9JaRZ zFxcbWakJk|`FM??UDmI2?ngZT2KQ_=a;;TcYD@oMFbQMKgfg!hwIj5>;*j^~pl@EDntJFaoh2Ci_=SaTO}<8qSys@s*` z6Me-)N7ldtycruh*)N}>A~t49w(-HQA~2pm)Wg+&6mkC?Z--voVnzO98(d^bW15?r6>E} z@0s0M`JeBZ$(HtigvCSoi9YMlws~-CP#{+=;`1vyV~CQ&!6P`d10-u$-$KS8Xhw67 zAKHd)J+Pm;MeEt|bcZ1dS`KOSU-Zlr0&b69?4dbNY%liE9s55HzpvZ^3>vcI+=I)& zBsz6{J*T$(H-W}sSmfOKE83k0DCS)x(G8Cd-xVpD@87*^m|ShN(^B$4lCZ11EQl0E z4dLnj)2B>DBJPEGXtn)0Oe6y)#kX5u+;4-3N@0se!fSY*1aLOD5q|7M4Qf9^Tl)3F^$}BisuVg7o>(B+H%pWdNX5-70 z8S zQf6yV%KY;R_+AZv94KWj1gFf7;FS4~^fPeEd_h0^-%6REu?gi>*3PN3iFU_gox3w# zF5H;`SYY}Y)!)+3oN^q~J$)ga^^7J}1^D6_W`v#3NF0uvR@_A>CbgL{yxzc{@o3tn z_b&E%WgUkS{dll`*h7jl6l|)hf<{x)t<9|LoFKnW4@ulEdjKDoPwSx!b+Z>5clrZd z(j#srw5cx;tly1RLnsU1e*l}%wxNZ!KU$Q_(Qi^?QDTB!t+X-)6DqOz3xBo+_%jPXN^t}J%)<+R zCL73~dGsfLW)a}ebOQXD2kM2Lo|L-8@^2yh9M#4Zztk>L{{VX%oM3WT0=IT5R1 zmBh1k-FXM6?r^_cKRr6y&T~|vraQ5PmavlA>kZQF9c^b>b~YQc=|0${7k184gwDv> z66evvC@wQ(!$g^R+{e@A8e(y4VeY3j^YqXvM_%=0Zr!^fl0`qWg+SF7hp8ZnXj29Z z7YlH<@a^eH-wSvUN}Wlc#9e9Fy!Z&s{z$FkBW10ET&@Txk;#@T0yK1cUY!p$rFh`Q ziA&Ax8C~FLwcx}=CXVBS0?EMkOx)4xAfJD%mwgqC*lF+qGNHc|%QvX^hg-MnMNHGET21=zXSDdprRAAa8*ZZKt-__8bHETvNf z;MOtOkL2nN?fj?E)^oNfzh*Bldp2eeHxnY_6(#e82@djvp+}PVZLbj(uukHMt0nKr z9n~{6?|3qN6==UPiAN*g6#+MUGlVX10k%Zrv6%27jcDa~7KTVCc;4ncqCO{Z2ph+L zEH9H~6zk@N_ar`n3$q-E9NtKc-)%$M=zD9A?z4lzEK*4Sf)%k9J(g?Qyj3WHMuOy) zA%n2-l2pH#Op}VKuD6!1rkMw`Lul8r-kVR)2am9Gp%%u&$g`x9$5}lHzbG|#h8Cxa zeT20Zb@@agZxbc17btUe-1c@{wf><4ew0q88v~5|WHg%{njx+u6DV(JF1yQjM0!GZ z0a~}itjt&rM+Gv6*Jy!Uv5RSa{y_x1kKW)a-fP2O7bfN4mGRA_m3-7ZxH>4WfvPuT zQTWHu!5wz^hU=rWrMzik+(^o*iN!asVwuz&;W-juoZ}a$1-?0&O8hYB8~P5(C$*9r zDBI$!|IOFVY)Z&UVZ?0z)K37p^c!yw`dOvw5gcn9V2 z%%fe+1*6P6%Ou4d)XRfewc!Iu1=s{wvTsvjNuKn9H*U8J7ZYhZ){g(YansvkkE#W2 z+!PE~KaFhBj~l~bcy9;D5O^8?+_+i$9s;Su{C(>jxB10La;IWemVzyVriy;n5DOx) z?mXq+GY2_P=1|8f zBjtMg23EHdb3U=%bo$w|9siD$)j+4;9GbZX7Nu!_acFu24o!eAkaF(OJh|%79A`1S zbZBZ^acD;TbZGWk+yfk%<1Ao@rUuNVLoo!?S zHK7OB9GcfwZ~x%X#0w*v^j9yQ{TNh2O(J9I`lvj7ehtaiHU*)*Kfc`plH*JMlTG1Q zGfNJr4F~I6cgRj&D9y7cg^2M7$4(e8n{u{$Gj}-fRp*>8XhUvBGe)xTh5=MVlth#emIC{&K)p z9Es~V{NIlhHZA@xQUD>)K3yQt62h%;ej(7X8&KbJ&wvnUAI=eI$vemIVoMu|n>Y>Y zd7bmI7NgpevWqkw4tpXyVf=WD9OSLC{FWD(MV;97?LWAWihJ;6 zi#L&u>d6QD4Sp4u%03v3v=kY)3ASVcLD9!q$J2@$c*K72e=d$RG;$ii%PVswv1r~q zPXwSscjC+^OzZ^|G0n2H#Y{W{>54QNEOH!M#YJm1thszI_GiYw_Gc4n19&szh#2d_ zjmqUjuWr5E_Cw@Z!yf!WF5aL}b&nSDWXLJ9PQTf%OK1R9i%fLm9hP8wJb~OGOGK!V zi{IQL|32c7)5_5-2m9^lrImt`^j>;kn(O~$s+n!mEh)D(0$CYgpi7VWL`uz&c1XLJ ze0cFn_|&D_$g0#{^ru8q`k~9}ZxYSs-zAzJ%adB)1pX?~OuH)4v=N^FW*+a?Ie@Yn zeCuUya5R)laC^!h!+-=a*o3&G)<1;-Rsir!hnfEu@Qeot1DI<-VZc5k7QrvW=AcZo z(O!k0xx0oLZ^`n5%{8vx2?-x3n%*VP*WylLEJ$+SXmS>K;|Fk@lNX^FGRM!y4&lXf?I(2DWv8_RUd!z?> z53Y8SBE+0N0fi%l$@{S)hwtZsra;+zFbr+*?$~(p>nfIK!A9XHWd_OOe*1pC@L{}( zA-+e8{Q0k(H{lmcoG8ekYAE_L^uCAGvFbO(@>uwy$Yu`I-1c$$F#)e$5LelWi`=r; zAi9LQ@$EUMne95Xq-h_`oANzeojD=?9n?~-C`L9&81$^clepmq%{(4#2ObUb(3f*j z2L9=HCb8xX@;Ql~FXd_cn?ZoE+}_?ualGhFvBbvc&bV*EsE0R%a}NsbP8ayRwj}z9 z(--e8){>cXwD{Fe|LB-gGsIc+!Jwb%Uyd!L`EYE-^FdAeG_t0)^z=Lajp1*;LK)wq ztY{_7%CDplUigWa)xane(#xPb{A|W>cY=P6dV=fvZAP^8(B> z7UodSZvxt>EuWA3VM4 z(KCx=dFe6>TLc{hwQ`1!10JGdPgxi+`HgZ}Ua*jtcy7eDnK=-u+{lclIMONC&S_wX zygxATt`D+vRxmEfj_<9kQ(Gj>bS~V}^a!z_S&iVgQ#fta7F$vmRI`Hen4K`xG+PN0q%{&~lY=~~Ck8PqWoOZj8R z%%hpWYButMdLD=Yrk-OIZezu}&&YBUAL};1qqaIiD|i`MbU)7W#Mg7M3FRUUAQ%Fr z0b|KTq(TI5K9Mf(ECWO{$xD@H9-z`3%tOg6f?0LrQ=?Zesk(_d@g$T$>zQ%KFp_)( zpuG-PSbW>?z*TZrQ3Xzc2_185P7VhZ0zDTc#jaD-iS6M77&c-Z$Kmdkhxj8fTJtp0 zuTt@JzO^9m(zcvSGeeT?@3(vkS?B*R*fbZf*fiacjxm7;euVN2G`*37zrD%?at%VJOV;*d9`tXcuVNioxOXavhE|I>X1JlL{ldh%yVj4bs2ON>5v8Q!6M>{MFW z)#Tq+_F-`v!mOop5U}$RXJ)Zajc-(^NVo?LC-E!R+COsPWMp2<4~+HBA7{(4aT@0= zF}bP!NpeLoPgV9Ey%2?b=^G)U6qjrf=V)dfr!Z?Y<~Qj#RnLs?0MBpaeKfdvPs&bqBpKm>@P5TC2@C&cNLqHE zYA5nS!>#+x0p=960wXzudZ>5h_TcW$Br#rLn=Lt014JqyJ-mK7(^Fl+$v7~eV3h5d zjVV{|3h%uofTG7(+JBUl)uY@qcUn|;!leWmKyqd(JFY@SAd+4)%jJ3H&uj~Ly&DGw$=MQWRi*%rq@0wRc*DFxl45*xq zj^AFvsd$$o2hh^G_pdb0ykJ>85#Mdk%M7s?>;2!sG=pIW8fDCT@OC^p1^D)Ho;ofX zKz)qHTmfLUUEOC4zyaMFMgmYr_bhaYFJDu5HhLhR({BmKU0FBsz! zQKHqjD#jL_{VL@T5A5+zE)s{6@F^esopr;W^>tusp2nI)+nbkYEeG`1b%d;^5O!fw zT8ChP=DYW+o>uW3pj*1PvLTTlqGNw(S_yZ;DEi(FvFo^*w>Lq0D|Oa}Che5fj(f)} z*Y->%FJ7>+Qgrng7uAsbld2*9bNQZh(zJk5{iXeHP=c26Z5*7jMgBBtkcun5$BO(1 zS<)*BgLt=>UUi|-MPyT?4rh$KbY5G`AII5!;p1tx^m$Y%s!!I875BDUY1mXsKY?`R zs;4r=_fMuy+_5iR%;>V+mSwR62!{7hsp8yyZV<4;rKB3@)+e;txv$H7PNkGcMA5#v zL`%+c?$s3D8nirlO%UAR?MeGm%{9_&E5g4ohfnf(CT@VOP575K&~Wx4ZbA>O&(h2F zGi?c5Xq-x-tLFIh=}d*?~Q^ig>Zp$9@!Yw z@9yV3d(72v@b(=e _CM&TOU&RXQw%UBa>eUzik@892ug;fQbNHSxvLq9_-xIuvq zCBezT|2+7}XQqKk+kQ44H*T1twJQ#m+Fs^Wv+dS=AD7jPL@yJ zJ|MY|&U?TOSy&W(-K^Q4dTG|YlLs@<^+CBBro)+>>;*B+f8zR6#2goMzxm_#7t!o)GVWCd9f8ZAC1~lrLngHL!Y}BO@794n0Gillfll z5$R{~)SCy?qFRa9VTJ=+;s>ci%i72HIbPhI7uRfMOpbX&3)&JxADpJhw!WfEnyV{r znrM!IW>6n4kn*ZsT z{ikF0pN`poI%XD&h6Cc$8vp5-{lD8W`?}&o<6iZZveZqQdB5-5_>U*!6hhP8auEF7 zOsX)rJK>8`f&s1w@Z`rBwveCd&F$u&=W5 zXm{Di)WnuIz*Ria?G;ChgWyVSI5JdoqyGCvhw#_9V3%1zYZ;Bo?bU|I)sZU z3d`or@QGB5QwSxw@4$s9ll)#YlcS;$y{6cR%M<#3I{Xy6etoZvBsRdP5z$1FP+<^} zh}D5f?`}542+t~{iONvQn`b<`=Z?*PSTAdk8q}7ABkw1Or3b$ifa!mYXth>^A|jL_ zcf@>qqSuYWy3KZt+3r5>BoaY}#3vt&>Fl;@491K{d1Bu^?&QxBh00Vnu6`kt?0PEL zWa=P5v77&8Ik$L61jW(ooJNB`I~Gu6H~ zJ8QLgMZhdiQ+K0qN z#aEoNQobBh>9gZma?Gs6?7JGKXKu&qY9dMy+;N8YAJ7YEeG!3g+ew3b=9j`qFWteU z<@`Akjz+vrt%}&;Ze<_3_vFhP9T4LSH*C1cTV}cl9ogTDAuI;D#y-9AvA1p>60z<* z)2n>!_CaiG5maA2S~BV)rUFr>+?N{Y$|(X9;pKH-$)4KQ_59e3VepMjo8BTG3XJ|3 zPdRriYWO-R=&`izdzGe~d^g{S`9+A)=|lU+i+K>;Mxxw34V|R=#rrJD-K}C$wdOM) zsiE`q(^((RF4S7sx5Jl8)exGi(r}POR?NP{vHlF*FyHC$-8#Q<2+5PhB}e)u!t0`K zeF0jGY=?ad)R!@b@)aI$$Nc2&b17Js=tpdY)sb(0Ekex*t?FQ6aVIG+mAaEbwT2B5 zSf|XcT<9q$G_E<$F+@IzT;#&`Y5|G$!@@BJ(%N0ERJadnZfh|i+PiRuzYbos5rT|I zz{geBFKZEW*7P&!j)d^|EG6LKO!}?jZk(oSP4Jq@5U+E~_?`_(e>Qoxvn0FH zc6LJSY9tZ3ru1Sb7vGH_enYDkZ_9XhquHn>gZo3FuQB{9@X`ftdhO-NFGCU4tS zF|AAT5gXeHF6s-4cTY9y2DYgRiGVny{X55F1gMTW!R+|k`l=UMh~|pt$F>_N=k5Vscs|5+;n=V@dBBCe}PaXYM*ZNo|SG1 zmp+VNwao~p-bs*$aQL@Z_BT9wG;V#^Jp;0ZxK)C;#$j*weZNp{_o`tQ1~1p+$S@9S z(rzR?F9>nibSE@p0EH9|Ceir?r zD#j5tT*z`{L3;~Xr3U$RVATN+4wi%paxE3IZQ00hk-}P2=d?QD*pv&TFPrLumCIBC zJ2s&J$L5hFciimLn?!SPI}n~+^%W~WS8q$Ox$P3AV8A+k!ZDfo$kr+ih_6nWZaNpu z>n!bvQp|H;Ixe({+d;o`tz!0su-Euq=)@(;OiG#RFDSF7B!b6Azc^+OKpeAl+`n+l zkpIFl>$>rx40q`UIjxD<09TguuuW-Aeha>m+h$D(MZMXrWDnKBmi&<@RQ6a2gm=zX z5u&|@8d`fK(&$VuCf^eA#^2rsnKoZvHEmX3m^R&dPi0~D*Dg$(#uui|dMc1ub4L5E=`+n8?Kr*%OyE3Oq{DkPHYo0j5oFkZH4&wLB~JZD<4o z%}{)ri#dXzEy%P9dEK-bb7|VN0+}|kK&H*tzf7BKVAEz?2VmM<8-=CG(@L8i^t zznC_Ss&ImJ2usIOZ+E?b=kjaQwV^YrWSb+DdX@D)G0rjYlC2(CK4aBjO;k-O4~06t zY^A@)D1~JhL;c0$=3)XwhwZ<-OQSccsDnMG&QSN;`usK2nqwyXT4sZ+ILBrpIh^)LNjEyD80 ze#6z#iNFUR+Nvkxw7lr*;jR4WoZ)+4ObWWvZBk7_ayWn%Y zc^A|pUy@lE2S2HjD?VHL5vE|pt;FZ%`)aNo)j^zbzZ}Zk>Tur{a?H^O_3^g#%|csl zVVsY4zFth%hGTzD*NO-78yuhS$_IQC%74V^rQ5GOtnNk<3A=i$LgnZOlkInN*0@-c zy=HXdW$rj(0$i^)@?5k0UF)WAc}|s3FRcnE)SoxyKj_iSsvuTR43~Ban|iY%jo_L< zZ?OS$!Aai!di)+(rs3xposCtI-J@z|Li=9l z(|}Tof-!sExy7tJ zmC0+)O@lZl+tpUXU+=fu62Huz*WZ>-KFX+9QGRZN7X+j83A^1a zuhBN8fL>n(5F%=BEZ4B%H<6`eiBb>2xKF!J9%*c>sGXfcoE z=HFGD^6}JT;l{=r|0UICISuUvVb&j7vDXNb>i2VQ-1FUWnVQ0(aLE2enp zzP2$XHXn*p4EF2pF}|bV+PUHxLN!;^ewzl=JY(`)u7?In4+k^ zg5uqsuj6|EgD^90b}-4z+A8G1RyQ1X0wCRt{G)VpbRz!0nFO5L`9`1}3`mT5YSa(h z##G2w+OyL|a;si59>Xg<+YzR%rIp}y*ze|K@M(glQaDTecXNO>$tCVf`(|4w{2JwZ zq{p){0zC5}6WbKEq;$41mZ5cO^^SJtl(f>d>NN%>q5RHM%>30gT$Rt-&q{nM=Kh!f znC6{E7q~BXSL~myXsB6@iWPWjX`ewlCHgGfKv5phXm+;7ZQ0a+{pj|nV19HbAVbu@ zkRb+)PkL4yJ_uDPd?X%D#uM=ZE5KYyaWXTjGOI?sR%+jZ$&BcI&cY8WYRPnuQCtU6 zRPH+C?t|hK6uIOZOE({5lGwG5X@>7$Dt!=*Sd)0~VO>VMA@!u;=<$0G#>Ytggb;&k zD#J~vb8C|YPW&$>HfiX(Tf8*o3m`_PIG$PDpX52@X2DwCKD~71q~o^1F}dt7WawcnP_AhWio;IR{|=4`*)~ zRL8otYX^4^?jGFT-6eQ%4esv2-8HzoyA#|A?(XhRfNzqlz4qGsyyw*U&Yw|T58YJL z)isOfn%5Zj$3&1e^`42~ZQHthmjG7q$H5?s>S4j~n}Jlud6QNQjqx{eyozL*l^IlY z=Nh-)&e|T|)E{RpWO(>I;HgU`<13^E%;j{Ks5jCeFH5~Enk^YwssFpPrfz0d8xc^x z(}wJ)5S5tw+Av8$wldcoAm5{MA|>s*j>NJt3RCbi#Ng*5V`kTWYdf4@j4k_dyj7Ni(z(0gFfS$$|KTJ^Z(gF5Q zj}5R~8EL+Lc%XNx+Njqjiw7VHvyq-}D|FT~S_}&^swY77e9{D-LuX~aOmFv{?JoT8 z+nt@4lZ#umt+Uy=rDE$rVkedB_pZ#(JKf5hbn6KYjyOe~D^}%RB%P?OG~*}EKN@$k zy(Gr#GoKVYIy`rlcMp=-Un@mzjPF0p_AdMq)YafMvIf8LfUbl@&g83x`@EKW{gmkM zZ!}sR;fgWQgwFB*qTpI5nBsWt!>79q5hc3LNW=xtB?ItVgPw<6(FzCv5>-W z`nzYmT0BRRt0<{UWf-*=QxML)%WD?>QoO(1B@};cJvV&Ts8w47NL2;t?2;kZBuA?#eONS{>@G&jOx5&oGC{Z$Z|k?K~VUT z0-dXbtSbLHc|k$fzT@dOP`)-^s>KjZo0Ne|E4@=rUHUs`D!kJ$J~KUH!T=Eb{(@5H z?r0s^XH>wbv|0L^{+9mzhTo&o^6XuZM?+j?Jz4;x(z*bloMAz|NzquhAy1@Ip*=n^ z6>woqrjQz1=@A;v`)ZsZ>_M38rP`A@cwa6A$cP_FbyhhfNKa zi>XS9jTxilDZC<)Pe9dHIbFRG_{B&$3GLU_FBoqcP}GD87?oxvI8;pHB86VidpTPC zDHg-`v!bG`6>8me6Y%mkj&L;ly1Ef7u*kUBUvH^{HmyR>sm{_qch>5{{w<_tdSAhiZ}Uyf@#Gm3y&)_$Cq z3*N3x%qvHzTU}&|CL^=`N`0DamQ#(?~?jUXq-kq8BEUoao56hu~o(MmDZ8qS48Cd1aLrDrMW}I>Bllo zibM*Y9`Z?#59{xd#nhx~@F?AH4SCv~0`!~*ZKP&nZ*R)hm?Qx^$+J(nQ`rNtyw-o^ za{l~RE@v1ZmovF5ldf$Nf$`USROh>!1&HAMx5$>twQV3jOsE9zr*KEZ4xX?350Ops zbjS_)J(ttC)0VuQ_V?5@^l$I6oOCrB|A^((0>pBT1_Cs?Kc5DFeJps(Q+e%wdylhZ zX$iz{@w;{Q{VSW(=wI2Ki{B040oj})Y>xtN=76})f6HX9f+p!aLi;$t%;Rg>*6_ef zU*9HJ+t#U0g8wZ+nz5by(~_hd0{i<%CBJ?>@NVTm1D=?h zCtxU=?itFF7Z%`QIHavDw|^o#cICC224r^P#oglkfa3zFZll<4|GpW(xU|1!sAVX4 zp#vVrF=WHq#Ush_Vcnsx`CaRwA^Z0Uyp7(T~8TTv|2r2VN39TNPWcvSDYsn z6-KL!C_eSM_p>#S>*&hPGh+9^jqZyK$M229S5j~ulWjG#t^t(-bIOb6tcJ#{u;;e8 z4}96oT2EQpDVQZSoWX*F=$RWcWIwzKnzm|PSC&|0bMNT_S6EAixgPgGugsSS|rn(5?75wsCc9C-QbEU0pWoB`I_g%F0R*Co!1X{>XZV}I&M)sk#$9U@9hc?PR$})6V{N(anxU{1zX2T0H4Nclh{T7$1bnE6(SA3 zfMcOll-5u7oeY;Q9Bu4|a}1az$Vu}at+vqc=n0na4qKD^&z7Q{jCmWebqFbAn?X2x zoxY@=XV^%nmUbh2dMuKjH&|$(%eEU4Bi|{@SyfU)9%ka1WjCvBNI~EyK8#j=0C$(I z{IV@0%08k#P?;F_14hB8Uy5Y&duQ*1cGqxlxV4k;h-Ri{cS5*&+jv$@y6DcdW~tq5kz|ofLe8GM2;A+8I8EeNUcqebO>QT2xvX4fTn!eDrEZ;B zh#`bgTjexhf?9C&ObJdbvut7*fn)4K(@yGnLcu1OVgM-VYe8{7xsW6(1)=lqRbrfH zOD)2Hb_y+AIaAJj9) z+aNgEWKUh^*o5e0pn#{?N}rOc1=6em!JXXEv~;m7Ya!yYHdrvq>dCKJPYcB}+`FWQ z7PJzv$?{sVHnI!XfwM}e+gRGAtZep5X|@fNVj?sJqS+usq-A!zI4T3t3iV^Y^BNLc|fP`Fm57N z>%ScCA$-u2|A@quIgBRHab|oh8tK~#?YPUK&I%j-9E*}&|19k->Km%|sfOSM)*J89iZ;3-7s8l&jNzg$u{ApTl|H+T?;>7LL82nStIP7VT^y`K zPa@K<0?Dm2}!Y4Dz-IcrpX77a-HpT z6>zPQOg8osGd1DJKqBhsB>sx0nv0Z;n-(4V-)O{~ly0n~JU7zc1B? ztOgh-5KAx_j|?l{r}#O1-ci1#!kfDIRQip}nUFO`uD+J9cm`>CtW4i(I$Fw7CHITW+8ci@oWm$SBrCG0pk( zhw)0Mn}~93T|zVlxl<;mb&T|>h?r`>MRiOD2byc#Mqj?MT+v^~+tcytjs-k=fH`VV z%@Jcj^K!BI>(jWfkf-AzVx?;btke>=r}?n@<3O;pC}$s0BIR~6l(ypN>+l8enYTJC ziiorzi#}JsHIZz{ixsLc(V}wY-GuceirP>wkR?NXUkv~TVSvXW&dhig;#ct3%o!@Z^m% zO_!r;W0``w%OutC%&3(QR#j*LIwfl&^|H8tX=*58pxeRF_UGMz=nWD-m9gP0;y8E< zI--3CAvC@%KMF9Rwp2=3=u&wTzFzIoz4}nFR%`JNlajCy8n*x}5L~aSvWn^|G;9^7 z#ys}mL;O9^Aykc-vMO!m{`a=%nPbJh2MP%|aSt;z%c%1Ys)wQO0G}dPyI*OKX&aF(^_K|e*y9cQV z(!9*{Q&)s3lCS2|^1rUQ-AzHz!`UPI_wMNQ0eYuD33R97BhOAJAQ`)2T|1!v0zc-u z)4IYoCzEz{GF_cELBBqopDMH2#(L&K3Mvc?maMC>l35X;I^L5=NxzwjMj#D4vCoc_ zyw@geA&y`jiZxOVtKd_V*LLq4LlUt{;Cjw@P*V0cJW?nLHyXY4dzs(Hx}6cS?a_)k zqsu(3gt?^R^@)LR~1nh32yCj}8{{wiCIrjR)S1nRd8 zLhoxOg|3LgFamY|FQv4}5>dF6H6n;W9WtkWnvx(G&DVtRcj1K3*|r!*nY7gg=7cYS zQbH*rgRcyNmzFuPNFjbdgNKmspLf-=juZ@t$h0hMZynUw1Tz&k7VrZb#hj*ZV%p1g zH=Y*b&SFN+?sXM(D(TlrLXQOt!+@XXqtx(FoV{_lJ-p)+<%x8 z$iJV~iUO=w{-)4U=W|Txm_}##C_ak%L*fLVRWJ=mxZg!E^jRE)pDWb*v|H0;%%tT$ z6h{#yN$3aFWkk;>u!&0rh@lJ3-*7YZr(utPOr3f%W$I zZSjOCo!m}guo+vgBAXM36YSF9hd>c3M>e)Hy~=sqMy_-qOQA?gf?=!*?uWv(q}Q#% zLGxc$o%%AsOpMteMVsYLa;&|4ANV)ChUvvm66m60LZ=+i7g#i$r;u#BF0e;Ek2_>$}_!n^&TUb!Sr( z9Z;PoPm;f1zb;YnGBoP7E*@|@_D*~GMu~%|m-E(#Jw2*e*fTtmaQJ(l2ezJvC<`W7 zNWx^tAm}-e~H4zwl zQ&(#PwjP`<2N+u~nW#Vjv|z28zL&IrtJk^W&MP>j5|S0aIbRQZNs0I@8Tp4E|JklI9!H zb{YB5gEBp;0N)LH>_s*BKy$cJVtCl8#4Xe%3`-LH<6g=z$0>a4Va;4HgI=yTV%H}9 zIa@_l%@fhvPk75A3Zve65U&f6uB0e**@`FIUtFM#%I>8A2)x$L`&g@WX(EmAX0g;MlCEW0dZ3Hdk6 zPIIIkgsM4DgjwP`2@FdQDffa_t&4T2AZzUXqA(qxqYi}A@Ua-FbA*1{gSctGFVDD{ z3Q`_iXG56QV()XKigQ*1pm)nsC4&3OPg_hT11#;T5*c(0M23A@Y{yf0?SE4eW`f(I z2A_l5bWmM8rzbz0_XK?DtlJ*wNB>%%d)=AGm0oy~@WTHT1Vzob*sL6V@%Gw?j?irV z>z<8QMZ=?{k<+2<_Tc#<_~rJQ_oqdsW|JhuVQXwfWZYfSa{27fqxXPMy;t~$MDA0% zq2{~e55x0~Q68;0FUa@6vyf*ezF8?4sp}sB@g64$J{fYGs{&isI8^%F3*RkO$B(a5 z)VcigZ+?U9YWIOLPBZYnikMNH9GKc)Xz0I;+Zi`}--udK(LFRTY`ge&z`W}u*g+qx z3fI4P@@CNHirCyURk!z@9@2dG@T*UIVAwP@g44fUlN z4Z-|QUKKC3GFi+e<&$1>0tAlJK+O{b0TTn3wm&GIE5Ya!-$e^4-WwVA0VkA?-V20h z1Bnat?W(?kUG7cxLw1dL$9hz_FLH=DnINWuIb<1Pu!#+M<)M8i3&N_qyTC(K@$qt< zgy$25t$vK<8tj$y$=lTTYP*y+RTkEsHiqn3)rnT9qR$UdV(ig!0j!T)i8hyS3ZL4C z3f9UbY5@ZK&m!#n^>q{9j|?NddZ-E7H7-p$2W_mJmTURw=j(QQDKU^SO|Hxy&*OK5 zpSDgXRhxPlT`J-$vyjx`Lsl?xdG3JW*K;bJ&q!cF2Z~UUtd}G+T0O^<ZyxT$fO`)`n|_#b}%K}lyvh-w);zb zhK(3_<7;?kWhI?q(-N|h*pU^1SVe|1!<~J?E&}r<_A*HBC+_+}#jU3unDlCV-^FlK z=n5j(M289S#K2v_vZA$IAU0fi+BKYh&NQt%EFCMoCTfCPD)-n3EJr;Rq!t_o+^uN$ zEiii*OMV-|gZP8`OFuUK{+x!w`7R~ z-fU;SLc&jDyo)_CoI1H-OjLc?Mu02FNH|(2(q(&XoH%H;lV22o(=%5CCN5jT)q5k+ zXsG0BN+z?ex@nkCg9bm&#WwomsyEm_S|dvNyA9JuhP%(pYRJ@ws2=Wx7+aa+U7b4Qnt`;nDmO(X8>DSvBf$5rX5Aeu0gwfT%(G^WDHG<2fmp@X z#!?;ni4}lXh=yw^Z6^$6og@rFJ0RzJI3wDmywi$F_X>ke#2(Miq&dF9ru7tTKKD4t z9nbwxFS)fz8vkAvg>`oIQ|ylPxD=J2Q&F#!b(}n&;dU(Q zOBPurq_Mbrq>8VS;Ky_iv#PtjOA=VoGpvqFi-?$Fswsi!((9qo0KS-*0o$nL56L$G zx^h%@&VBmy%svfUevhgN7rmHE^dg(PI^#)TL1h^_GOR$d;BAZExYZ=L14|b#id|Bb zKu@YJ$n|4(^bj)7%@_({_fa#n_=qP{+SAhQr%W<~N56yne(ii`$7t0qxdyVTX9KoYrB;Y}5!0s`lk&vahU8GHARBt=LJ<)cF{K>REYET+ z6`Y>ZFg8+S-W&CAU||PP=)vys6rL6A$z}0S`8MoDTfq~o0Q|xvvq*etya_MThpu5I z0QNQr3Nx^}x+zh6Ese2_Y)DyAo|jcZ<)jD}35xv6s-KV5qENq>HnVU=xw*6na; zKTngGAKKBW?)z&+-MWHj=elL$Y{B15j*Ze@9hZB<3*OiIpAZ8$G6epo=`Y_GgGVc! z+k4jbc9_6KEA2uTTOHnP#P1O6Lw+*OZ4x;|Oz;xW|2u?%EW7*t*)JSt$al-3&|&?@ z7>gPe-p@W9zf68Su_}UM!ny})26n?vX+C7Nk&}z+;un<@^FnZr~jNPJE2A%0^vEKkun$ zcENZReB6Sv{x}=i(HHVDEIG<-h*_tFfioXl2$dR@VTWQc4OHc#&~+yG&B7x^p>({C z+`^!llCZJ*_(z7h;o-dl1c+d({nlg&TML|&f~GqKWR&AUL$g0upMO2axigt;$ZWX+B3q*_fC{L4M4evP~*Pc3Ob`f{6LVZaP6ZI{KnIU=SGk8~rh z!FAfW#xPx9F5SkL;r^l$$KO9TPP$yaAmf^&A2}8=P)8Rtt(n(sM{s5fw}+YWsLLs} zxXMu@hZBE~shXsV6)62`q#G{*(SROf-$EFMf7!*X_LEe@85KN0`BNRfKHb-A^*-NK zHWD4?*}h)1cEJcAcs@0ic{Q~#xYF+$3OKzM$>}chC?u*DpKH6_lri7)K24DKRK}2K zxhircZQt`gJCOZG_DZWMNo#%n12&|P^xl%7L@|x3jFDH2L}?0%KKYb1e&lNP!*h9@ z#imf4u3VPOcTI7EtiBDmm@{=?Q^uew%^GU=3g!WfV>2o@GtAFfpR*)>#|iu_K4wJO zWKOJOxw~WOtwo#zt=L%SuDzsp4IbhBQrHCjvz)rZ zSG`k~mP}Fq0T^&0CT&^wLk`&K zfN&vZLErH}(7X^t!TU>t^bR93qVfNESF7ic!cw@dTvqo^=&n?41aODcCRN`!46wkR z`?(#?EuMlQ;zfz#+2sa@FXwjy47-Q|du|cJ7PQ7yk(s=0K9K3Xg7t&cgIU3m6T|>z z*8u*>uMX3Y?4thoV!EuVl&60^M@M`;;E&cpdJ~1MKk{LlfIG+cd8bQPyZgQl&&t8j zVcAtMvIH86;i1~*D*U;f4~`b<9s^2Hh&AuZXrq(V8St&yNV5T5u%5g21wRhRN)X}T za+AF$W!>Zm$|FV265QoXgjOW3A1mWGy-CT{F*x&uW5h;JW0_&ihe5LBynaEp@3W=f5>M?bC;sk~l`WK5*v z!ka()fDnsQkTo{&5ra1e5viUmQn)+xXZ%9DAF$2gD;qcWJ0m`1R>Se`aFIzMYIgQB za`15Uw1aYd^L#G(-*AC;0VA3X02knXVclfxx5)4>$*Cp8?P1*e?ha zNV303&`kz>hjQZBg{Cx@%eNu{QJ^cvZh_t;QVtYVq$`He5^Rd-Q{hZ4Z5PsTZ@tKo zDRlmjfM&D9S4r^&h{`q%n6~-BK^e1|gsBc5bdbcS1z@&G^mGrpWGMpMYzMH)bmZ#b z$s!=Ujhd39I?0LcqqSpVP5jGjYa`+`Ur5OYm~H*+i6A@bez(Cw{=dz(e%v83p6cP8 zj6Y^u7sm4+vn~DIYD&oLkyXr~<_Pz-VL84&sT5yk45Te+x1*{1g2IHJvxGJ)NJ6;Tf&+1NE`D!PxTJu z44+JX$Z%h!tM~1BU7P!%<8podLCx~Ac}&cggZs!-#~Ikrbdv8J!suTgX=opQx*7cd zdlPY@qJ3!E*!J}vgz*|UiDJFl`X9ZvEmxPa{&%nK`nT6+W(w|kJe2=^Njsi=ysFLI z#mM$S&Y;^%Olr@BOUtb?-nT z0C3v^%X9~!|F24X20lhjH|=N(Mva{=A=LyG5A2t&=!B$=qhP!;fXg!JhsvWi>F3x= z<)`Idbv7LOBO3LcsSJSO{{>fyz&bq!B|R&a4nO&M%%4CL5{q=>ws74o*CH6t8*609 zC-50?MAw!rX*G8K{3^_LzQ47{17z@nYICPuGC)0dY=y#{X+X8>V7DD4$bbPd^htL+ z^xX9WPEOQ)nAMfv%|%6iUoBT(e&xDwBu#s&$6c;CMhM4@(wF0O>uL#p=Q>64UYQ|Z z_)WYLzU7YX5LA|6MPD;XNXN`=t5Io>p&)NM(@-6Kxx!Yr4#K+q(PA4M-9oKVD|*7| zEseo^Z0?L+x%G)D^chB^5Ya=7*A3aB9owy#x(~Y@XsX+u=@266z)O+sRRO_UinLBj zGP+XxU#jze?0MWC!(}_+BsmO~wM*(dwQzQ3)g?2kvg4k_^O@)pP)0%Hj8_+XjeIwi z$)Oz8Z7k6-FP-$?Er2A&(smuo+H9jv*9Q03oM>-QC3XzDY5eEIv@J^!3YzR6*H4a zh>esuRoP8#S0am&s;zpd_0aFZNGS&u+%F>F(=_yFTPBAAo>l)?MTv{V3fYjJRK?FE z44}CM1!*gkCi}Kv4M6tPGlY1~}Xbw=N$Iis=)f|1QJ*YLwym-G3L( z;J|LR5|CtkjeZ4y-KJKe_jtpXz^!Q(mHDKNOLf!kr?CoYAgAAqDn z1!6=8Kc9atow>H!GR(r-qQU1`Xl19UP1UnidUMn<-r8zTx2dXeHpL@!@XdN1(1%!q zhEl{r&-FF4p7;4Ugi?O{^w%1t()p>U)@;$P)0?S3h3zw7E?esbJYX(cQ6nf|F59p^ zL-B%+hPd*ENLBj>t_#*8&#IZ@h$@835;v+7@&2ba%)6yvqjuc8g;3IV!UlQc)|*7} zBGhboCt@{J?@;pCV&8%Hxom^v#0(jq0CU-vCRbv=dYhIl=_f@nqFI)AU}Mi4wGK9Z z_C|=YwqX&t1-FG=pu1Ee?P7Lsh$FsiYEWwj8G>ZSnn&Nb@5S^fI+$ewj_6-E70s%y zPl{ZlCZ2Fn(`M2Y%@Xn#?+NF}pnN(J5@8@l><{gD*kKOBq{MnP?J*f-wQ}D8~=Gu=fM5s;n8A0GCF*AR<Y-N1Nr@3t(v!(jU_Y@N2$;x(SA7@EBa+0QZltF*v{j6C1x_u)B9Rxw?U-7WNmq+TDD& z+%U?3Rt7gHR&gBo^A?q8Rrmb;J^@}P67;`cu#&6m?dRb9sjr}tu1$c)6G+u>Ti-ISkTGPY3h_t~GUf7blS9f7aaGX#?-_ho@lDl=Bm@ZUlk1wd$1 zft(EAFy9mZr_h$f*N+;;@C5BSokRJT&}R9U&=&niXoD~4_)2-#=}N=2qBrs`v=RQW z{!gKe&;Pg3Mwkx}+DQKv+VlZJo3oO#MdEPrkNA(`&>;bX02Hg&%65VP@iI3<##T;C zm^){}j?rL6)+15Km*%wmQXx5-v54QuhIHMpne4phH-Tb(F!Rci?BUmh5BT;gHebKn zX{es(p3X!{d+u8z#PYPZw3WmsUIy*<66FpsuH`6pTg5RunGWF3;HTqXWsFk&Lx^$Z zd7EAvA-k`+OHd8%DgXik3%tIXEp>^l5Z79PJ(5x`Lr|yoOPtdavTWj&e_a`F!@Oiq zbItApCeth=?nqPEj38W4f(C6aGhcO&(J~j5F%qt}qI1K?!sWVMmyDWsP7IqJnS>M) zKC>F3UKNuN*h)pHHrjkiSe4G!073q3vzR9xd7fP7Wa15R^lP0?)Xq1)018VIDQqhe zlt|Yo@Uj+pT2aB6lCRxX+Yxk)S&3+k7f9R;8*`biJi!f7Ssl~)1GH8+c5-dH@Re}O z&f#E|0e_gWsQ7`I=sJ5HNU=h$4yJ;Q#1aJ9{>3!>wN6(o?|npYC~Na>W))UGuNxeU z-zob=|E_ex9(L)Nu!or>R^f%(LoyJA$%j3g58FJI%l+*U4pezV+ezaR2jInGyV7k$ z+_T9TTU5GOF$Uw2Cf|?aq?$56kFcF7>C_CTVp8Ojf_EM>sqt`PC4LTDn9MPnB~NMc zfR%YBWPCi~x=pnCm8Pu!i*1lJ7D7@P4fDQ2hU$BAGso2}IF|+I6XK{Ir$if=A3;i- z&84``#4Rt;b9C@Ii|O$wDeV^Vibfzwi_Gvo9gj8sRy$0Qqp|$zR(WqKvOKuEMXi51 z{4m1O*UT-=&{m8RC6rhZ(VbTj{*Hfv;QP6pbD~Kz8gp-=bQn0Ph?4}ThynDTx0Jvx zTn!k1q8PUR61MCdKgaaxFach^<{?iv@sU6aJa`{kOZe4C(q@bZ7tWu3=Iw z%KmZJVgc@&x{Ceq2%Avn$90-P3IrdTFU=VX-)fGTH6<)0T;_we3#b5 z0UNHg|3z9W|1W86^?#ApGX6+w#D7U^X8#3%TcPuROKU6tgS3YEF0COh?Ec?KYwCZb zwJNLsleAU@P81LKYE{q??NgFq5E2&TklSUwEBBMH&3oFUZa(lKipj*JWr3YW^_1l*QwA7cUdr6x&)H++~%WMjrj2YV;5js`g)a$3EuWJR3 z&Rr8zW5*xq&KSu*64}RdxmF!UvPs;~Tn@t0ilG4a&L@%b?S|IpPVdwYDofx=m6j@8 z8789J=p>XddwNI55Py+RJBvR9bVZ|ORL@HwVnCt-!^C0sg~v}_ zvhJ&>=hfRI{64)Gm~{E5Pz{=>QdmeL&YTYlt8}UKaoZ6$zTy~P%8YCJZCoo@b?0yX zTgtxTV8jFczl9z_Ifp_GklV>o zUP@prMP(siUFxVR#n6J{6fbydBHI+@Dwbjhfj#w!L^orMY{TAH(} zJveO|?#r)Wgo2MsmsTb8pUMQYUl83HQs*hrPC5u5bBbxn8V*p+U>zR1YFhfc)h*P< zR${jRF`&u+36RU8;uI_&7;KVTj9fLCaOX`6)+hlnpl!7!^AfB&5y}!Vu?cF0d~;u< zsFo#Z%f6VGT9?c9D{N^^%Ag@sy>VQ+0D?dTZOQ0VmQjA1C%%b3@)y#>a& z%e9G>prW?tFD&BT{1~ZR6IX6uYk5&hDKri0nsUZiESo+6+`Nj4p4K|9148+{)R$7M zFU1F?HFMd&Df1S;+rf{S-thw0y0&Hz@mw?ew$|*+3^9)cTH?xYHc!PNmUbxly2Cp5 zi7B?ni&FT}ETa;L$Z_7N_+8#PpiuT+;!1L=qG`LPqtjX!*k$Jn&O_E^-|2T3^Bv`K zwMH9tq-wh(%unuxaWZ&`C?|(oSZpE6%Tmcrou;IOc;l&Seg<$-uDT~2L^3atNF{2~ zw7g0SxSpc2iAgpFK!&w^;D&WtZR{uR^tZVc?_K&Pm$u*RZIj`7o%Hjf^B%rhpih(5 z)2SH}p7WP=u;B-_w1OJl77fK4A=jkD*F0N^y$uUo)-q*57_iB+PeBJq!69)$2*eUI zu#5O(H$t`y9U<|<1@gno^RdR|18F@fs!948HINJ!E0PIF1Ka6WN}C130)F`$U77*O zrHJ;Z`W1qs%E8Uh461~Cl)Zl~mgM#Sb)+(;Y;xN&Y#0Cy+g>By#3d{FkfyhOBuKF$ z2iyh0#hAzoBAGw-X;OSO;0OL|kS&~AuS4ZNcqEq|#vzlF>c=Ec8=jv{K+*#u2aI(l zesf$z4$j-c1)x(r7131mK9u5}?w5y9Y&#JIDv(o2Yzt4NWf^*Cs(IvEbO)f0-bc9K*J(e8UmCk^$%9YByb(t0e zxm!;6p`|UJTCKN|?Z~5~;a(Kn1i^{dx=WV%W%(v32_s-a8x#SvqpcK0a?o6N z4p}~y3;jxVv<1B&_B!&@09?80RM8HvD}8e28BcjIHZJC>lc$0pjt6x*_gAlT zIS|hF@6)1)STz(0bRcgu&9$BbYU8*i@UY9*z7Sg&8(lEAbN%Un$uALWyy~o8Cc%YP zCwIpfb>D$vL+6gHtkm9vKhB~CJSmY7PSK6vRPj0#$ECb&4QJ+m`CxvZ0GoMIeul)} z!vBG2W2}ckem9)mKL|QvKiN!0|E2+2=H0O{GSPs~&g=8hz|Q=cNk7{ClU-j%dX1Rz z$&j^e6i%VrPQ8G$y#pn6B%e-OK}*a^YZoJDM+L8Cd>lfjWLoCdmy5^bE{64S3Z zZX$I|f%smpQ({qz;0Gu+qQm4=6JmrIg^u{Y2_t8r5A-F|Q-_8PV3J^nGU52bcp0&+ihrm$~WfnalL18LBpeT6K8^*DsfSd=2z1;sQ%RZR>Q zqC6&$N~sTi=YB?@g?H`$irU!>{W2t@Wos){8Z^Bi8?XOL%mX|iiuma}d-*TzB7Co1 z)4(4MS$wz_H|RdMii)Ym3?}+Dk~S%yjq~ygSohTkq{gWjKHWZW99d(h>vvnG=R&f$ z^vU+cvk`m-k?qobN@Ksnkxeh6*<{(CzY3P$he;!Nwrb95@2N=PpXrs`L{W(ypWR7h zmojU)SSIE#NF-v}at2Iqu?D?w+qj_q&kkx@;(vEgw@0RMhy8kQpzigWvvCV2c!2bc z`kxDBF%l@gzy%U$Cncm;VQ$|Kxs_zp)^8Rb1}a?guTm{Du2WWv2rXX8-@xM9HNfIu z&%NC*5AOTDy|?}9`^eo(g&;JdIuN23bUM$kXYPgqN*&@ms1A?V&Appf)nDqosGKx# z_Rqgr4_&{;rkQslW_fr%4>pcW(%CY}M{JB&K$e75KWcR~cnoV}9Xx(q!z1DS$wVyL zT6;F!3}~Kr530K1Y+yhD;dD7~(i4NrUJ!}J6m~F5T;B?PD@y{`ywovl-1^f29Mraj zFzRH?1aWr5bv-{YZBz$&=0(=f*u>LL8fRUVe4W|v{}P!vn(5GTqb-I06>>oy0#<%V zbQZ)ZL%hbevBVI@USD(%Dj5?w)8S}bA*+ab4N^;p_ZjuD$SGZ=U509L?I$)QHbdFZ#`WH$LU;9AYF{_jeHHU z`@T9%EJ}ecCoLho;DKWbra!cej@s&7s|tW4R}V>&j5BENHv!^4(^3I(pKt@RrBb(mxX)Wa+~?|h+-E9#dW_^~_9Cvb zN&x1zobRy!yS3XKF6Ig^i&sYnU<=_WB~MTc16!}#?zAgEtE|8;KM3fJJ88I>$&d{> zj-zu}^Md@!R6y61L$4MoNc;sW5w7~cJqmnffWO)04Xf17iPX}gIRL5ln{@Sw1nb~z zK(WX{O)qnZ&{+uj=w>~TPjuFoocX|37t~1_DrMT62%&vUTxb_K)O@_#kOVLUY2)ByvU;-rzLFuhWjE&XHyUm{FX{Z~CC zyo=u331biU3@x@7Gq1lXPlx7~hGTPb6>)=OD1(cCZF?e5$CRR<*4c$zEG|>n`XKGa zleU67==v$3jR>Z|p;j-Ov1T&T1QRJLnOtXA;tS8r;tP!bN2ZzE#RNFqnvo)r6O+lB zE8)_%@R8K6i8_2DMGVHCBik|bgR$D z2EUmD5r8=ygnG$>wK${1+%XC`3i5g%x;`VGYw?$Z_)-3-AAI6z_%hXMe}7XI>2zD-}jAf z%Uy;H>CfvRs0WaS%L$9Zyh0AVgIVRfT>MR?EpnFfjC}kTWfMoYr=laXy1EcyWhoM_ z1*xwviGV)2i`153j^;RK0(`5ZgIdDagbHRjy5x>egduD)G(4CDC6H!bkx<;#CkIq--z9ry|fLbKxogv7g8^*|-~K zdk&xq?X~_vS823;O1Bwu1s$wR2V|odb%rhN*Nf(UW-}+-A3GiPcqW={&3@{gkyU(w z&Z7|Er>1`jFHe;mVDq{lk=;>JCoykBiAmdFMk}eK2m4~wXq|BtYr+(EOe%qlQZfQH z4&}a9l~SUw*<(KYb#he~yiu^Sf{Bk+n)%C(cZTA1Y;Stqm;@ZDl{n@dn7) zeQz?*seX01hTy0C6dIf^X9QD(b6@L7EY`&X9__N12zQO$x+83Ink*HaMT8c5BE|co z4#+3q`V|D!h~vb1p9uEV<6|y*|M#+0BJPXRE>Nw)Cb1-4kkCGc)Lnd3AO()|b&%%uUBX z4j+T=t+68RmJr`;!QtS>KLelx56F%A+F}$NNk%Ewu!E{RzY~r5cu>^nSp4w2ZD44IWJbl2pmG!`0%rmAqcf?d%N` zZTzm9?CdD_FA9N;E@dOKu0tc>W%VBZdF85Q;%p&UUx=N+Q4YUm!w1pT*jCW!_QYeg z*kGOK1vDTW^gp-H>0|=h=TguAw9kExQ3@gf3$CP-@)|}p7b_exk137iPE=9N-x;E& zgJQcL{g2K$tTNQ7LfgnqbpkLFy%4{_ty*EYm>0$uab23)o`HfpjcW69IgFUE;QH(v;|r$=MJpN-Aya4>L?WDBHhpwd_Svd3iw=A9xI@$j?1kfQ!b z+P#}Ku@u=3yA@ufMKsY%&Y7N|j*A?x+%0#xilnbT$@fAnXdqRpNl}`eH^yBdWZSwKMUFn367K(jlvba9+gY(2>7dcFIJ`xTLE7V?;!y|NxxpkB41nnf6c_y#_ zUD|k{BG2hs6R73vH>RQXQ<}qWN3bQl3XHZ}z4`fk6k5D7BehTbPGQTU$m6E*vZ@fh zX>1Q$tES_F$5HdsyH;7|q4Cn$fnVgfn zz0ddkxVN?YXEHLXm^Ev*k)%eiw?FTwt8SDw)+e14jfK$55dDc_6?9^QDX(L}?Np0_ zO<^}$n7QeRISoHv9TceJ0EM9eGZbit^+>l#c~m5|ODINgwnuFh4Luzyrcy%-QET`b z9o;Pr=}7e|!BMC~1%t=WgP$`8>(m%q8;%;n$=Mx@_=O&Z$f#2)`if&Eh`9b_1}5jI z^DzOb6<U{)wBZXZGgPY-Os>l7l$Lsv zm_OiOPq?(k))hy^1$(H~hrL#x0Ru{kf_#$~7C%PBGdrGSAN(b>5r6%ULR-d4wE!zV z-JQ}I!Xv3zB<*g1z?Gdrk4kzU$0}HR=Y6<)!ed`Dq+Gg&>dnWcUblz3j}$8neIC+1 z8$mePh-IZ}NRAUjP0rDVq^%#f`3DIe)C+T_T9txML~@G5U-o1NqJ%z`Vf7bzxxRKfY;x7W;abiLa zo!`tT$Q|owvM-I1pbtAXC;CMiZlWGoq7h+fT|ydSWs>xM)YCz%ynUqL*s8nMeB zA^oX`!vI0|TVotKVR%3L_o6PzAa8K-cpnuox)MA?l%7)WL&*}+^Iu38vh9i5bXuwOX{`=L91k!JO6D{ zKa|e%CngXmaHa-2xK4S;=@2L5L;8hlSM`_oL%`+t&&VBCm#P~AAxTedZwZzWcI zA9E|xJ2z)T0m?u6#YAh(J|WIHdXUT-ADK7=PeMX8m>C*u#tWsc1FKfh$YT`{hVSYr zCY&8r+b>bA81PkH{;Q~VF`=qFldB7I$|J&rmKA0R`LyLfMvkzF=_@R6lfi*DB7Kvt z*b^2WYSGL^h7ZdXFNMReuRy_cfXbe2Eld6AJqCK5Ci4bpQJ!O|}3;{Z)Iq%bihqmnCswk8oCPqO5KHh27 zMO5NH1HA)seD80qTY+U7DpARSn$`?_(Jt6=zZ__?oQn@zmM=Ft$QX=sDh{ zrT)2p5$0_$N(E zkt3&tk8wIPsHaPQh*o#WStA+XwVSI{;ODg}3}d8(2&)6HKnOT67C(bB4}FP>;L?o~ z#NCfzHYlI;rh`g*iQ-VFvu!M*pe{GNYQXsArUh&+yoDx4s*D4;XTZdPuy5(8#OdG5@p#bP zvdkEfe{{s0E0XE<3Aq&m1x-;gcw}e8%l!RfJ!v&+aSyu zU9HG4%MnxI5l_(sHt8j*2d_mqq+9K3$CAwHmnTaa9PstqQ%kqXuebV^_IuiglQ$a( z4~IAI=}TOVR&n7|j>H<+M#nVuY9$$Smc14sTaVa3sGQfdqHT{+fnzHyaqk>h?};tI zixE~9QFs~YnA#~8;-weGK{zwImVJ75Ukjt|yney~4)%Y*0j2*62O!!u)n-A6I%3$L z#vZTE?9i#an=^ursVt-|2e&aPcODDqblP)>FG$m#uQ<6hSA0Z!DR*6?T$fFZY%^~~pv4iEUgC0`{OCZ37T~Mgk#sYN_%vK`$`>-8y6TFgVA7Bmt&oCq>if6fd zvw|F$^QW2z6sv=fTz0#Rqk1FUvGVb+9C_rPBQ|)uDs>N*o*AQoZENGb^RB=6ou9M5tU>R0$rZbQA{#gL!(S116TJyR<@TJdMXx1y<&>XbxB zq?C5CV&BUd`sDkhokPI96Zo#<)y>K@Ystz`CMxfTex$@0T3S_p)_BYaG(Nz+kChH; ztDBCLVL?i&^dkr8auffIIG4#I+hZ_#b5A?htee0Bqf1fAXlrhjHGb^Pm`7qV7=!G9&PeExb2jL-6UIb+uHg1`ZZ$AB^;3Q27cm-uFUT6?V)0| zUD}mZ@CK^*@yJZR}?%EN;cL-oPh_fSEUn<%ZuN?7YrAirxY^`4B=A=rlR<(lu5+4 zvS=iF?M5guT#$F*O{^6+rA;0J8Wykxdi(8u*CT9(CMvap^q&HXB z(;Q#H3%Bzc_^4w&^SV>Eg1d{Wr{tibk`Vpy!f3&aF#gJML60K-GGKu(?RZLyAWPAg zZ!t_;frC6^@C6v z3eRAWdL(&k`2H_2NaHGq5;XzrtORi6x$({<`(CD{Q!xb)7|NKr5XG_^Ai`$Fi8#g+ zo>Kc>{`?Yfmn|Dpw4Ct%p2heeGx&TB^H1ITD|umu%^v66bW>PK2Rd1c5|~gY7C_|OW!5WKmGxD z;Vioi09==Rj$Ob>%#(X|g|-Xc<<)b!TPqzWe3MK2kve0*{@zn|$|K%t3t%cAqU(|; z5$EkR2q(V!c>0DDERcoKsTCUpP(qC-ODbpQDhFrcs2u++2P^z2lL&(}7_ASGLP?X} zuk|xqzVPQtQiz8BdsQji-JQ9E%A@2#VARubPUyHQ7B-IpUTn|q=`+Kiwo4}JLeb9` z)^Wl6>+bx%nmrR$glUkU^OsoDAYts|A2=s&3s;!}x_QO)Ly}1v3Dy_O;rhMPS@os~ z-f=`wukB`kGkM&@2-n1m80vym!HG*H7=Eky%%`@nS9_R9WidP}PRT>a|_P+KAj(mgCb_H7jC7jrjyb=w}m`}GAfKHtj zPGBCodD|K51|>_x2MQT6VExNd2Cb&{;R;qA+Di~?%p3snd`}A<>Q34n-b^PZn~x_9 z$vR#~0IY46cu`^{g^l_66LfN90%N9oXHP9^j2dFFbf{8=X`E#z>=~idihPZFOa)J@ z#qv^V(dQUi>)e7ti20ZIyjbbNyKR6>lWS7OraO@s-U2}QnN!Lb%fy%8;b;5eEIdO< zQ%eS}WtWK*YT>xV)6UW=Yl5a(_ln=+hYS0pkKQd_15{#xfccp;s$P61bJp~vqus+p zX#NkY1_A_x_M$O_%9fE$A!L6Pib1&l*FrHLScIrefK?nq5gWoQjb)*Rf#h&(;noON zSJU7Z@hu2w{$Zq*x7Ho>Dvg@cfp_b-T)fbx_a!)36Z2$KLEqQ6Tm`^**{u*dl>Cv^ zqpx|#Ss!J(A72r#J7M;}++v^m`d@DGl$c&!QlPY?=oT^#v=RNcH!vL>(Aq7#_RCH= zykm%4XUpG-#C&FQY)CW_(p4nhouPn-iI5u!*N$8b603I?e#f*UkGO&A6A&{A>O8%F z#}^UqZ!kmPP;0Dm6+}Xf&OhxDD8cn0)k>U7Zxo020%H?o=Or5_*w<<{EkZAmP16+1-7uodg^0q?ROAC&Ja#W`4Lx1zF#Dy*TbEy zfz9|c6k41qZc0La@BzTvE&_<}5au<~*3`Xm&r(L3WR!G;xAvq{G& z5jB!;i7Q0Iobg{~dx9v4`yRfy(`) zmLH&8W!y$3ES^bMwN9X#fnjalgAH)~k(r@Zp~9&liDhDHAuN^;#v^((bRCBlZ^L0yLM#x#W!yBSN2h=m~;>CcKi0P$Bf#6 zibdRVq>a`<(l86IIS%8q67oTT_Tv@YCF1eM0Q^<}M=}9*5aU#Uh?FJFkDN-vQ^x&B z-V^|E?U)jXL?sHTNm)pboV!hngRNmI6jD;|K8&%b#YJSl|C}>%6N#vJhYefeBVM#b z_$RczL{t2yEPSK$2K@0qA=@9m%0H1U9{s-|TMe-Ob1W)M|1I}dSJ*wDoA7U0cncC5 zAPWbs{~u)GSj(ajR+fSog`DfRY^`|R?LAIwtJwbY( zKoF|He+HZd&J6K({|q>*KmV@*XU`=+1I|vZ{uyva;rnj^XAr*w&SK4<)7Ac$FO2*)7lq?jz}d}**MKu&^M3@KQT&Jnk_QBwQU4imR-SEYw32vxk4eW- zs~x2Ji_da?Fo89RYp+c7j(6yXzU-(Yv$%^R&4x$DDlfdF9C3_zMx?=5HPqDEFey{p zOZ21FxL@H1eCMbCoTVflnW1(#S{LA^iMoWHB6F+&0r9bO@|}9(Me^Fg{!N3ya$D4W zoHhJ^R)Z5*0cvp0%5OE;GDz6aiZvM?udR*pj!dZ(JB_45uw3k1Sydx0nzW|n%R{kz z-u^%Q;JP27ty0;oJOc2_ku&hBZtT;m1x>9c_?5ij4LdPDWP4=&aI?(S8<5sK{)*_D_L0Ml`Rw z-sd+S-~Y@qJAD!+KA{N160@?r7EP_LlzF@n+^L4^@RX{dF*vF2?+2Vy-(XI(kt(!r zXB)m;>qE1awiDX&>?9LVP9{t5hheB(^6xD7J{r_Q>zmvMzv!JYs#UOsjqP|0=5+Lu zJGnsJ6rwq={7sZ~n7Qm9;! zlJ;~}f)z4)ncZ;lvyAWObh}M=0KN;|Q+Fy}qi#qt%3R6N?PBzzwtH%SFF%v^!P|m}W5clNzCdR_YAnMBUNr(lCLei1p|DKc~X8b*>G?nEm znI9b%`#^h1PPlQxa`(;F-(9ZW%7Etw=XXfANoGWeI|C*a_^N^aV*k=DMom6Kex2M0(t8*1%f~VE&0; zZ|flbQPTAXBUUhR_&3t~RyWTo;2$+%pOiqWRN1)zC1rKkq5p))c}I|c5@bHRwzEty?QKNsUB*HozPR9b4~4K z>j+}`+rV2SLY@}7QI4{uV+AEJzy?i<3;$?{|Kg|B(;19ILCNN0Blbqun-#;3$k=-_ z^#WRyFn8xoAY3AvJDST&3gL65H%ZBqHQ54OcnX-Ns96Ut`2w8(i4KN9$1*l_h;rBJ zlbXZO?gYC>9@yjUxS5z@CL3147k+9k4Fw_C!FNR_{XLt|H#zeN<$RM!+*D$&+yQe(P3iF?UrdQN#B;~9qs|De*nPv`xO@GaMW zK9uAN!MlNW3d27ZnR=qSD%Hc9P`}K?8^$TQmwAq4SP&nb%RnS9<7pR zUV6SPhX}VbKR;mNmQryos$sJ&xLmqB^*rCZXB2#urdH3(xzrF<>Q{LfKAt-$xKgWH z-emEFa1&3zN!V6@@O$(9a9OxbBith>#mf}b(Lqo~GIaD5>g#v8>nWb`f*;p-XU^&9 zpYXdsDIAukJ^)N*$G74YKTTzyn{Z5r8Teogq9k4cC4i}14ltEXI#6Csw*Jk)FLD109YHxfNAj9=5$eJJjib1JNCwSPz;Xl22@ zCW0lcCoe;@oC08LV+<|4tZ-SN)3oAw;g(sxu2{vDM*T>CN2Q9x8`}2#a$#d5Dosqe zVv$Tyyktn&j#3s`ab$LS4|r)0nUGanh42ntYYH$?6yJp)bv*w=EV$)X9Z#0M`h2EF z6MIPXI-%~)N_z%$DYmDL+T{~R1zp$?hw&wW5lma1wIn#mg>PCugUmp!cplkx??xDl})war?u=eye8$pYG#8I-TSIY3iFIr+z=np9ZtGc{m@R_nK&@aMsE$Kd#_f_QmCWsNOrS!lrkZG|j) zp%~CSAKC?ZC^lnOocOEP6!mu^YC=TxvJfw<-Z1?N{2WSymv2_@!j8RKkr}EioaxC zg^`^kseeRL%$X6c(9x;<9Z$9s`8%ErJedkB_BEcYxy=78ecpU)Xd}#80T^twQ7Dpf`I?4aS|*D|k| z@isY2NY|87#I4slFA6dR75$ZFrZRoqos*pXJ^uKf1wf$}cEgBhgHtZeo(pc2yNI12 zcLDHfbI>=-BnDRejP}bG_rM$K%(*mP`(f3}8=PfIFE_YfTG;@aZn1m}tNUxASJI{w8)IXCKn4D`MckJk+J&KiJ6c1;aC0P;>1KHAX^6CcQX#?e8sS&2#@;W+m4V?Ri1 z(~!sIzlmhHdujkWP@nfxBpU?%8r^vh?cprXDrpxDo@*?bM$RPgJo1kabiMZ|)?dfz z(rVcPSfvS`xyDlX4&A|&IQ6d!MM$QNneB1kE{mm9R#hWIUVkb20Q)Qee#B=|`~3VT z7$|m({~?n;otId=b}=|JPg1hti_Xt3QSZp*YMvU9?4D{L|2z7eb!4@NQN`;c@!LQ! zp$q{#x&7Ndxb&VzKd}(~Fh_!Dq|`pXxcB*Zll#}Ba+-+d)n=_kqPl$ctevbn#!lSREnjD3M#i%!?i>sP5@6##a2}YNa=YJs3^|pu5FmWhg7;j~T z+$p6GtB+`N-<6U|b!8@y!dgcQ9QY7F%y8uwYEz08sLGLx3FATG>GHhslp>VV%GBeT z%F939+jm!lbAo=Paxv!7f`5ihEjn8IS;fNfV6KV^bdaTw+!@X;pcBQZTQ|+HL-@Td zmD$1Y521-NF;>W$t-Oy?X`)KRu+HgPd`C02=9=*ugdTP{;KPlD=0K-yaWT+AWDPfw zh4IPk*5tVW#hzh_vCxizj+ggAKyb>T@5<_(8=#Ggej&HS0BvYkZ=L@BPOKM>XnC@? z?&9QHi2OIq_-&R667zOQZ@(XH;_!h%73~P!{Pp^KCPPFQtbjzZ+yg+O*rdweiDKOD z--AAYf(1|@?h2jl(VS&Zn(v_OXsk|C*^TfeQoEnv_u5cT-uw@0urFjFRpOJgIL`Zn zs$#z^-6KNn>oH~#py%e~#{Y$4Cco{BFAB7II2@f})4Mcja;~~vOcaqft3c*VKMdVa zA*PVr#yv0)MfpL>QS1h0MICy4K|z;#2)G&%F@D&el1m&9`hVo2BP40bHkO3^3mGh> z{*4T#S$*&1*&kxWu&Y)jq_R&wvsxE7rAu3+NbKL&9>WZikF01W?lpySY&MM=eT#rA;d3=oXs@IrqwL4`pcB{o z8IA)ofw zCSD!-|Lslu3dsK_n|N^e)4>023s1C@8*J)h$pH|7r8? zAH}8TC}_P1F@F(?*tauvyfo|&!y5yLNuOOj{~iKE0;mUF_eYZ zYGM_xR%AJKAe%?bp&5c<-NQjcBnnZ5h*&IpJ1#-FWoFHuM)9~V9`F&|Sm+KG>%OT9 zgpg>8lLlW9Ne?CW23GUQP;eQq3OEQwq?AV&43Wb52ndlPQrW8qib(O#`AB6HCWwE3 zM7Ar7_w|>4KcBn;uS#`^3phyOo(=6Ezg{wv{O0eM06aU*PzwWR!Q?=bpHZ)%lh#WI zxLe@Kw9v2{RHRgYLR!%9&(q>nMK5omL@6Hw-xhnrtDu$igKCDY-mMX)+@9nJCJ?1F z$jGc6yqV~2Mb?Hf9Db&Ouc;YaF+hkIE#mFD<8sY!y!Bd4N1}yQsN;l{OyiP)5?U2g z{+_E3WZ5A)iRO&X&2rgKbwv(#cJ;_`?smk%fKc!tfNt%>FvnUxCLZn+(E?qc#2tFd zaj-^U+<99zWPdZxBJiLv~dsmg>!d(L>9lbvY`p#{rm6layrd9;aLFrLAFHmu9T zT&Q=1tmuPM1d?I8Lo=WkJ=ekjA>^^rI6d=<8|iS(*=4AL(qlRTS__o%RSFK_$PBj> zKc0`DGketz5aVYcN*axXtd4U_Fy$AQ)|h;APH_+KiLebH#x}>qiyquYgn8=TJPPaY z357yqNQ^c;duHKHU6+rCR|sKYV=;%L-WMq}s2R>Xo+Wse(9iW#%dUqN*A@*hV~MzC zKnLM~9G>EWv~&K>fd=Nal4cH}fnBX#u8cmF#|(_hLI?v63GB6xY(5qu$sNf^&Uk}v zs<2i!tfYNp3UFGTxlQY*7WtcqwYbsDA;QE|2%fo<9&a7sd{~3mPSnc+`J0+O1LDqS zansr-5j`Gv1EUp6VRs=nBM+sS^OE@AC(BC)3h3sd?%t)+0{0SI3(>WOfKVkLu{2X= zV+FO1d?@&Mp8A!V+?kOrT|w54e)`Z+3IAQTCLu{kEU0uHe7A0>vUn*50-x|h?8wAW zE$(72q2Z^gsF=>;KE@nv0WRj}MdvnzlI{ExYkRShf@$UPIJXCPPLO^vvK!{eHwi^vAL} zC&cq(4<$FK{&%FBp`dfPeHo*Y*=kG&cWxo*_j4BLviICC``;E%7d<_r!s>|GT}vdx z%EWJ;7|!M`n^)>qn{4yGPBDMiKyf_|P%HcHcsNgA-{bqERD?MS*?<>krrP>6(DVf`&+Y;l1M?O@_a_OE+%pIdg>DPj?%m17;-D3T_g4E zHx>m$JE>=gzYusgza7b|3U_AzR+y=wo3M$?LelMKFq!SVKaKrsp+x^>v7RusS~Xgi zdzB}VeKGw|i+Mbi?bh74UM{1qFgnlk3^&Yx;S`yqcBK1&7m>)FzG0U-dX3T)`(lz- zc`0^^Z)ux&0i~u=+12Oi>5y(K+(ni(*Hxu6hj5m0%%eOy#1>i$3of;NSlDORM@k-v zy}3?<6>iGLi&Ed#={L<@Kt(y zBCIqL2J}VjBQ)nUhM_`2ESzzwFdXz8R54tm+JC3nw}5jgpx`aCvE!O4kdR3CZ@j)c z(`Ko)d}xh#W~)?7+u|)?q?KkXLn@g*wRerztA8-DNXIDX&l7jl2||%wu%7r_J)cI` z2&K>Mac6_wHE-zlMidK4pT#i#Rx>tyH1Fp2%cBqDW(ncTR8zC*iz`d=cmSpH@rtD8R zme5t06LE6u3Lo6$S6EiEPMSWDkFJxrKy?Ls9&nZiy_H_Y{36b&*N56|Np3IOf%P5# zv)eKDb@yA<9f{t|=C^I{&U_Sk#y`wx89c{9AUAtjkt)F1_it+ZCLd86vntY>C!v?u ziNl#~+@)A5k9%dkm&!qZQCBO~x=VS;`<9_Y1#vW37Y$u_@JL|~Pi&WDZuAkwRiySl zv26k-nFiPh6=!wgaC;&Kv%4mMeuD0$uV&I1^`!N}*uKN~je1wbY30Z!1qVi!^WxD| z8vJ`nLQnPlM6eUwO^O}3{+qq3BJO2p6YF>&1yd?pN9tB3LQ1Nsot(qeF)zz+P%fZc zIz?W9_8gM-*ZP$QiHd5-Cl4i4ypW7Re1%x{&Fz9fvBzzhpHYc+a^6(9O_$~DGV9KuV-p{SbBf(7Q}-pPfMJ`s@JdGsbwH$cf=z7 zv?XUeF!JKV6WSEVNjyJx2o14&vQN54gR0xUrJK^`>As1*r28RFjAC<1KXrn*IK_Mt zlVEUIYXga;vG$!m2OLG28@9Ah$r#C3E=(~*JFck#h!_ZBsUs=56wSBY5?-*UIeZRH zl+81OFYuzBGHsT(pS)~eqO&8WSu74TWy~nbzzs}jbaz-KbC+)Avez2djPc)@vC3r< z)xvPBvefZlI2u0cHb^JXCOc?3%E5~TN0Wati+hC@=34-q80(den+RVz~RBU%;lNl@?O+n3xv3MyA6yk zpJ7~ih!AS0ba_uKxw!?mu^x3zKp#+YVDOoOS|QzF;Wc6K;3nAGdSm*T6&cF8Jm!^I~DBy3fD z4Jly;XbF)~*$>PNC++HG%n8&(9%;=d%EYtf(NSngm#VJc~EK|U)*aJd}Y>|n7KOir9z)C02e?Qbv*k#iE7F5iCAN+2RksF2D*(L zV(zO2QAJOM>~rE$75T<^*Ciq}gBA<7@(;r2%%xQ_b>_$I6;XO69i?%f}4d-rVXnnP}L!VjtYuB8=!aLTfc zFsxMwK($%v)Iy^QVR)0nhsyV{H$pvsgv6N42$OcKEoLaqx~)v*M)2sPM)II07C)Uv zedoB8#zHvck~2-)jhtXn>;vzdv zXA23GsCVet3IU6i>5_!zqr3BH9=naRm3k&+yr%ng8RV6}xcky7uUG9fM(PHK zN)EcDID6Nk=gRVcF!P-&AH3pHe}8Y$U128J2CXf^b^7xnzPd zbBqFWEY`?Q*#=c3D^u>8sYW$Auej0E)Ud=x$4K5eTj)N#c&+=9oZ_|&iME`FzAZsf zjZDj-&cbPN@vy+OpQa)MYWX8&M$WNdbqH@x%3v2BBQ%EfCEMJDO`EK(LRL}jWrTeO z0vZXegmz*FEdnM9)7+@f;&Bc;)p9>O1@&4DV#ctrK4+%42RS|FOQ0AXxutkavIBdy z;ns#vWX>5je;bPVYmN*y!Xx}}`U!enLV-%UMVF@KU5IwtQ7tSnV}|DYmmIsLsC&&ome3!x{p;(8Zg3sW)<>H?xV)liKQ&6cKtVG zWHhVM!%O3ChR; zw%cCE8tiCvO)i2XDPfFi!%fd4)-rK(AmLbGlgdeoH!jGC+H(sLC81eJ?h=5}dYqKd zl!w?VaY|A}E_zNkjzP^MRp`ypK%SKb;|mqGAWr|Zymh=;bRH8O`_Y#OruHFo72=r7 z_=dL`ZpnS(#K!^m*HqibimYFc#Lb>CG-HQ3X?gQke9$=cx4*kix-KJ+?^+c(vi3_$ ziVXhNi&h=gBqtdC$bAG&Dv@u=IbXAy^=+XI)ktu%X8gps$AYzBYsRrCd6h254FcAE zb-@b(aX&plWbfP5+34`4YKfb2Kf>MzXSa*abnNk)$V$qs?JWt0?IeV)aUSk+>lGtLnnnp03)N~-E)6SHmyAvxPThb57AlB&&rBHx@iQIx0-6)shElSEXH1Ob!?+!h&Ry-~F`Ak^&zmf`v*IGKp)e!H&MFCyH|7&S!(q7 z8y$!ah*45O%T&Lj1AN0*bfB62iVpSyU(rEwDgYfkr~ZWwDw%$w1G&e)&_RenR$jw> zB7GNsa%Ly|sd7{_LP8J+tBZ4l$uTIUM`DNUb&B@#2dRZ#@N_n;Y0AX#aXghpEoQVY{?8?+d(E|8ufTARvDHspXE+9GjSqcJ~8h zdM}#P=Ak_}U$*CpYu?+Sw#Jm=d{nTxkoML@$M|FOW|-PekJC0_^Eb6X6X10bF5pYw zW+B=@%qxBPAeP=3gJi;dVS4kw4Kl4>-Ynrc>w?$vx=(;(mb}k|fp-mD;P1g9xQ4F^ z2;}6rT_hOPxNbQ`(-^#=MwUy={H0LPi(6L3Da%m2OR@1Ie+QCr#i$1>M9{-nxD7YI$fKx&ZT0S=jGxhHrDzYRYMpov z20Y>1b$C{`H6dj00PgaVu}q>ouN=8uXNw23yD9J}_jnJF3S zY{}GdW@>jnb&IZKK-l2pJREGqT&ItwDM%j(wM`tSuYd7#yvIqHY%^VYtIu zkD_(<6Z3I8>5P(HhQjrIWlc5`tH3PXiI35(S;E3&@=Vo{*m$*r6^wOo#rq{ro@9Dl zO)5PB3QGl3012#17pA+knnT1@(N7=SG9NZOh1W}V?@G}jTZ9bsu6F|6&K{fmNNmUf z?G$;rrBObjCs})9h6B}u-1xy7vL-!{dbHm7I-;bCh0<910o~)!S&qLMf#g^{^w=_< z-TVMofr<@8iC~Tx*Z9W2J*OCVfAP|-yg**C>+3V}1B zzL38Ts{a@RXBNK)1LIMEx$jT@Qao0KBf|)1JqXuGg|aEj8hB7Aq_|gdd~mTVol%d% ztUx?47wIC|j^HxDE9;_Jt@;?MFnZSB}bP^m8!Cj%s# zAUkV;Giu~liV1FXeoC7aj4eY!gv#q)Fg=*^Ys$r8!V7+`23sgh+j{nA@7Sq&vd>`I zDSN%o;LY9{rGzE~!cdsBFK!nB1eAzRbathTbU*fPu*1+nyrN}d2tpsfNA zPM)Nj(a4OP3~q*VmDD*i262rKr!d^kBoYEx-|iGY2k_JI@>`tgK@bM#555Xw3*>X2 zNCkB$YfN+>DkWPN9Uq+1Q-C zEWou}BXrK>?f2!F@R-g6yn)Ec)__pJSraFHl!}W;O)op3TjLu({eE-*>wSJRDy!z4 zxe$cD?RDUzxTsvmgY&ilB@hgY-Ue{L;i11MceogV1rWTioSenp_M!#+_wY)WaT&M_ zAMZzR8Dk+Z>?n|Fid`kH5B0UYIN)_#wG>L30k{3YeLfI&R9zlgcB4FlUZ#Be@ zlRbZ{2xN6^Y~Rk5H=)LrEfsrm^>fCE;j%oV8fmslfQg|RD8n21(F<4}ls5`*xFx*v4+TUZ&Y2*k^1pAxKX15s e0rKw!aGb>