From 29e8a3286458fe2d7ac6a1eb872f0725fff19bc4 Mon Sep 17 00:00:00 2001 From: Dion Moustos Date: Tue, 28 Apr 2026 01:24:04 +0930 Subject: [PATCH] big --- .gitignore | 2 + .gitlab-ci.yml | 11 +- Dockerfile | 4 +- backend/build.gradle.kts | 101 ++++-- backend/src/main/resources/application.yml | 33 +- .../AuthControllerIntegrationTest.java | 5 + .../moustos/mtgsearch/AuthServiceTest.java | 24 +- .../moustos/mtgsearch/UserRepositoryTest.java | 24 +- .../src/test/resources/application-test.yml | 16 +- build.gradle.kts | 113 ++++++- docker-compose.yml | 4 +- gradle.properties | 31 +- gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 56921 bytes gradle/wrapper/gradle-wrapper.properties | 3 +- gradlew | 310 +++++++----------- gradlew.bat | 79 ++--- 16 files changed, 445 insertions(+), 315 deletions(-) create mode 100644 gradle/wrapper/gradle-wrapper.jar diff --git a/.gitignore b/.gitignore index 8fe9b96..645cb5c 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,5 @@ target/ coverage/ .nyc_output/ dev.properties +!gradle/wrapper/gradle-wrapper.jar +!gradle/wrapper/gradle-wrapper.properties diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4faf447..c0e4a19 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,7 +1,7 @@ stages: + - build-sonar - build - test - - build-sonar - docker - deploy @@ -17,6 +17,15 @@ variables: build:java: stage: build image: eclipse-temurin:21-jdk + services: + - postgres:16-alpine + variables: + POSTGRES_DB: mtgsearch_build + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + DB_URL: jdbc:postgresql://postgres:5432/mtgsearch_build + DB_USER: postgres + DB_PASSWORD: postgres before_script: - apt-get update && apt-get install -y curl - curl -fsSL https://deb.nodesource.com/setup_20.x | bash - diff --git a/Dockerfile b/Dockerfile index d84d026..a202a1d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # Multi-stage build for MTG Search # Stage 1: Build backend and frontend -FROM eclipse-temurin:21-jdk as builder +FROM eclipse-temurin:21.0.2-jdk as builder WORKDIR /build @@ -32,7 +32,7 @@ WORKDIR /build/frontend RUN npm ci && npm run build # Stage 2: Runtime -FROM eclipse-temurin:21-jre +FROM eclipse-temurin:21.0.2-jre WORKDIR /app diff --git a/backend/build.gradle.kts b/backend/build.gradle.kts index ccbceaf..23d9778 100644 --- a/backend/build.gradle.kts +++ b/backend/build.gradle.kts @@ -2,20 +2,42 @@ import org.gradle.api.tasks.testing.logging.TestLogEvent import org.gradle.jvm.toolchain.JavaLanguageVersion import java.sql.DriverManager + + +// Version strings for libraries +val postgresqlVersion: String = "42.7.10" +val flywayVersion: String = "12.4.0" +val jooqVersion: String = "3.21.0" +val logbackVersion: String = "1.5.0" +val springSecurityVersion: String = "6.3.1" +val springdocOpenApiVersion: String = "2.5.0" +val jacksonVersion: String = "2.18.0" +val commonsLang3Version: String = "3.14.0" +val guavaVersion: String = "33.1.0-jre" +val lombokVersion: String = "1.18.30" +val junitVersion: String = "5.10.2" +val mockitoVersion: String = "5.11.0" +val testcontainersVersion: String = "1.20.0" +val h2Version: String = "2.3.232" +val restAssuredVersion: String = "5.4.0" + + +buildscript { + dependencies { + classpath("org.postgresql:postgresql:42.7.10") + classpath("org.flywaydb:flyway-database-postgresql:12.4.0") + } +} plugins { - id("org.springframework.boot") version "3.2.5" - id("io.spring.dependency-management") version "1.1.4" - id("org.openapi.generator") version "7.4.0" + id("org.springframework.boot") version "4.0.+" + id("io.spring.dependency-management") version "1.1.6" + id("org.openapi.generator") version "7.6.0" id("nu.studer.jooq") version "9.0" + id("org.flywaydb.flyway") version "12.4.0" id("application") id("java") } -val postgresqlVersion: String by project -val flywayVersion: String by project -val jooqVersion: String by project -val logbackVersion: String by project - group = "net.moustos" version = "0.1.0" @@ -32,36 +54,42 @@ dependencies { implementation("org.postgresql:postgresql:$postgresqlVersion") implementation("org.flywaydb:flyway-core:$flywayVersion") + implementation("org.flywaydb:flyway-database-postgresql:$flywayVersion") implementation("org.jooq:jooq:$jooqVersion") implementation("org.jooq:jooq-meta:$jooqVersion") implementation("org.jooq:jooq-codegen:$jooqVersion") jooqGenerator("org.postgresql:postgresql:$postgresqlVersion") + jooqGenerator("org.jooq:jooq:$jooqVersion") + jooqGenerator("org.jooq:jooq-meta:$jooqVersion") + jooqGenerator("org.jooq:jooq-codegen:$jooqVersion") implementation("com.auth0:java-jwt:4.4.0") - implementation("org.springframework.security:spring-security-crypto:6.2.3") + implementation("org.springframework.security:spring-security-crypto:$springSecurityVersion") - implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.4.0") - implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.17.1") + implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:$springdocOpenApiVersion") + implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:$jacksonVersion") implementation("ch.qos.logback:logback-core:$logbackVersion") implementation("ch.qos.logback:logback-classic:$logbackVersion") - implementation("net.logstash.logback:logstash-logback-encoder:7.4") + implementation("net.logstash.logback:logstash-logback-encoder:8.0") - compileOnly("org.projectlombok:lombok:1.18.30") - annotationProcessor("org.projectlombok:lombok:1.18.30") + compileOnly("org.projectlombok:lombok:$lombokVersion") + annotationProcessor("org.projectlombok:lombok:$lombokVersion") - implementation("org.apache.commons:commons-lang3:3.14.0") - implementation("com.google.guava:guava:33.1.0-jre") + implementation("org.apache.commons:commons-lang3:$commonsLang3Version") + implementation("com.google.guava:guava:$guavaVersion") testImplementation("org.springframework.boot:spring-boot-starter-test") testImplementation("org.springframework.security:spring-security-test") - testImplementation("org.testcontainers:testcontainers:1.19.7") - testImplementation("org.testcontainers:postgresql:1.19.7") - testImplementation("org.junit.jupiter:junit-jupiter:5.10.2") - testImplementation("org.mockito:mockito-core:5.7.1") - testImplementation("org.mockito:mockito-junit-jupiter:5.7.1") - testImplementation("io.rest-assured:rest-assured:5.4.0") + testImplementation("org.testcontainers:testcontainers:$testcontainersVersion") + testImplementation("org.testcontainers:junit-jupiter:$testcontainersVersion") + testImplementation("org.testcontainers:postgresql:$testcontainersVersion") + testImplementation("com.h2database:h2:$h2Version") + testImplementation("org.junit.jupiter:junit-jupiter:$junitVersion") + testImplementation("org.mockito:mockito-core:$mockitoVersion") + testImplementation("org.mockito:mockito-junit-jupiter:$mockitoVersion") + testImplementation("io.rest-assured:rest-assured:$restAssuredVersion") } java { @@ -98,7 +126,14 @@ openApiGenerate { )) } +flyway { + url = project.property("db.url") as String + user = project.property("db.user") as String + password = project.property("db.password") as String +} + jooq { + version.set("$jooqVersion") configurations { create("main") { jooqConfiguration.apply { @@ -125,16 +160,26 @@ jooq { } fun isPostgresAvailable(): Boolean { + val dbUrl = project.property("db.url") as String + val dbUser = project.property("db.user") as String + logger.lifecycle("Checking PostgreSQL availability at $dbUrl with user $dbUser") return try { - DriverManager.setLoginTimeout(2) - DriverManager.getConnection(project.property("db.url") as String, project.property("db.user") as String, project.property("db.password") as String).use { true } + // Load the PostgreSQL driver + Class.forName("org.postgresql.Driver") + DriverManager.setLoginTimeout(10) + DriverManager.getConnection(dbUrl, dbUser, project.property("db.password") as String).use { connection -> + logger.lifecycle("Successfully connected to PostgreSQL database.") + true + } } catch (ex: Exception) { - logger.warn("PostgreSQL is unavailable at configured DB; skipping jOOQ code generation.") + logger.error("Failed to connect to PostgreSQL at $dbUrl with user $dbUser: ${ex.message}") + logger.error("Exception details: ", ex) false } } tasks.named("generateJooq") { + dependsOn("flywayMigrate") onlyIf { isPostgresAvailable() } @@ -146,6 +191,12 @@ tasks.named("generateJooq") { } } +tasks.named("flywayMigrate") { + onlyIf { + isPostgresAvailable() + } +} + tasks.named("compileJava") { dependsOn("openApiGenerate") } diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml index 8f1bea8..76fea04 100644 --- a/backend/src/main/resources/application.yml +++ b/backend/src/main/resources/application.yml @@ -38,9 +38,12 @@ spring: max-request-size: 10MB server: - port: ${server.port:8080} + port: 8080 servlet: - context-path: ${server.servlet.contextPath:/} + context-path: / + compression: + enabled: true + min-response-size: 1024 app: jwt: @@ -50,8 +53,14 @@ app: logging: level: root: ${log.level:INFO} + net.moustos.mtgsearch: DEBUG + org.springframework.web: INFO + org.springframework.security: DEBUG + config: classpath:logback-spring.xml file: name: ${log.dir:logs}/app.log + max-size: 100MB + max-history: 30 springdoc: api-docs: @@ -61,23 +70,3 @@ springdoc: enabled: true operations-sorter: method tags-sorter: alpha - -server: - port: 8080 - servlet: - context-path: / - compression: - enabled: true - min-response-size: 1024 - -logging: - level: - root: INFO - net.moustos.mtgsearch: DEBUG - org.springframework.web: INFO - org.springframework.security: DEBUG - config: classpath:logback-spring.xml - file: - name: logs/mtg-search.log - max-size: 100MB - max-history: 30 diff --git a/backend/src/test/java/net/moustos/mtgsearch/AuthControllerIntegrationTest.java b/backend/src/test/java/net/moustos/mtgsearch/AuthControllerIntegrationTest.java index 9276eb9..6e63aa4 100644 --- a/backend/src/test/java/net/moustos/mtgsearch/AuthControllerIntegrationTest.java +++ b/backend/src/test/java/net/moustos/mtgsearch/AuthControllerIntegrationTest.java @@ -12,6 +12,7 @@ import org.springframework.test.web.servlet.MockMvc; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import net.moustos.mtgsearch.repository.UserRepository; /** * Integration tests for authentication API @@ -24,9 +25,13 @@ public class AuthControllerIntegrationTest { @Autowired private MockMvc mockMvc; + @Autowired + private UserRepository userRepository; + @BeforeEach public void setUp() { // Clear database before each test + userRepository.deleteAll(); } @Test diff --git a/backend/src/test/java/net/moustos/mtgsearch/AuthServiceTest.java b/backend/src/test/java/net/moustos/mtgsearch/AuthServiceTest.java index 4ae0ef8..a0d6928 100644 --- a/backend/src/test/java/net/moustos/mtgsearch/AuthServiceTest.java +++ b/backend/src/test/java/net/moustos/mtgsearch/AuthServiceTest.java @@ -6,20 +6,40 @@ import org.junit.jupiter.api.DisplayName; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; +import org.testcontainers.containers.PostgreSQLContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; import net.moustos.mtgsearch.model.User; import net.moustos.mtgsearch.repository.UserRepository; import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Disabled; + /** * Unit tests for AuthService */ @SpringBootTest -@TestPropertySource(locations = "classpath:application-test.yml") +@Testcontainers +@Disabled("Requires Docker for Testcontainers") @DisplayName("AuthService Tests") public class AuthServiceTest { + @Container + static PostgreSQLContainer postgres = new PostgreSQLContainer<>("postgres:16-alpine") + .withDatabaseName("mtgsearch_test") + .withUsername("postgres") + .withPassword("postgres"); + + @DynamicPropertySource + static void configureProperties(DynamicPropertyRegistry registry) { + registry.add("spring.datasource.url", postgres::getJdbcUrl); + registry.add("spring.datasource.username", postgres::getUsername); + registry.add("spring.datasource.password", postgres::getPassword); + } + @Autowired private AuthService authService; diff --git a/backend/src/test/java/net/moustos/mtgsearch/UserRepositoryTest.java b/backend/src/test/java/net/moustos/mtgsearch/UserRepositoryTest.java index 007e7f1..cb6f9c4 100644 --- a/backend/src/test/java/net/moustos/mtgsearch/UserRepositoryTest.java +++ b/backend/src/test/java/net/moustos/mtgsearch/UserRepositoryTest.java @@ -4,18 +4,38 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; +import org.testcontainers.containers.PostgreSQLContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; import net.moustos.mtgsearch.model.User; import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Disabled; + /** * Tests for UserRepository */ @SpringBootTest -@TestPropertySource(locations = "classpath:application-test.yml") +@Testcontainers +@Disabled("Requires Docker for Testcontainers") public class UserRepositoryTest { + @Container + static PostgreSQLContainer postgres = new PostgreSQLContainer<>("postgres:16-alpine") + .withDatabaseName("mtgsearch_test") + .withUsername("postgres") + .withPassword("postgres"); + + @DynamicPropertySource + static void configureProperties(DynamicPropertyRegistry registry) { + registry.add("spring.datasource.url", postgres::getJdbcUrl); + registry.add("spring.datasource.username", postgres::getUsername); + registry.add("spring.datasource.password", postgres::getPassword); + } + @Autowired private UserRepository userRepository; diff --git a/backend/src/test/resources/application-test.yml b/backend/src/test/resources/application-test.yml index 134611d..f5a03b8 100644 --- a/backend/src/test/resources/application-test.yml +++ b/backend/src/test/resources/application-test.yml @@ -2,22 +2,14 @@ spring: profiles: active: test datasource: - url: jdbc:postgresql://localhost:5432/mtgsearch_test - username: postgres - password: postgres - driver-class-name: org.postgresql.Driver - hikari: - maximum-pool-size: 5 - + url: jdbc:h2:mem:testdb + driver-class-name: org.h2.Driver jpa: - database-platform: org.hibernate.dialect.PostgreSQLDialect + database-platform: org.hibernate.dialect.H2Dialect hibernate: ddl-auto: create-drop - show-sql: false - flyway: - enabled: true - baseline-on-migrate: true + enabled: false app: jwt: diff --git a/build.gradle.kts b/build.gradle.kts index 5362828..32628d9 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,8 +4,8 @@ import java.io.File plugins { id("java") - id("org.springframework.boot") version "3.2.5" apply false - id("io.spring.dependency-management") version "1.1.4" + id("org.springframework.boot") version "4.0.+" apply false + id("io.spring.dependency-management") version "1.1.6" id("org.sonarqube") version "7.2.3.7755" } @@ -88,3 +88,112 @@ configure(subprojects.filter { it.name == "backend" }) { } } } + +// Developer helper tasks +tasks.register("createDevProperties") { + group = "developer" + description = "Creates dev.properties file with default values if it doesn't exist" + + doLast { + val devPropsFile = File("dev.properties") + if (!devPropsFile.exists()) { + val defaultContent = """ +# Development properties +# This file contains configuration values for build and runtime. +# Do not commit this file to the repository. + +# Database Configuration +db.url=jdbc:postgresql://localhost:5432/mtgsearch +db.user=postgres +db.password=postgres +db.maxPoolSize=10 + +# JWT Configuration +jwt.secret=your-secret-key-change-in-production +jwt.expiration=86400 + +# Application Configuration +app.name=mtg-search +app.version=0.1.0 +app.environment=development + +# Server Configuration +server.port=8080 +server.servlet.contextPath=/ + +# Frontend Configuration +vite.apiUrl=http://localhost:8080 +vite.appTitle=MTG Search + +# Logging +log.level=DEBUG +log.dir=logs +""".trimIndent() + devPropsFile.writeText(defaultContent) + println("Created dev.properties with default values") + } else { + println("dev.properties already exists") + } + } +} + +tasks.register("startPostgres") { + group = "developer" + description = "Starts the PostgreSQL container using docker-compose" + + doFirst { + // Check if Docker is available + val dockerCheck = providers.exec { + commandLine("docker", "info") + isIgnoreExitValue = true + } + if (dockerCheck.result.get().exitValue != 0) { + throw GradleException(""" + Docker is not available or not running. Please ensure: + 1. Docker daemon is running + 2. You have permission to access Docker (try 'sudo usermod -aG docker ${'$'}USER' and restart your session) + 3. Docker Compose is installed + """.trimIndent()) + } + println("Starting PostgreSQL container...") + } + + commandLine("docker", "compose", "up", "-d", "postgres") + workingDir = project.rootDir + + doLast { + println("PostgreSQL container started. Waiting for it to be healthy...") + // Optional: wait for health check + Thread.sleep(5000) // Simple wait, could be improved + println("PostgreSQL should be ready now.") + } +} + +tasks.register("stopPostgres") { + group = "developer" + description = "Stops the PostgreSQL container using docker-compose" + + doFirst { + // Check if Docker is available + val dockerCheck = providers.exec { + commandLine("docker", "info") + isIgnoreExitValue = true + } + if (dockerCheck.result.get().exitValue != 0) { + throw GradleException(""" + Docker is not available or not running. Please ensure: + 1. Docker daemon is running + 2. You have permission to access Docker (try 'sudo usermod -aG docker ${'$'}USER' and restart your session) + 3. Docker Compose is installed + """.trimIndent()) + } + println("Stopping PostgreSQL container...") + } + + commandLine("docker", "compose", "down") + workingDir = project.rootDir + + doLast { + println("PostgreSQL container stopped.") + } +} diff --git a/docker-compose.yml b/docker-compose.yml index 59bdd01..259f3b7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,8 +1,6 @@ -version: '3.8' - services: postgres: - image: postgres:16-alpine + image: postgres:17-alpine container_name: mtgsearch-db environment: POSTGRES_DB: mtgsearch diff --git a/gradle.properties b/gradle.properties index b2a9a8b..4e120b1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,18 +3,35 @@ org.gradle.jvmargs=-Xmx2g org.gradle.parallel=true org.gradle.caching=true -# Project Versions +# Project Versions - All compatible with JDK 21 javaVersion=21 -springBootVersion=3.2.5 -springCloudVersion=2023.0.1 -openApiGeneratorVersion=7.3.0 -jooqVersion=3.19.8 +springBootVersion=4.0.+ +springDependencyManagementVersion=1.1.6 +springCloudVersion=2024.0.0 +springSecurityVersion=6.3.1 +springdocOpenApiVersion=2.5.0 +openApiGeneratorVersion=7.6.0 +jooqVersion=3.21.0 +jooqPluginVersion=9.0 postgresqlVersion=42.7.3 -flywayVersion=9.22.3 +flywayVersion=10.8.1 logbackVersion=1.5.0 +logstashLogbackVersion=8.0 auth0-jwtVersion=4.4.0 -bcryptVersion=0.9.1 +jacksonVersion=2.18.0 +commonsLang3Version=3.14.0 +guavaVersion=33.1.0-jre +lombokVersion=1.18.30 +junitVersion=5.10.2 +mockitoVersion=5.11.0 +testcontainersVersion=1.20.0 +h2Version=2.3.232 +restAssuredVersion=5.4.0 # Frontend nodeVersion=20.11.0 npmVersion=10.2.4 + +# Docker Images +postgresDockerVersion=17-alpine +alpineVersion=3.20 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..b498d2444600d918cbd5949508e2ade6fbef0301 GIT binary patch literal 56921 zcmbq)1CVCh(q-AUZ5v(cvTfV8ZFbo9J8MNm{yTSV>x{iLuFF3Ji11Tl+U-w8P@#(&NJb*A9RHa+2T>qk#SX{9hBOe2u?;1pKe7rVjc>R>ri3 zR_0$r-_g-d-^q;5&cW8s*ulx%*pZsz_oRe09cAM_71cQP$e45k=)Wd_|Ljx!V+BZm zI|1?knZVUS-|p+4e?N&dy@b?=_`LMQ$lm`w-EQ!dF5cJ8aQ;2r|Ll2?udB8WrvGyK z|7-#MZ;L-y{Wpg2|F_|nd;aECGXA$Qzk#EZgTA4YpslsFzKxNTxs9=)t&PiwB)K)v^bTwkOeCIBF)oC%AgeZ698%zV#A?G(LL6Q{PvM^>NZhh=V1}<$IHSHme2M?av^EupYiKc(K!zD^7uXa@bH43AN-oktTd4>A{ zFJH7wqZ)p0roUJ{hvA?Hm4Q=;CO<{xEy^a|QiyR}kgzM29L)0a<0&0HHokFyAe zBRq^5`0!RR@Y=cC0*vap9iEL?2I;x9Tg5k?8*anVX!+73gs-KZ5p?VSv?_5+an^zb zM_Y^6N?ExL8$6)PaZ~kc^uk5=ghJheR;4?(*fvz?#c0YSBikYsAo7^&{K>^Vl>oQ&+r*=L}0)Cd%L zsGpa!w(ZPz2wMr8e?Z+FMSDgF2mnA4^zWd~_17UP_rJmZ*TI^lqN$3ljPe1O#^8hj z)ej~_1q3Q3CNYOr3M))m#D+zej#a3977L?KFxH<2*_(5<-r)7v&?$7R;e5aRxf@7l z`!u)NvS^=p#%c9oCb2h3M(e%$KwvZ}oYgtJY)?cy1&5inK zC=_NXdF4ml${{1nZ`DgG;h9*ivlwM zQF2;~I2~Q`+AA`u`WTSRp@e%hsleQy7O{ga_pAh+IJ5Lo*%^B6lKf=64N@btnEDyp zX^DH4qhAD36b@u*4O7j*hMO)h=t7#KGN{O6^)M`LF#AwvNGniBzlCFc`<+*3iGpn2 zXP!GMuV<4FJ72%y9eiaYH899G6E43m{yOZs&rfRz@<9$izkI zF;5DLA+_z~FmFta9SYvET2OQ+)JD{dxk~t0o+kR!xoDBsQdmGfBzy5OqdpU-JflS* zEy`jEIX;+|WarF#kUg3rMi{bZG%K;TB)vezkUn=2teY0$Zj!AQt{V>Pg%$uUh75XA zVi$pSQ6+*{!_z0EK=TINK&$Bo%{ko zEaDEm)mZ8?ItV81-G77cIDry^QSC_t!oqbtjsos}0mR=AK_2tRfG(kO&*9|cvef{w z^Ukk<+mn2nm5$GUsR`F1T5ioR_CEV!?Z1{Q{{zkb$BxDCVCrmbY~v*CW@v2ZWNvHo zZ<>vplmKQ#80@;6tg4*1Xs9d&_xz>l439?*N(t4w)04b0YrQ1mf;@6jUcFzo)dPN& z*Ked*Z-ywPH$3KbJ1TYaas2|eg)`3NFuY2kBo`!H<133_hOL0u>{=$~)?bzF{Sa$M z3Gow}&TWRc6yI~Rl|R23qV+tEzYyjwj_Edr)Qf_K_}*eNaAIUq*KADiMEWZG%y z+W9C&zQK-t51n$Xh!lxrG|G!ZFGM++cZP^zaR``*+-;$3AENTwQ=}eY+D+=#-0Kjo zHV~JAy;NY-izQk>zU-_T`6=}f5e2+axtGhhG<0Rx#W!YvdcBRwpEzO9FxJ#7r{W-&t_P0@MZ7YGNbgPC`AgYVYPIKoNMe*({ths<2)2SZaFgymW!mVb5VX}kANG&W zL$Zcq?}M!tcE0>H{Rq8ip@O0JOtot_t1_zj6Rb_1W{R-}T_7>s;=+JpTO6GiQolERXZHsc)9 zQxh2pDY#hHHo8uU=y+rY~Q?zKa zNB#7ZF}Sv0@LE9^7z2-9%!=Y`h0rI;=#qny3v}n!v+T| z>6mqTSKXZO-HaH=4&Zd8#srnxMoNXtfTBX%!o+-QEbS)R$@LuN%I6b=H92g-E^p84e;4VlcR5HwZZI?@lvv? z)tDP`#k^IgOCWu)iCaH0p+Dhi_?tirtcvF`qnVv^%@_G&BD7h6dG0QAq4|9h0`-$r z@CuJbAIpDDO#QF{A)M_lbdA-mo^Va_fy}!k*CyX6a86e7%?H-;$cg3#j^qw?I>v0x z>BfJCe3xaAn}rcstcfOc)`M-s#M7gO)DPLT)1$j#ej~QzIO@6SL-*w&W1)ArTZ6^t zah;+PinAI75Uz*jqMRTci)E4IVp(AnV(h1!JVo&Z{{hOL3oHOdAbX7_mVB%|jX{Dc zz5y}`9rVmsj0d?&+B$H}?yrp0DV`yfc*bH_zjKhqy?{Rul37ZndVwsjbj4-8iHZ>E zWV}|#PdAnEC=em!Zq6YU>URx&&wwckGWXp$BO%17sXQ5M(J1p^4bA3aDxnRN7$( zmv7*DA0nkVV0O|@BkVB1kwheC$E%V>a~RPs2nUB04yU00hhh#HML2SmLiEaoci0Xd zZ_Vo|@GE!*X&lUZUQJ)CDD}irk2O33k!j>+5B@p6M?_Of0WtT_p_p616Ns=o9Vz4v zlOwUrJb($Pp*X0p*#iDm#uT!VLE=JqP}0bNnQT3B?@tK)Re!10W4rpYeo6=4#Spl+ zLI(k#fOoc~`t=&0@?C(ej!Qy!{NB~;Ve#VL`N*o``_-_o)IfF%B=l|0pW9gQ!G3rv z4}XP#t_9)s1kn@JpjUrhA6q`cEl01Mau>C(ZlojDPB`;Am;6UIvt)!v>3Y;5G-^ofQJSJPL@20P?VN;^KY~qJyt!n>k{I#a}ACl+)&@}&EH^0eO zX-CA|!O=<4+2G%o|8&KG%Bc*pJi-XB1E7?Mof zrLkN0c}OV`#GK5?m#pM%B4 znRnVE)C*}eBZ@|@hzasGLcz4i>bcSgha<`@p1tg>{Je2o0KeN>2)Y*uxzg}pXQ?(C zvYH9}3Zmw%-=fNU07;RHo2C&^mF1_dz(_OmuohIT6cj8Xfn1z$ZbhgMIt{WH4a&yM z5V2XLI7-wbsdJnSby*{tD;=^hR&Zi#VOp`%oYRcGDrPA)9-WJhioCHC;!xYEfIjA@ z12?BxA@73Z&!Lg^r4~>$!gKT>b!uP$#n0$QUz7AOP zmB8=G7_M{#d;vAoH?@>z&Y`kYFJ>upD38~cm(tFR6skU=%(OE--N(|2!Y}g^VyqOH z3p%WFSUN?!PylHLrZ5o!aTvs7AJUrk_qcbWny^hBaIz=yifkRpDux(8;4|O0nLTjl zA>a+%VHSdDo!(7u%UoqtrY(aG&6pg%gU*HMRPUP_6H*yDWR-C-d|saa+7J;mKIT41 z#t?|m%M5H1$nOq0*eCq!Z1-PbLsed=NDCna(W`0b(wSLoPVlnx06>8Z-fpS_DBoNG z1QKPLy{fk6(V=|(P@qH~+v1PcZxXFA7(`VgG?(Fxs{Ub>J@q zf0f<;8o|u}Was)9g8$UZj{i;`m91rG-EjS5ZlRxRc5rj+Rhx2vg8*?{R6v&B*rr%|IdQ9AMA9iMbJip$u`?;^p z<`NVWWsATg1!1n1p`XN*vPKCs=%Xc{n<%O^)R|+_2hB2N)`r?@^|^m+uv%9Li>M=?D4mNPz*OH*?>!v3(Y)qI!RjqXU(gz=KZ%?M%D04> zaz@m?S@6aOq-tbS#RQLirO{8yos<$U9ZBONaJtCOdU+VM`KvnvzCZyWheiJ)2=1&EdO zj$Nf_^5V7WZMm_ZG(Tc>YH9k^ZNgMW&B`c(Wwj|165w1@lyWUlo1Q*Iph==Ko!FJv zNXN2#m?41)@g3HT;@1S9OGjk-RNy_E!|M)-CbMs(wi%0Nd6jrRagTYjshayQefl|W zQ9aCnv8;EPUPD&5n*%EROvTl9$U`l8kF4>G6OmqLdg6m}7Xe|40`v4x7I~r=qh2v4 zIRcmCo`cUsbUs7sl{lX6A@t^f#~K8={4nw5G}xCEma@AG;XC#ge~Qn&!NVMbm)?j1 zuZYBt`6*Qf{%nZ*<$zn_)h>E-NP>F&>^-%C7<>vC91bS~)Y@b<^V@Jmk!9C-BEP%f z;#?8YF_y1@=wKJi=6AnUyryehidr8o9{SD--ydMeg3x^U`IRh^f&U#Cxc>t)QOJraU83M}Ibjx85(P0<&=A&=L%JNf@w*kGpy(ebdaSsj26&5O_hqi~BV&7JBjF3?J zr|5~RcAT{cNWS3`QKVO4-+MT?1RSSd5TP0JHilTLIJ!0rJwt4CXE1FjFos12{Q`G^ z+>Y2rs$zL<*6}eqx{wqcC&CPG%=Lx}P7tKp5OKi&$n@h|gMFjLRE2QFJ#M!>S9?Gn z?W&_(A(|9Xjv^EeJ9-_`AX%MeQD%sW3iC|9lCEfWt)JqAPp@%FV`Xv(y1Ooylqr&D zrg>aYT)#Rx>LJ;7=$0cQAk;LT4?3qL5eYdZ-eoF=obHoXu|r)n(o$uNYyp1dg?xK; z7$`N*WOJmY@R;IF0HOum9fr=_Z=0OZ4_k52f~cG9|OV z_?m+hOi;PBnt5{AKd4cl!j|c&(egXKGoaFPUV5By;2VNOJ{+5Y~Q2zmPM ziw$yPD^;@L`pvo&;3Cy{8H8-i(r#isFhKb_3WdN$P#kIIB0Tsn?+hrQ2_*(8@6bq# z?-vukGaPNOUPs44Pf`(+D1^)7oOF}IZQDmUs(>6mLZ(^_;`2P_pLq0GrnU9 zgd45zH_s*!#$JO#E+V4Mc3R;n*QA7w@t>iZJ^sq=&daeqHd0yK?3|V{!?9Z;g*OFJ z`SRB%+v=&LZ&bkgX{wjE-^L2kB|ZT-lP1oHZg8sw)wXS`mkP`?^D%{vs5Xq%GauFP zo9wW!OxE_*27jelIDw*$v#uwvBQSBF5f%JXZpa*V~*==(-u@Nhwk)|9fHNZ(>x*AV=zJpAu~P|Jyz;Tmo{a9k+rA-ttAmgTac*ddRLe#_u- z0`o~wTtpIYH}{@$(z`wylaCp~GzJGmQ)BQQ{$PYe&Vo>}c^%I_v^1AME>6}!7d%ZW z=5MnoFv=B~ypeKEU@K;ju0f*KzeWlgWuVm}mlBEbDb+fBq+^Ed8kO5MVWNKlZ&R?1 z)J~x-O5Q}gh?)AGiEK#bRSDGlYvD7dX~O#{H1DQ^RnfxlF3mG5(q(=F&p$m#fD0vy zU2}(F+tCK-`rAohvIKJk&Tschon^wpjVh$ypGf1_78Tj#y`9U0gE^&Isn3IYO&Ksr zwy)mnag#~MmL9ol5#mHk(vu0T+Ytn@{=uldZw&cCErg>r-I8h;8w@JX%wzs`(U)2w z&Yc!stv%$Sq_tyozJB-FNhl^yo6Y>X_6g2haNV?HbtJcpY_l~)&UNH0MhSDI*r)>=B%9VP#Eh!K5cHz)44sFJc5)&e2 zTYNanKEu4tlY{q9Orz$XczXJ;b<-*O_aln4JRye-lgo^NoSs37cm0^F)YpcHUT4)J zcBt2)>6PjNu#LmNlpR9T$n%&_MpK3kC z3RRWV49Ayo%Ppz={GQB{FWDj^hx@dg#>Pes){jG}gq|`bZlai-MA;jVaD6F1FnB7LDMtuiu zO@d|&l~Q#cltYFJN65CyXt=LCEBU>Qt!ZY9Z53hp|bU<&g_?B&mLiuBz3Vd z&se3{_$hl|-URp6ux=y;wd8qE=;5v>wq)|gb_#z&Y9qDYEnXL<{23?_5-ByH zQ?!Fn2eNxu5Nyx-Jo}G@2?w9=y(Xj!dqFE1;%#8gVlp-Qa)Hh!C60GoC(Smekw=@1 z;r3_f5ZF~VmQ}{kO5@_?qMKHEInsfkfqhcX?b#&!9L;01if_f(7#_FPIkDZvaNF%8Em4 zOz5&~;`T^|jCgmfn921!*jS9aq`6B3>l|90=&(1~^=4}XjmYzbtMUu}Md z2A=e?Ir+!GpFY?5(_4Ej52v_vYV}cR`C%gocO}&(ywHN(DkhoE_Wnd7<|!^)T{j=M zcM|P+Mfdi6p&nTc?xfzc@H0Cj*N{3{KL&yGKQz}0K&PU5y6x3e@6FM@+Y^4d7fqbOFpC%<&+YF= zNgkZYHL!!4hEy6%CzHdq%b2bA~9V{OulXG3UeL~V+{0`WU_+sS_nzTb<(a-o3 zwK`v>J*3$UH*~l-D?iS+U8;5~n&T45wm&V!gLr~xFPh_(>Gy@K8|m=%Bueo4t3iSp zcYw0#6gP%7tal7-U{S5C-1;Xao6PnL{cgfiqW4?m+Yn1tlq_?X{ zDzZfOsR)I`v(4I5t;VJ`-m&_49IWi&`!GRI2+BJs-a}q{pvj#D1XuEtDy1yqIWYY7 zY^}fKIl^3+hG3atpjdV(a5#{>Ozszg5CnVpZ2h@$D=v;r2 z7;tm(c1)JoeoYm!hjhn06+`rbCT$-p2}nH}KP4e3YtkyFZ6Uz8m_WSJeqR^MJg z>fSp*JEVlLH;_L_*x}%k8|y1~?LquI68=Z|tF*bJpo75V)y+Pt=J8Qu!{2+%Fl0D#ehxHS2G4l76nv-G&fN-+5GW&5sn^56ue8c!mh;yUAe$SjEf9 z_@qO@P}cMF`nUd330d?A7|ZgMTEALY`t>`)0G95%WlkqNe@_nI~2R% zu;BYBBvvE%3MWbNhLXNx-{AY8WknEVSH8IK0m|n<_Zr2jv6SE@hw+%ueX!~vjqjz| zceZQvKaf!p*M?a0B~S0Znl%5P^7P-3aMgD({x5l2sdWBFtAa<-qKQUR1Mx&vnHMVY zM!u9t08yAIL~XjT81kddda-rpBEC&?TJ#$7Z5LizD4K-V58gOa6Dk>{u0NHmgNykw z+tK7=?fL%oE4gB~@4^OjGKaw82u0BEiJO;Fj*u81OSDum882H5)*jJpe3lYhOdKiU z%HCh9XcK7U29@S?-uOoZQ>r1~YC`T=6cv`?EX4%b-%Xox%*(YUgeXAp88Jw{A z6XR3$bu$gUz%a*v#_0zT^~N|4xW4NcXr4nAk$3I94H35^4Dpw-WlkZ=K&a!r_jhTg z+HRlK*)&jRd;~xU!d^*i+TZi+yke{hmRzShTWfTXs4gi-yN`}wZ~ zuJ0tnzUd1g{eO!P_J5MV{fUtOx9kwDwE0If;NxOJo&ppskdh+6ukO0SDwiS)f^M2d zz1t|He~2kveWs!CJj^%57lOXiFRuUU%-3*Eb+^SDR2_U@pX)H&bCPrOdE)r_^TDvSGM4>T5dVHlCEBQmkQENSInez^2mFP9^z%2Wm z!6^x5^ok85zU8ed$Of-El+ZgD*F2(39oE?N@_V%>k_TbrQNr{Oz>twsMNm$R!jKEl z)=`GkQPuZY+DV3_^ouegFw6y;@a6-~koo3*TEb|UYL8TXHr4281vz(n^)*C$)j^6u z3=z8RMC;i?B;dl4V*V|5$9b8@6Vy{a77MjiUnhC@$LbmkC4wEmftX;;1+5N)mezf& zZ2Lmd3VhL!Po6}^U~{nAi_K$R%yZ89Qc~URgxfGrJ`*=bWPiXKGVWAlPW@LUC zf#nTyH{dn>w)wT$EZ3E6@#MU6?Zq+eamFW37N`yIK#f|Y&7}u_m2jBVCRB{#9eG`D zdIgmeFMr~QE7UdA)gxFg+=e}BnD8H?Fw9M9QX$#t(={yB1K4UEbo|&wMNcbi6!l8K zG-b4Xt?e{^#obAAvjl3@(yUWvq@SKtg`u;NI}x3AQ<>UO8MU+h2x(i<-ceoDSp~QgC8N}a~iq9;-|P~2AR1fa-N1njJYQ= zjK2y6rI-SP+jN_9N&@TjX;9de0x?z&rp#tC^=AQy^G(DE0f;Mg^ZsZB_y6Mc*@GW&4;b25(kOf-2 z^d1jd13~mz`}p%jiA3Xhwd4*KUFm*PKiSa|@R)Am4i-klEPURYJPv*Gt5_w#D~rO5 zzONV}ZYsK)cEv|FJK{(*O+MZa%)P4=h>A&P1g(5FKS$WGFakeox6G^Hxj(E~1?|9B z7MX_<#TaJ}SPD2JX4O2HeX1)#;-@Ub=3V9brquj$qpSY?$qw$ygmaA#Ci^>WQsO5y zepT#yA3s!Zf4}fcG||vN8ejzlAl|1$BC>X$NB-m$_cVHyj?2Vv9G~v=^uFWGtKVY` zf#lPYRwUNdNS|blYV2_bZrHZ%+#7YBhU@kZ4i|8L=!)FhGS%X*BZdWEE!4l(75}Jx z`sc3sXUX>8?bCm&iC@;s3TUNC@Q6zNMCStP5l`wMhSA}OJs<;HU6O5-k*n(_u8c1f zy#Bs~h+-_)fL`R$j!l{%s~}>tuZ)k`%%&z6XVrY0zCg`^iinG`-_i57JXi}3 z!pp6(P*<6L+jP)no5(w2u=N8Ke^0*?chk4X? zY3H`QG$Y7ux$*ncgehCRr1#M>wed^K5?L4{7~0V&Uw2O$Z* zT8Nm)!@a65`@DF#=n%>$JwZ?&?l$Pm-7W}EzAUvfhn8-Pu|2a*PYxGpV$x`R{hsQ; zQ4)-EZjgbR5ac{~H&tgDt<&~}3Jr4C^x0%e{E{je64^9##8!HH0^kSc^O<{6T-K;# zfc2Usfz+*y;sfjC`wODS-7#?CeH!qT4@4HEzP;ZQBtjoW2ya9|_roXjsd=Qfh{Kot#%SNY$m?M^CFv^)UIlFA=eHkFjK8ni(` zu;8x8CdNA5Z(Z2CKD^%Hasxp)l^jN-s} zw%x5VW1xR#jA!#?E*mig^@?|reFK+5IkdJT6&@pu=(39$*MV?HVtSLLTVVd_=|fM< ze%C%1oNx$R2bpVQi*2Mcl2R`Zm!8_O^!v+g*$j+MVj4PbD@0BSy4a`Q|2H$mM#n-*>>=rUDX3p?S_`3w662nkC! z>n`(-deBuZ)i(9oaQ^DHs{KVAJP?)KfMUE$;lwE$4-iA1i@XSQ803zmZXE3#7!14_ zYUSaQA@Pc#dZrPky0T;DQr+RW*pg~7!FWcAPCRrym|df^=H8KmoLEXYt3=s6%A8!P zoV;O6W^`3ai4TmGFo%G|xse=*M-0lMTi8J^mykRr0UClF0U;?86q`J3nB5i|k6T z<=;g~uum@2A4VzHp*($*uNl?K>rcM6USkpjW0Gf|w8ip)jq299)NWyz+lb2C2A_F3s&?C zF7#j*t$(6#<#PyM^slH2n#2gL@g*VZSFB`f+bqaHs8HiveVh(1O+S~C--}K|H`h(W zy%HTkoo9Gy)$b_g3}BsCNG%#!5??ovbIx90mn^}f5?+d;>#H2)E!#~H=+i1GYLi0` zsxd4%_?B(ekIu{C2A>#Iut&9}ST~RoPG3u6oVkZR z1c%x*F=9hbQ;-lhjz3~+I+cq2D zKZ!488_U0Gv~?&;el>|vJ|^mmieMBFr~=@H5?v?~Qz+0F#aPl2SoquYT+PXyoxTYc zEAG=j>1v4)#Wr7oH#_WFZVyIdze5i?nvxaG#Lq-WwjAHdtRo&`)+iAGlZ_% zQ$PqKsvz=%>rcB#EXNZ^6lc?>inz?vr35Q$G1I)q*-^DJKlFRpEYnwpu2$)5eyoL1 zYh_K<8mWb}NlhtQPWD5`u?8#uwrP&hPjavn4dXGYjp^(uV06;1*ZPJp3X>(@Uvxv) zYbEK1JhEH1AaBZ{LT*~7IY4=bAka&R_=43$k>#O$x6P7QVK*#@Vcp>gi6gBI$Yu zJr%V~nZ^Qb3Oqy7#-91A0sN5mqU#!}dwyn}U=G*#T~msXfYjWR&U+}ieO-l=oJ+AW zGjWFc@)+Wv4A23N^^$T)?k4lzF$uO;@g5%J3GnDlma?J}l?Q3WX*7E&pg0Ei1w=u! z_;7s!q>s;Mlt+f0LmHNKhjHg8R0<|R|77|m+2e~5>J<&2QzPzKPZ9FiPyy4AUMp~x zZ{L+NmIBL-A7ZD-9;doSp`qv;GmIdPkcsXv?O%G0_o-iwu?O9xZz1hKRROEXf#Vkw z2vMua2ZG#OaLNdrLMrbRdaEt%3u&fYf2iK80_zB1^#L+r6A-WPf^FgeewG4@TIj(d z1G>dkI^aB&fXlqVHQ)-XS^hwGEG^bg^EL_#dRTa!^UgG!^&O@d#Xdq`eA#r4N8+^< zsFMNH%E;uOpf^|%GPwb$_Y|5Jh3C6`ol_cMK;7dU#Js-6>8npMUC!vCxutrWO|-gg z9(0+@Q16CSX&PojPxdVWrK#;86-Tb^`a`ua>6`f+d_l_cZx4Nu{R2q-soJwN-1QRY z8$Pp)OgcyQfCUJ;bHDomh>I}bv{CckJD(OkM-dNHSogCV~YKVP_ZIZp5#t~vS~ zu4UkGKdb=)lnl>u4hu8_hC-5S1@zh#x_dbGAHr+QVh8#kOZKfcJ_~##`NuY_poeQ9 z_Aux&U~F`<)w7~(;AzZbK?e!S`&-GyuaP-yA;Lfo9j4ST4iNdvF`KH`Tx;)TY@k7d zlq^1JP@^`O8^mfjl_skpFX=y9yW_#|XZz=o-7reUmbeFY%H7^6!)pE zgQ|;^T)?ErP0R+JxD(cF4g>FtJM5uwgNsbRnxOuTUOodm1G(z2$@lL7fx(i>+$o&{=ur;_;(H@t zz?Pu!zn&=Yy@a{=D?`n{FQgx5ZSzY-t>_oTEzzk*tks z@~lnE{h(Kn4*Axw^4Nt?5fzdz-vr&;r-ShCHgoML#@(@*IOqepUKhFO7>ui%t(Y}n zK%}gCRC<2e(g`pusi=bLDhHuWP~iE|m1#8BMjJ$+3rkx0(xs}Duc5O|M?fFXd>{Tg zi8tRbSA1JOUs8HwB}FRbY~sqcON6{yE4T$2TB@?jMlJM0ng(>8Vc}WZJ-0$-Tvk!e zoRZ!wHJ_$0+({wsyqAR+Ru1#nX5T`vctF8tt5N1p9iGY)p+u^dEKIZ=2ChmVyL~ZF zRwd6Fw~7Hb;N>rOM^mxh?JP9B!A4^a4f2l0SuLE6&0eRJTyZ^4))}g)bZ>6mAmC#n zBXTQCP^l2!Jl=o)#LG{GCX=}AL?C|sltp%-@Wj%*98v2<(q6^;-rWzc9AwXYw7!sw z`fHBug6W!gO%OCtrId3azqUeSzt@}WLNy}=8*V=29Pax#pP4~Z)q;kMK}s^EUk--r zN*@_s51vFmQou->T;Zh>9o~Q}?Auts;qPrq2A+Na4pFO61oo z7R4@3BpXX@e7V8>l4L%p1=e%*L8-~J8@r$z?0A>a13elK2J`F*SXl>bLsR@#do?StZ*Jv!6_({^e>5zL2BAy_yeP4KEbL= z3@`7>JzI-Tz(UW9Nc=XBLV1L!D^JbPqy(AZ<3CXfhwB}m44IqcDZJrmNOoaM;@}v zRFwYa>XDgo^2;av!e~XgRk+za0mVy#ZCep1Ab~mQ>%-30;8I&5Xy~MfInlM^J&G^~ zHqh04+K|0EiF;!k3xk-*&~4(taB8NY=5$IDF=D|ayyvq%u&@mYm!fYQYsD(fFkZwAS1=A7WKcbMLA`khu6UC<~gZ<6&=rL-&J{|wV? z@pX9$5^6$~#^ykpf(Ymwqaq;*m~;z?^rX@~MNI7mP$NYji3)2;O|N*)mR6OrIf=*~ zc2DW7@Cm6@jF3sCzedU-##WrIS%jg(b)UNOtv zlANVq#rRld(@XSBIz*4g%R?ra{xBC$#vxkf9oC8e}(4rGuH#{7C zeL!nF`X+Ze5Eyf&g#1nEkluB&-e>`%Y9RHIo6yCuc>rB`CH(nlBg<((^Ycw#;LB73 zwW?|GD|~&XM-*`jh*TG&9b<@IIw2jK#i&^CES%*m@%_T=ktLAN{v_?Mbqvzk3+mmu zpr4YX<3RXbrB^DyA%xxafe_OeR?Eut69vQ|(-u%2ck7djEZDKBL%t}}dT5IIPSvq# zR_V33r=`IcleUTxI1h?iAbFKNmEeMjHizE!Prztf4pmJ@3mBJPfii(_Lo)?t-q z-f{rv5~Px86zbIE#}DZ=E0^yYu;BzD{bk5-vbxsM)Sgg#3in%t>9F3f{}6&nK08?~ zHt>j?C9?A=XLOK1n%42gmUH}~L8MJ*!__q`M2SY7N@oz%W`52sB*9ueze<}M44i!)ldPb(SfMV3y$Gih3 z6#E)cNSSEDqGWpHjB88UL!_#GR!{3N;pJw8c3Q=9=+(3D9jAU2u0E4ngcJs@?-N$h zH9vUEr#E8by7XBQf7cYxFfWvO7>f)2uC}X+T8-bb)jTI%cJW@IPtPZ*pwafF>kf6b-F{DDhn z*WH-x(dQ1NBL$SrvXbi>=jkbmQF+>pcC33dl$|8)cu3g}u~?e}0&9aBT(>3*Tbd`QbWAj?-z z951!lYId~CvXMWlewpAM?PQxw7F zXAl)#x^MuV5-pq4r{<2LzE(xgbw;O!^=#M#tC+&p#plI}IkNK(MiwbQP(MuJU4sg? z$-iqY$&1s^>^I0%4|+hb|0TSc&Oekqj~{K1uun{mnYB@LQ-TDyBvnnrN52x!v!cFB zZFgZpiN3u2!VGbWO#*3f zaZ=`ukeG$X(W}Lv%mxmdw9%gSmh$NlejZc z5;5e@lnu9{?B*r@l?y^_=Q%_!ozwnt^B-}&s{y*xNSiK+oxdFe@-^Jx$nZMV#U zCq1p1wx$#1TySx?AlVOuZ-#wQ+h(B;8&rw zswT&Bv)T1%Wg<tmmfXDzY=!TOJSI!WR&hcW@+7qkp*Iv)k~&mC+!Ju&Z= zx0~d=8emZ~IpcKe8Ty~r6m~9R%k=icQw}8zi(FRe_R9xsDb8WE_qXI-Y4yc76u)8z zBfH7_kM>;z$esy;O6#*<+}Uyff3?nk2p(v2hw|;Zdj+7~aG1g#2xAY@4F&2V zO6#U@e@K`dpqRW>Y8|kc57!!V!H!qEY3l&69N=xovD_p@pJ~vg)=DMi_OMmGlv)^k zU~1e$gNP?z{(=b4kJoZ&Sw?A-n)9X}}CWsk@YaXSQuz69a49#uuRT1m$WyRlRkKLE!&+@_H2Vs0+E z=o`3bj{zD<+iGj8>SL%JDA(UIXOk=JEY9;ui)w0|QE%1l%64FUXC#b@l0=j`k*<@C zNa~H?GFqnG_-O@6vx(J5mg8B<6WeYZ`t;1 zzqs(1Wx&p@FY=06xDllW19hE=#Gn_ebG< zBc~B;rN1E@_L}TLg1$n%?hzl2u(zy~J9l(e?TnfFk-^@`wPga=p-gnEAbp~(>+P`( z3CB#dMU3x>+*eoKpHRw$Lm6MI=~yg1=C9YT&>6ur>gNuJL*5>~KH%LzFW#Z6 zn-MSGfn1&s_oQpSKlcou+|#*a*y?x0x$nELzW-3HMj81=biT=v4&Sh#|GDY>-zZl9 zY$+Ih_tXB(RQ#7>6|MTJinW6BnS%;8gdS+s2Y)~r!yo{TgjLEADb7%DX_&G&Bqx?> z5;bgqO`vZsWL0XO*kqoNauF#&uRs&0IO~? zhJ$!1%wE8(0L4sF*ltnaA&cG|XsbsK0P}^h$hTZADTLhsB}}(!AWLUKq-ZqdHGbqa zHgYsEAZ~0kD?&0ZOUiDZ7r%qv|U^%Okp|&m~2S5OJ?CFt~1p3X3u1yjaBFHFn8{{n7btq za+~ckGL7D|V(b;ueNfQd7tTR11L$xU=;y|`e7o#x2i?b68;9GG8*5sM%uE}Ar01p) zp-MNsHNp!N1*JsM_CcwPDS_4l;xqNQD`*|>hJNDkxGCYsscdjTwMbTobHgdCloXM| z5@W(bUHHoV#omHfKZM)E$6c`p@dnB-YS#$~X#g=MuwcMPz(ihEc@h|u!}yCWvbax# zzHBEo0-i(7CE!B;Sj^4DgIF!qEIRhnog0&EF*b zz8}6cbf-$DZzPZ!(2b_}smo1>X6h_u7!ng*Ov026fAVCfbqZh+-8BIf3T=9bijmz- zG-}SKV7BMDk2qc4SLDnIR|( zY97yuktXk30`@huW^cI_fLJc7#M$~pYJVIPQ!Q{Z#vv1Ltx@a9bg#!|ceZ}3R=Lay zpglOf%(j#xOL!STH0f%GIy07EFflg z+))7XqJ;zoo-uH80TT&e;X`&2?X5y1UAyueaJ$Mlxrt8|Sut^%s$nZh$x>J@yc2At z6UWbb#&(+3SF?V7M1L9w2QwDeTlK+h3zjdo(iX7Oh|+^TFvYKtUIC6KPv)iyp(Bj< zA{OhT8V;8>%j}26#^rK*5y1N5#Y%Z{PL&vm7+A{PNkC5l$@jC>^pe^%is(aJ-3iCP z%D4w7B!j7A-A>?m*|{MeS|~Qsd~=purD5ED_L68euq$)8R+z=aB_0sjR`%~Soca}X zBy;H-ldJ)4;&u+ka}^mhsCF+ zYlnA>ro!v#W4X=;Jf3T{TB+TGscZG}bM5}{O}x|eL-)^RGuxe7#R*&0Hfwa1bA%#@ zctjp-{XUCUC94wl&ooWW)%*JXw=a~OAT@i;!8ZQAd%Hv04+_WipTD22z1&d#0{!hz z$*V+*Pf*}q*F|{;7NAk4@mJ>F8<`wm?^Rvi?krFEAoPXfKenY(jh1Q)S75qs>AWGw z9UylxgtV@!|5eM_zmm3(1#&9MZJ&0!26AexC5+MxyEpLySsis(c#GXL9+Xbo6H*H- z@dnl-?$#r$e!Q^u%36Faw;kGtiJSUWx@fUld0P|tzFNDN7ot=18Tt2%C=Rx1#VrI4 z@e@%ktJv1On#!x|Z02U_&2Z9X1jozCf)yXYN&;5AN)6!Ke}FL-DY?S7Ry}3scW(dr zez-JKj)+ z<|jA%4%r%BiPVGtLe}M!k46`WB8*`F>TrL&;^&iOn0$X07vLVxwinPP|DE&|(=`YL zV(cYcH?yk^>caBa8+py}2`}r5$EPR1429q9bApjL#!n->^S1CvX4UaUG;gp(7&5LkT$9$HIR{XO=}qn=b6a;ecO%)EeG zFk!j?*m2xBNUVhs|8%yNQWd-ai4QO{9!BfxbG2VJ=nIF*u-z?lg3@zPy$0ArdChI% zCh1J!r+Y&;x_0}xUUf!8GaYRAD{xOWy2CmA!b~N;tMnVBTmbQ$FY?Oir$r8=ft%|u zkHMk!TrL%;3~396WyRk40P1zRJ(qWLNE*{wU*#xIn1<*$%Fglu?C2hVvXzo;t)I<< zJ9ZonPENrXYa9I1qNb?SfmS60t)ay0?YGsAG;gi)9GA<8Gm5IT{~qOWsvXfR#g99n zoQZF#`WV8766W(^VW6res)FyvyE4tLsVf%x>D{U{H2m@ z#DtdnJa+qDn+b^EK<*rXcqbfmhlssx@d?_bQL2u1e6db7@CN*TS8^i>f{d4A5GVin zYx()}pOm6+(L?p{yUXh%9yH&FlIov#0@Zuply=fA24C2iRSJ!GE_xQ=8X!@i_z z0`QGlW#L;xc77p2Mu3qC*p*I8338{4ITzsva*cG?Ef7*Nez?bFEMrb94Ri>xPL-#p z!#^M&9LJZ}-!`=$X@iOo1VO?=MnZE0`1MmRX$JI)ip#96OBGakhWu>Kt>pMwV=6*J zAP?^1(yDApBpW83BwO|*Vc;Wk5b8pyQ8o|YX)RXLb5<%$O2rl@Q-fWTwu>^4s*q`T0wggQ~k&Z!JQuNsx)q zQyNGOv(E!{%v2)7+duH=E?YpafI$C>Dq`2R#jM$;SIV6nbF8AkSYeO`%{X(IUa~6R zdI<=dYC^Th2#*LVp!~_S z0gVOxq##~pr`ssnkH|-XUuY~bVR?LZTN_+wUXu)?&B$`9!(txY;Nl_eBNevXisiE6 zP3xFYg!Ytt28w~-5~~18MC^ld_KU^?YLAsBz0Vet=UT2Pj6T~>=n7uo3Vr{LU|*NO z`>Emhgu##aoF$jcgTDuQ=aa*seEs;w*@4ZVS?5*(-Hx&|uAcKxmw*4D^x?KdqzRD5T0ty~ zBES|wZvJNAJFG#2e6Ctpig52JHX2Aq?b?WwA2R5rFxZZ>-wD$~a2O#(eM^cfSF(j7 zhc8q99WN)52lrIo;W`Dym|T{bi$=A8!p6!q62p(Q;h;s zbxn- zXz<7v*F{JT@}<<=F58U2a6qDX-Am8=D1;hzvqgmvHp=-v^fADaRNxA!Me!$e4hqNEgWcsyjE%oT<&l1|SF_vtp+-+|#p7cRvROu-gfH8Ht1}26a zYa>9ljx)s4kX><_PbTktXLb^;BPC#3s$ir1!~>F(EBvY`FDN?S@*emfA6F?k{E&X% zj$Ww$=;-D6zt>sO-OY6yqeZd>O8hH1M~eFe_(Oh}M#-=)e3)nQs*7vpA~U=7IaT$C*`N%rLf#*I?I36) z1lV>vYSFlONtzAgwo88&AQQa(j+8M$APgsluhlfs?02DAS?r z`I7WNmY}DE?$53n+oO3L-U9Gqv7Q_cLCUMqS!Idh5$k=}FgO{( zzYjY=`v0!+ep_XfhF+8}ty&h+R;yw#X{P5pe0*30+H4w`Rh);|tXSP&f{1ZQH{o5&Eug~QQV zKOGHJ@G!|d(;$l=NoooJ4?sm>fYHonfabK}P;`k-05HL685#$7raQ(ERRq8;gqR-( z??GNMTIn)hDomHH0Z6WN7{VCiCf%o{$Qm5@6_hmW^0Lc!`xBELWp>_!ARhnm56k zvCCofav`+`eY%Ec?;)F=`5B#3+ei5-Aax+(kfa@}F>|&8F=53EHN{>t_8c^aX2bc_ z^N0m0Iq;y3kt7?G1kqI(3iOdre;e1*wQrI$IH6kBH0^M^{@TAQS2sTj3t6#Gx~pfm>CN?dd_&<voOV(IiAaH!Z+ zt9wzAA}rO{n09I-FPGOUMrfG?<)FA8waGAMpJfcRzR5|vTVdJk%c_b|M^Q+qSV)$d z`qf-~*og_*2FOD!U=j&#bx|I)LT)wh_?v=m-7;k6apK~!W@qRI=c?RQ+utXU=jd(S zpu+%SE{Du>>2a6>DbV_bV%TB=)i^-MO?`)=&*_3335`aYm7zRuEqaoo$PBUqKwSCT zvY5$msyaP=RF)x!u!nN@uxbN^%N;Xpl!-L5qG*qSEr#Kdt{UOS2h_`B1 z@gDT%rEr|!sxVZ2ZfLVh7UX371~RL~t7X)b<>oX;R~AhgVF z09O>v!v)!Kr~MC4`lxPp8P_f0i$Xxb0j#kmVGQ(V1D+m{+pF?mTPpmBH+P;8VOwPA z0}5fZqgxQ%*o1vYKJUOtQd83_1TRVX45r*m*G%{`s61GoP6Cs%uoA!=#r}GyJiz7D zec$&~cjPN1HBg9RgowqT<()qAdG$%GxhMZ@78?WBBNR)$;zv95e zt0#s_7G6Ba*S)GPSLgE{8X%CxR__sUM|t)4G+AX}K{8)F&Ix+nIQyGfz{`&>&hC^j zR}ZYKIG|u*0h2}n2YW=)43m#`qH+sk*!e}m5pvx%{qo88kN0nVxmzs!ca3%SAAy8K z|NWy@=$jm4Wvg%WZ;GmSwB$EM6+P(Kwz6Eg-V;HqjWta4<|pk?Fj<&&7!3i1d9$nI z-cRl%bd=U<`W-8rL+<+&znL|4Av|O=`@^`@Wp{@8AFYZejlax!~`*!_A%F*~#o1;cssE zzhO`Rh{;*_M#S56k{GS205wH1u(mMF|CAm{{Vgn}I7eI*Kng>d&*NUb1ZFJ$r_JfF zuvi~(R~-cLKYZi%*)F;o6mep=kB_$;BRwuYpKnjVeLUPvaRTeVhlkOJF(TrvJfz34 z{BJrES~mndW(sW3g}UmyCa;RH|*^E2{PqCxUD=i zyVb(AL&8hsjN+gxaR(zbd49^z!)5*%SW60*gr2Tn%qKu{2Q!<)sCEn9n}Z+lO{lX& zaRjSbOB)$5KZfwjsw|t|chHuQnP#%l?=*;iDxe)h6!ZzZb19Z1G9$474>_&Ci%8Ah z!XePT&GuuIVX3&!8!oPW4>S^K{z%JL`rC_`ied7w3`>JDn82lWpL;G29eE|T)ZCyW zV^J#}QQK*;;} z<4<5+&W>oVu_l9nXE})?#fO@?+`$2Fn2C(ue~vWbxH~rzeiuVh|It=X@SpeKzvO^y zH7GB|756XSmJ6zhmElo6co0HFe4lZMxZf8+ep3^AQHE8$Qg|jnw9uR%?|wrx8+;8%A3q>o!i;PMV#foz9xiC)?*OC6AxSTH+~I07+4U zEyv#b?CZar&yqV|563^OQq}P&<;?pG3m}&Q9>q-?9Ovr`>^twf45ubnWsZ9eUxm2M zg+Z5|0f_YvHvA3kz0d}}4i57!9TV1n%%M5Q#7AU`-wex}vgJlis~lBKHzlN8LKbAG z8Pvh%8P5XISirm_#x?i{fyV0>OfPPm@*3KWn?gDk)5}I6BQRG6dH^ZP|rAwg`mv1Q$=BQA%(_CYx!0wUkY{9_+6CmZZ zFU=F5h^t%3CJ{1!O3L0gl~qe;@9yR$`$XiHw!><{TGijT*(9Q8F`!;^$44!7JWs-) z4*j+H9CDPk&Jktf?3EhsIS0Vc;KhpOpuo{4OY*&9vgbqpf|<*L^bT*jB(7@PT_%hd z33=;~ET^oetQ#59d7xibSPtUZ9|FNb%eJ8Ke$>Z%!eZCk$A|snJZ249F+Ucc|4E3m zneEeYNpDC__gmJ)V8G?#q+ZH{G_l0g+H(EJOf?N^z1vDC5xN{LH>uiMmr^1xcbQ8l zh=1^w0T8AoIuV$NH1O#2vzz{mFft%W#S!{Ad zbZSXZUUAiHDxxFKZC$vcTTnT#4Pb=Hp31tCc%4f;B0zb{n6W={A&NhEDSyr@Y=D(s z-vCh&pszU)gN@!I_*96&rJUsLnl#pPXG|BtL^>UCt31{(`5I{BIZ#q zz)U+{I2fvo&Kr6R^AQ!E3xImCYL6<7p5dxzrmE=oJ3Y6=c-%h*l}mXMM(Qo{QXI>v z61YAf^-*_juefz%G^RSkQw_dCBJ~j_F@_0b<>ob(-GKC15>nxZ5r896GzaZ8*;l0O zLb0MhHCuH?${jm^(Kw|5ea{L{MV^#g4aC?;SMJkgxpfCsg1PlGl$JTS+78uK&G~@o zpTv@wE{^N@+F@wL?>5+ndLgW|7Uw^clp=OUqFEu5s9dm}&$1vEd$mK-Wxd%T_4(DS z$q8YmC4zl09#M*F9LOc++?sW>{|t&2dyRv6g2j%GEq*I?GkbHRC%3YtXTAqRIxg!1cn(tgfEn@ z>F%}k2k@tSoxxm>=E-A2u8U$hrkVs`t6<}c;&>0f8UyapjKli{?W5BFUlv`D_6zlr z^gGFzs2IsFzHfB z|EQkSOqqzs^(@140C%;~dFoykFf;-`KrL355@0BnOtEBeNS4J&jZRQM)PAVGT0n=z>^zwUz)+Bo|!$2Y%>jzJxd8UgsrRhpNuAs^xR?N1#8GC~Qyb>0g z09wgG{zAPFbJL7Lcuscx+Gx6!6`#)Dx0}<(yvEqW0AeDY#fas&475TJqvW(nTgWSV z*Qkf2jG8Jju6*}Z&BG!+D7H8t+=w%6d~&kxZha14zi})IiJRMl`7lu#Q4a@2Crl%? zwlE7k;n*3^urf}Qoua*)D(PIi;?v!j$XX2&&*&mcmhD-tnCd6z=yZKC=~y)fTPb4RwX2T#l(E^#<^xb&wl--xB#E2mgG3lbf9k+d z_EpKBC|P%7tXfJx2a|*&!u!>ix+lm!r3DZr@oc4W&}tN4Ay? zkuBs*U=K7}d*{DGV{ow7@nCb$c$gXOf(9Y!5S^i`mDVMSM62C~Ym@?^r5BhScKbf_ z7593O-l_ae0z6W>pL+96M%o)v-6b2JMi8HVo4hq$LRZquJzo)b?v(u*TJ(fH5tjv| ziD9L5in=HQ$1oh2#%eIN8*ZEN8wRR^vAoMY&+|&46k<=Lb6u6`=z7fM>q3bv z=9pLD@GrK4lUW3>#^M}fdCi{gn>-*6N-Ds(xA+D~xt~GEh^(Ss<|>)Crqi9KJnsF) z$9L}C=4DBhvF7jDL8=eypPZjnftVX>YllB`RtH-VWQK8hEj2cZx(#9P3P>AOiBxXb z#D+7ALMv6!C{6=g+qo{|0bEplpm8mjsF>F&+yQOyyD%aFC8yjimP;N|a%?@)i zB1{>)VU8PL_Tcm%$!>@~U5#$1&)bl1du?I)J{1(V&N3pGr#nhC{#IF6Xb0zJ)wF*= zuWRr@EckLnlEqr)bvLHOv9Rr`#Vhk6 z`LW3*14cM)@|uYvspxi}YEb?>!!+Zm-OfjHp7czLV}HE2_;k>EClG*M?E9cGTot}v zoBCalKK$hLfXi+`+dA3v?LHawf!_Zyz#b-#Eszvvjx7Qvdc%qhFhuV|f-Wu%d*sGF z)OHI)+oHG4FFeHQSG5Du9YpVmNqiy2EkQ=`3awkAAI^U&Qrgom-+M3^m?ya5l~9aL zE!K^hFW+y@`T~&QN}$S7xl4?CxBpT61C?KX|E_`tsM=E zsz@@{I~0hh)Dp8V7K|WJifo;*Uk}mG=8`ATaZeO_QR@HezBrj^m+cP;{0?o!bd%*@ z_H(4K&ObAR@R%Ui{pi?1t)RXqGRIv)qZ>J%#3E-s>Ed@k$5n2cDTJ9?L*kbx$mgVD zZi7=K;z%X$!coHmcy-yl<%07?WRuBl!Od~vN9Ms!>FcxlXE%4KZl}WNhK2X8lswKV zG2C1c6t#>(7z1~b;cdN^`_|SvYbX{lPHo?P!Iz}3>ndLFJm2srjA2Qo&C<$-!uMw;N7PjKk;wtHZHpSJ<-zZQA$%~{YN4Ch zB!J=AB7Emg{Y1xePVTf)mE%Rs4R8{h=}xEFgXq1vqFm`^&m2oEiv53wp2 z-C^95+vAnMas=%4g)h)$L=!am6!5X(Ea&JT*qOCd-HoeBtOJh0I(JP_MA9=hrARGV zQ?!GRgpxlevL=A=j`astbr+SyuCR^^w39n}K0ik}dcHhoDcV6bQ1w0IbrwFx?L`eG zhTdWz{_M9hy8%eWAcCzX`@G!NG+rT*mvjrAQE?{9%+0epU{#$nyd)0$m=E-c^(mxd}Xa@!-PeoK``tj3?7C$iqS$X<@jkC`?di(QI40xt_JPE=YLUv@G!A@55MDn0&)J6Z1aC)F8;fR@Nb>!TeUHDFm`m5GXL%! z+59`&*g3i%GT`^OYSlV_hAcF4B|MAE=|UYKM4r%LdlgHuKi+ZF>3s6jqfD&O(h(iZ zg!kythx=z0{mm{s>iQ5NtAa7L1yN)`^y(SsOp}smq2Zu0266G9tmsf${iN|uRqL#RMvZk|e&3A%9=gd1v@#;2pj!ZjiCf^Q?(9g<%>XoX+K#$-&!P+G z^>XK&BXw_d&vgucWVV<3bk^011qeC53J3?J>8)efdi4lc(jW+4A%f{FTo z10b5yo^sZqxf1;R0-TCIzw;>*6P|9P%ydxMS|uquCXd0o${yz}>_#icReGr%y0aKw zOAjDxe`VG!3%LhSAsxz%f&xX0bp?BCu4|AISMAowo&cMlEKb7?ObUuX+N%`?Shxr$ zX)J+`9j2WA-1#e~Jp&foSplM;xZ2^ygg4ZtPew}(k|n9X;WUamE-78~O8o?!O&=Ih ztSu=uNRksjI+ZW{hmA(jvk{48YfZK2HtNzM4Qqcp&9WX9H~gjKCAb_0Zk;C0=Dk zsdSUn_k{8Xts({_^dvpG&mo&V2bG<9U*$64sLkKRtpqnsgG8!R#iC-arX$CsbGXYT zdD~)sor#i{V({EZBh=Jur3UPXgC|Y0Zrg!zoWNg{RRZrI;-D=;_CN^dK%7&l$!en_ zl&xmBsLycfL2EWUL9<3RO-dPi22!Xi7$n60H*Kks7nr+0h;sDgX^i1IP`7j#P6hp$ z5}%ZFV6a=R2tU6(03!=!^-<17MRu14HSLH0R%S)YF$cz$I|>>-!L0T&n&~9M#^cnz z@&xpSuzwE9;UKVg$jwBN)=*NwOobclf+eSuLrhv7s$q|H1`4X0N0%*S3>x@@QTGh< za|J2Ym1Bb!9n^)?F`h~h9i$QS8S~L(LQ9_JPgy~~DHB;sk2D(^JHf6-4K5Qsa`JL| z`{wj23%xarLFcFnvPu%Bf{m7_5L(PlpSGE^#E{qYz~bGE2zQQ%7TX*N(k&)y#b*wb zaXaKTO3DT^6%tc}Ik-v2%*i<%)e<7G*9G@GAub>#6fM$CJZHp z*tHu3v0Zqpb}@R|*STa~n{`G) z8oi&rhM4tqYl4mH=Yx#D2D@=HvL>N_^$ z2h;6F!oMKy5EhaB;qiYj`WU~*_@fT3d-R6VBRw$@YBm1J1^<_8J9xhLUfZb)3DTDZ zInv?sPY0UyYADTWY;AnO65z(!t8jZM9|Pg4C?EWJXQ*{lm?^$@&gd6@PJ3+4X&?*n zb)o4SEbalT@?eb-T`K0&R{w!1m|I44Nde2l*0BC7wj0vro%;!^$MwP3X^7PwdGM%r z6-A~uegi|iwJ~|_**E4d^Nm5+XhXr;x4*9Fk-WAy*zlQwnrJ%ck#@S+K&!0a;7D7lr~84d+(57S^w?Z6qij#%4)XceO55!a&k4|)P(^jf znjAqlr1N|~3UK+*b;BjreG}hkMJ4*uugS0Xm)}l|q1gqRyz+<$b7(zyNwN-NT{gD{ zz}Wa2=ATcu%X6_vU8P#XKb)Wof(Ee{MRyM<2wjnP1{d6bM{ZDUp?d{TdqrS-`{6B; z3@Xf=k@0qsKf}2{gY7>ubB{=ng@W)*f~PCci`hzr;P~#j=xJRJnpQ{dN92oCO#uXV z*nrnM6WaO!%C^wV7gl5sxj{*{bmnE@#+bHuSe2%5yV1=Ux#FsB07Lhi4R# ziUS_6ZyTa=@{Q{UJf8rSkCeT$`kk{x5C1qw(${`a0PW|c#{QpV*JHOAPDL_GbQL?! zikpSduiZoZUf}vyv$ZysvbD8zw)-#Fo#KYfHw23(^Y;aaBNM!sKbRR51dTmKw_rRudK@?!2|R^t zytqog-o>bW*@@~S;ZI5hy!Tn#ii&AY3JH9;u8XUvndx*6-uL(G*xVneb=dqr_#tp0 zIS~v_xLBv5rx-69T0Gq*BXI@I#+syU(+SeVj)+I0nPN1T$7|#p+MdQ(C{eB~uzcL) z{#=zfjxWSGDpZb!$pJX&l?!FdiQZ8C18g98AU)<*2GV$HJwB51D<`{oR`MIRIR>2w zw?J;S7HH{6uSeaqbJ8TH0ZF69;NghT{Y2Q zz8UlITft>0Ho3tB`cnPuxQtO%r{`3^PX7*EdO}-twveKS*p~7wOH~eSf$xKlyA8qH zB#_0BL6$HGUI=J*4$-^P!C)$*853g|(I~6xAbVBpVjPj5ayXL@>J>zXK_9f1QeGIl zJU>i+OEksD7#*rOoo5&=sZ3RvWGq*^kJ(x{>-A?z;B%R*);)?`Jcn03_Gb13iHgis zS$i3THpExdKIwe+(e=*+vuw8STfwNW{iPg+**XG4^k&YcI?&2ch@N7KX#2M|NE}d zzqYpOw=Krb*x?_}nE%?>YQNkRzh_bCQvMpf>LaZ|Gl2f=s!I++Fes^qak=?HXCMX) z_qv8E<{{uQAh%vZm3=BcWA)_wr2~&)K|y{7+erOAi_uB$npv zl;k*sRV>K!jiPA>6cjalJ7JBx-`~h6jCmv=DockyI4z#aO5>LjoAi^*a$5ZYKYddi z`|ZeQ4TK0aoZ6U>m*C89gK(eoAcgM?!y)lfAeAik>KJ(8c`#Up3waorjD*a6X>f9+ zmsmk39B0p&4)RaRu&6*mdOx(9p4o^gw&_iToXp*$BdF?A@Uc=@{4FhGoQ^ElTsYoa zGKKVcDo_^7%7nL!XSNetlvqnhG7bvI!f;tkzX!F#u&~^+6m6Ixk#i+NoD}<&fw1mb zpR%RXJd8+#)FU*aPRwN_E`Sl=f3Q}p22BAK^Am9*VoDD?`#ZBV0@Jpu1zRdx0h}L5 zNllL-bBhhwCCT0I9|F3l3+#K~)&<%~%Hp?l@6EPgzIj*tq@ATwa7= zn}1Gd^qhS5lHp1gw>`OJb_!63GrB19X4$@ao48(dpizfYbM{=I_(I+k36aQ$oR4;b z45SrhnRFu+v0w}YwKM!h7^zeWKIjN&3P)9I19dQr^=h>K-G~l$Dt&YrIshFwH3fU| z0D@|)vP3;28xGfuodD`{%86_d z4PlpBKMkc$Kq}-SM_W>E*`-uvom97kO5a*zTODKe;DmCQKns)#%+h|BT~V1k?}uZIm; zwyw^mIvpu6oAD6)Dz2_4St&geQNWXIyJi=May#4=LTNIrDX3X!U^sR({h}f*vsz^6 zEP7eW)GVMYB6PCR-wVUz9=A)i|6QpI&$S+}qpJXPD)!x&%h*k{CfBo zikBGRyZ5x*Aqj!#RB_21kg>&UwBA-`0|w^7ReoZ~Ub~Bn^1Oera3M{17r+|rza0}` zjYA!ht5-jfbH;_m(#&LS8ql%iOrECKoWqO-;`<5;YpL#8=G}Qq&FRHIVUwK?RTR8qSxq`{Tm@FOfabJ{;oufrh}dYOSOa zn}nmT(k*z8kYiG;+2OS_>>}6xu0N8$qMK5{T{3rR!@awV{+8$G;4pmvT4>K9L|Harh09V#!ZKn~N9iwC0>X>)-;uqXbtz*&=h>Q$beh@ z9~ADPhL>Qnn@up@#oG_pk;+G#tf(ZIY$&aM{4%g=^UO3ZI}?`Enh_-MyVI6wYGwo2 z#)t1zLhtPJ45{MRBw^*Xnce)tu!X^1V}T{&|*<|NnG#bx*W1FmM(p6 zY}Ba>V>7Oz`s*-6Pp#h8E1y^4?s70>j`8J5w8AKo;46R)jF^g`ukjC6_|=CYk=y)B z&Pes?7uT2PH&&;X=F_GWQ!zL>Ca31JQ?;|0HLHh6VL9nZp`$X9UzyIQsa0+-b1)Ex z?A)h~qXN~==DD3{z$ZMidW<)?!*L08Klc~*i|v6QR*z<}HvQNXrl}gDtHF0U{Wd@P zMpI7^caNi}=kONP!UHH3Vk{zf2PcEg#%Z5L0k@j^dN4p#)jGn`1UKpWwqtmvrGxe{ zOS&+}E}GW**V^jVXr^|S$K5sU#2tEOa*HRa$Wju7Y;B@cyrDpQ&NjUxO`o)CIpO{C z9RqQaCJ5->z))sr1dTMS*P7Q7gN8~^Cx10y&hvfr)25$n0yMhd=)re<6hy=kw-EIyCaMO>t(B5Ab0N+-LMFNtuK_oA97yV45oMP@exSjjx~@FLv3FCwE3D=U zbYh;lvu_oUAxIPS;jXf#x%lN)=X&-&W+%WC~nETZ$Kyf_e7TIx@F^ zUWJe6pn&`YD8wOSoZY>0J1(+y98~23kIY`*B)NqSC_=)&ZXrj?>?);9nRVm}yh?R= z$P3Fpfx2=3s2piOYruF6<-p6P|LI~u6qn>XI|!$*SM)H0*Ppf-OVbWE&6c`xhwW64 zx-C3&0O4ML3?qmUhrCAkv4T+NTdJC*mekTc?aurD)O1J5?t9qx3+o!Kikw*iOoKwT zep|d9!)1CEW;(8@5Y}x;iu$Dp{BzrxV=`P6i_$YTmM|v+UY@+=TH;GcUFpGGX}4m>*?7KgCR5 zn-14^kC}NVGRDx?y=P4rs*7Qa4AW?RLr2F#A2Vy|PwJ&?j{{+td1XG_QMTKCY&s}E z8CGcG$gh+hS35o@cbvXJsNxQ6D!e>LHy+L1NdqKfKh&>tKhGT;y{?sn} zWZT=~Ot#|lj~4Mg>Y;-*mTDZ23L8CguEFB9mxPUbb(d?jF8NmH2qX&&r;ZUr?cDzrtH6{5CT<4w4*QInQ5kGFjd{IwB9 z#SP8zXagfVq$d;R7AG&FUcsKKCPCBhiczPcarC`S@pIfL@sA#<^rbX5MLtr=l8&q* zvH?O9 z4JmLVrNIPQU?Imsds#@V3LQ#7Zq{o?B%wcXtaf8QmtZnFY#s&&(**w_eT!H30n!Kj zHyna~1)v9&*nrf{SXf@Xx3{p;zEEUz6D26M8KzP=>+*~;US8sIo8ViDG&=!*GAaLQ z&t|#8*g|Ps_o?`$YLhsIaoG*CP%^{scMDvpv%7xb+Rm?VX`gSf&yk>LXGPfLaPZ1g zl`Au|tTxUO+-?3)y`@vIwj89`%70Bc|0mV09US#7E&qNrG*k8I2dW6#yG*)~5Lci= zA!bY2d|XkIEdj63v=4?5r=(`7t7SZ?cI#SXI)Jke=i>QW1tdP9Yq+Ek^*a08F8?O~ zHe@t=o5W0jTo*xY9rw+C$A!m@myM41`@x6}7)|#QC51rg=P$uH_(4lSScv@q&LYZO z-l7a~3X>9TS&iDFIU0jYwO8|66QUszI+{fiM|aMmt^qkl5)0Neq9o2hwB?(~P8 zA$OixiI48>L&54PwE74GTBF1d4jovG!+4Hheo%No*hS>zUIx3D4j81ea(cDSOj zwI<~7RV!#~OAnJ!Tf)9+d!Lewnx?2j8E8w+8H61P(VDi9^#+3+t&cX?+=d zC8Tl zJtG0#p>a5@`v7pNx+%Zl_&BkZAFjarV7V;byS0d~wq04&9sS+G-rv zClpwr=%u7>!cl61nHHSnfr}@GraoAR3x8J50X`M{E)4vtG%{F4bQ)WoY)EjgNIIrV zCSF!3$H+o)sO%fsw!(ZZ>fW}-v*BXkEzXPiivEXJne^DZiu_m%xoKebW5)J7E<%2!XF zcFC>EMmTQIDu;GoVoszH@Q|XBN-I<>T%abd%}!>)_@b{Ga&XBss!Yo2-wWVPfqXkm8%1Zm>zB+X!q56`=*bBzg#?$!OtSOim zrIM7Y-_7ONAkk)0sTR;llSa|W=cQUmtrKkZ3HoV?k>!KXBCXW~<>l3Apt8*{6Y7

UR&j$T(w{wl#mTmyvu9DhRlM(x8jjp@#c;@FjGx;4_86 z(t=sRXvwy4plMIbw~(o)iiP~N*aF3s0<~8NZNguhs>|C*jFt;M+Y3hWbZD#hjhvYQ zES#xIaecQa=7?D9!Nqxkw*z32d#SNp+8zZE^Z2E&^nKSbk5A5*gMYY}Mr$Zsq1IH!GN z?NF*WR_|Mhd85}U?r=Rw2fjz1*6f(dbr8G4C}1yS37kdEKym0gnXxF*<%wZS$r!o? zn2b!Tu|{y-nbpIgMkxlwlVt`rjuz2)LKGoCr}_7yL*vB_(LKx=$k-=>E$B?n>cNJF2lei>5+;mDDkksDJYCzHPvk zy_Z3wZ{-zkBe!)*QE!(J>&j#B3nTy-v%wrD<}UN{Y$fVoj4fMml~FDBt4zLKEoYy> z%4HHtB(ZngR6Tb+;^W8P8W_w!`NZrj9ao&!@?GN%yy^!oFb03l0oEAO2dW zq7nH_U5!eOEJWZG-C@wMg((kxvbcm~o%oRle}H7-P@Oe40D)29-2#uJ4#QsO zzu1Q$f8hQ(eM#Q3!L1%%XSxm|8#P+Hz7Ah^GF_~iwD%`iTQbdKh&=a_XapgkBCN)V z0}w$^>S4+l#@H-=72kmYoOp~} z50D~tzTW&xn?;L?gVQr8Ev<<7-@FLI|KLUZ^K%H|gEs2`+NzhB=uU7%&OYp=UR$A04)(E@!t(VUc$73B)c;Wlh1S^bPG)cU+p zXp&`~2UiUJ@k(uZpT`^%pP%tLt;X=G6=U3-f@}>Al_*1|wS>4)PbNHFLTqkYsZM$n zi0jLrb$Z@NF)PiUhQYg-(+8W*@#*GsT`O%HBl22S16rVXKNp1@Qw?cqJ$ShG7%z~{ zko+?v!5#!gidqOv_w36H0MFy6Ozmwpj#S^N@<-YJyfX+Ya8|lJwzG=})9D(or0wO! zC9}dA9O6)@{)cZ_+!%ddXG>Vkv9Qs{#=;w^scG11K1*Tw%?Hf-aj}m`w`Z_jsFNib z2I|@C_MMwa7yr}|rFR>1*lB37MS!IH{Qu zF4rIv57VyUyIborA?xeAWc?w5lwK_osGYv)Q_h)DT4~F4Z#5fgvs`kXQV+EvZ8?BI zrXoD>GiQp`jCItJ3^g-VX;^a6$%3Nj<5p15<{+7wzpt~e`XGr92!zH;$PhlCDulOr zu&bYpP9Q)npS&paxHN@Vt|?ZK!C@ZQ`jh3x3kAO7XWStObwev>0l6#lgYglXG<`xL z=TvfygoTK^|DjJI?lxi`4ljfO+5NVHz!8N&w~=phQ;A^2TKN}NYFc*yNld{Rlh;%T z;0X?al0)7E{#Fc6xg9;+xr!}D-wdm&?^s$jIT5Bu)D7vGQE$^8)n)*l2JxwM z40>f6lVwQ8y87Of65JSltPHHNUF?LT!>?=79%`{V?S`p-6ubG!Ea|nU-I;NFjjM^?I13}y{lUBSkM%Ip%F}?sPN=0LVN>ofa zIV2(EXnp5>Gh|s)Q$l6+nJU?x#@j282yG5?4&{V%D`6sS1FG+tpss)iw5tL&_p|S1 zCDLx=eTYi8?q8=$hC>KaA8XQ7aiuQwf=HidKD;CVgv4mJW-a^A4yaCk5OLh}tudi{ z_>O6K>p4)Bmfasq)8IEKe0T}lE3GSL$AaHvPcYoO-ZKx}NPEn@o>g);2av={GYD-D zD+};MC(mBf*HI{+I$t1X4g5%d{G>x+^hfA51~#khlm0ndYYRll&{J*Q}8`x(1v#USn>fVE|1{xa#JP&R`p5E9E99=;t6?Rv)QdEqST%BG|=>1C}T%8}Z;fi|}5GcmO091!k+V$x~2uW^6b$JWN2WTqihoSylyL@7;y zbZ*JSsqWL0AGi$_Ax>DK$}ya}GL`OjEU4S#B@A+a8P5WZ$jLWtjaOzm!~>nb*OKGJ(|p`^gM#K-nKS*gEL6 za+YD)aV4-6ifDmhWy)3|A)4x=h!)jo;?7+$s}d+6X^@DBNU1$f5iok@=1ap?UIq3raVO=ll1ysSoiu`sx=o_pl_u_w=JEI)KLP2ua#& z&;U%qsX`XD!x+3hvCWTQ8Q1F-01})d++-kfy1LeC{6@z_%J*z(n}(&>aVd7u-;ULo z_Bh;ug0NK$)0w3y`629Oh@r(%{AgrRk?`%lol~2z(di!NYT=a%`{!fkfK+04;+$9Y zjJ5BFgegXx9*|L(_91q)9_@x+kEIAD#?VLIt%m!2KdJsfNZP~`zNj!#3 z?eC2NwaIvppT6y6S$Wz!T$Ql+CTvB<}M9keI`NrTqm!F zrf61zcNj{2=eOiP_!Rzy9-}_vmhlMZrM0X7o?a!H^thJg*DOjy0(W&3-5yM$%-SHc zMj2+N$92TDGTDU1Qm9+zCS)#8RUKMYTKrZ6wQRcoxrt+cgk>{6Tq6~G;2$3^V<(bP}q%s0w zZR0ur6!oFvqeNCjgC*pSp1t-g1pcZUaV%gdM?Ce|LE4_D2BFP?xN%ak7SV;zZ_~~s ziQD+NGI4&&7M_G1$(AtBL>4jRfbQqAGJ%TK!4XXjYJx5%K9+e8p>=_Z@`qAQsgCT8 z6TvrqOYcgyIR6{)I%+4wexyp=9Etcvl zwYqHtqO=riPblbCIU=I&%ZP+Ed8ylHine3FbySUNIzpPv1$g=&YHZQocpL0a%n@Z5 zM@Rw@Biq$@Lpt5f&6*JPbvw4ykttvUUZU3``)3$Xu9Lx&wB68N@A`AM1=@Q($jJgD zO2Z+q&hdzZyjqJgK~FJ{e++SbKj@!SkHD^IcU%92u{caNPu~F!@{T zeVk^yaZGgb9W=52i!y$z&5qK2=!((`{GMEQo5t?6WU4>qtOlq$)5`9ZHCP@NFFF|r)8<)!)|Aam4Ig2UNJxP&oFsM zY}4`&96S}FLHmY0g;18N&-FM57;e)z&(qj*qP|6K7`7H^3rMvw>)_ud=yO5rsX%xl z=y?dQ-tmb(x)O9+_i$k8)x_!|$a~<6fLRUde}o#}x^a6{8}~;~De~7yZDA}1pz}E($k)R2sdYM=ko{ zinLDLySSvId>v2pVwqo$u=C{np5I)%rg$yIRlmF7NZ#?=UN$ zcQ6x#ovQkU4XHO5q<6XV11qF=>^_U&YHzgyFEyUC4EjzYN_>=fC=$ixU?YtV0a!^1 z53fz=Q7EiJg(N_TT#l7o(FF&~HO|+_jCFUY;v*+xHUe^Ef`bMo>~a_t`b6dd`YKVW z!VFol`h5OK596XvenNe682TPZor{9(^E_q#A$RBKtQxprx#$T!)~lvZ*@i$olL&9$ z8aDz{f~^RmD9=!0#7nD?1xUuh9|ZbyoI$~tJorE5`>+ zDQoW5(;$i^52buXJgO8L!UGd{a3mFq{p~<(x|Uy`5&e*;%ynR14zWjz!&`2mTIZfA zU%J!eey;#=iBwcF?85Dt)eFf(MId3Pt5e|Cn&#=h|0AyS7ES-atPy*H0shyJOQQkp$BJTu{3J<|HH$>j<7ApNMm*l%cU2m`3wpsF7Rzm3 z5i8jvcBD_w0p}kGW1lqEtNK0ecrChAL~$>Pqu$UIuN(~S>D3Z-a<05Xn>JPZPQMHt zx$NGd#JQ$s=op0lz*60O*nNP+?V{ejhy40X-37Pv0hHaZ}~Nv2!Wf3H{RDbgt! zEi3Y?BED+sv|fFDk$q$#6WgVZCztr0ERBzwKICK<=bGe7wdL!_9Vcnlf~6SXf}H6f zIPs}wq-VhivNxL%eF}nXN7!~AGBAjqJ&?2#aG;cw;D8;y za&M;Ha#W+-d@-h>>e3snSZSfeSvoFQR7W4Kxa=t26ELds{Oj^JJMe9T5%yhA_Jzvo zWsC58KtP~+MA8FDp&eiP!@i$X^%T< z5>TL!#70%Fws)|Pqx(z8pa_E~BlGKqlQ6@s`T$mtrz|V()3N0KM)E<%=gJ*i){$bl zrObxZ%ot<9Ho+jGc1ZCr&TWFBXuNHA$l8}y5r^XOk8%9PiTvg0PcOpW$3WBJt@zy= z=BF0J{jvHezkaZ>Q7d2pab-qrq&DFIZx&7J6U$oZDn(1$V z=k1kUnN%v?l)vnmgPL!$x-c`IEO_79uk$LAMJz{EM{GE2B_?{`|8g3!Q%vJH01XUG zm-@eDGztEFMpN3x^nZF!0^?6)PzBHi-e+Jfq|7M6X_CST%{3EfH#>lREJQ@5$pr;u zo;XQEwasf*O`4Ha+lnRf(l48z9_4_{brzHf@C45L8EX!2Ada@tx2NY5b|1XinGm8% zqF4bGRJa-Pmrn~;=PAF_dr|ct;ZP@N2d;G)`bH9+VHRShW5)GRu!6uBn4M;J#2P30 z-P>2tv(_B}imq@&>s=@b69@`}AaE!ye;$)@Mvd&>orf{?+&P0SMZXPNerrzHza(8i zujj&;G8XIe`JYfQq0xovPqt3i;h|8ni`{y;Tg_8jQQ8yxqhOR0sTVu+OBQDd@ED&*Mke?dCHm1%-co} zjs?j7&Q)f#R;EvsG|G)q}v z*l8TZf|_^)k&X9CzbnasCy*+aB3Q}^=d=)*@0V@ldWrtVDPoh6kLkHW-a=uaiR<9` znt=mzV2k)5VXJ6dLz7B+NR*3*a{WP{iIAqf+`FYqjTDG&_A{E{T1XV1)iRUOKCA|h z$?}+6z=KFnS^~H|O_>CwG|p2Jw-S;s6IhN>fTEmU?*61K^Z{`w?4A4o{Yl=@rBHDd z_u#nir@YGw@)|EN{$`C=+4T98;E(EdE)OG_Bj`9S%YQ|f{1dPI-y5pr^c}woI5-$v z8CV+IlStbb>RSqfn#%0W44fRzZ2oq*Hc&xR3P%7$>Pgm0roCe_w@z>FB|d+g)M!Hq zE)NqpiJ@`5xk7>!7kXlyvZnT;3Imag_y+bv=_pkqrU=F@mGfZKh10>r`t79?;u60~ z%2v)+{jEJQT> zUWrz}NG(|prf`gDa(DAiLEuY%{7A)L!$hXTI~yQtXuJ9i%>8}(SK)>@h%`_1F;kay?+^xOMgsVp-ptkNd`h_u{L$xpMr0yTv zqom^OdkYA(Q18D2Q~n9{|KDzpzt(LMRm}`>=FoX3l6Y&GWN?wm`xbLZAdH3@)2izu ziGDWqeH@YL@I?*5l0bDsF%un)Tcp*VW&>{(()^D^6)W^6*w<{m_Xel|=mI zcXvL!%{lMG>K*U<&c?+XUYF3L=4Y$#sz?e`zB0a9)XS{2%Cn<_=6oI^6D=Pzqp^y% zvXH+=BmQ(Gil75WMt{zM>7!|jp<2}FEGe#B(P*hyDZNQ+<2&bYr_`La@_l_fFcxbv zt%#GsshbYcFC51f@uKm2<;ckq>lY9P$G7x-OnB!uOHGdSGqtGHPyGl9)5>kkQE6qw z`=gkgZ`UxrHC;nT9Mu^!Sm}1Vx~ub>r;H)Wz|L5lZ=R!PEa8}+Qm1CW{B10)CcXN? z?Gd~xJD%Bz?_(ymhtF*}W>-gFS0hcH-ZR|3CfKO=w*yUe1te5Cm!KqK53PP^IGEK2 zYBkg}AzXz1hnyFmFi7MtAu-tDC?}$$8qMvQ(%{g(#BGISJozaLXHY?t;{~Eh5shE_ z6MF>-6zoty$^f-nV&G& zR8r0jsqjsa5P;zMqgR_}(WQ@%QC4JCdV-s?&v$*B6^S!p+<4J?xQe6Z8hSkIWiV-A zK#i+)Z^Q9}%M!oTGkYlWjGNy9VdO1Y=-WK`oG1E5B~{Fd(ZUSTH!ys;1|PydK8TBm zO}I5~Sr;+2?tBL?^Yc4z_NFcb49tzZ-Fzk+$S(|=7t{b#Kp;+Rxn{7y&@4|vyQMyJKlKV zu+d)QlT=3sq(>ruD)t!$so$@r5a)^!H-|CZxakm1nG>=&C(T=(v?e8DA^3kJ7Uhh} z3bSaI;iNQ2ASJD`8Pzor)7T{$yH2O#3zda-s) zdqxqJIP%GsayK#Xv2u4bwsUk;voU97OYIW=;Z@R7I&D*lK6zgsgcD4rZ zpjFwR;#sfG)G+7}-=%Ez@!XV|X|r=eR!z<>pA9c>PYb%AXMDSr5%;ym9$fu!9;R~p zs052!Y7t2Gljn>eg;m;XoZ8sQBeZV7cJ+-q&Fa#l8q0nGK5X{t;lj(;|7s17zIxu? z{M63*<^59_-Z(44FIs&K?1DZM%G zOtK9AzR5fLI;JOZ*-=NUk@T6nX{6I*YR+DjS;LJRvZ#PGBuE^xAnDBD6)2MknSxS@2wsuvWz^#~Cj0?gYiz@e*G^kAxbMZ3 zCXV&wGYvDbDp5qIZS>Gc6u>S)}H+KVs zLW{n}x|%2fw_s~T#~4?!l{J$~yV^9I9W`hBjuE6{AwIogi(YytbjyLACx#w9dl@@} zw^C~es5MP9+B0v?ooxxcn(Ld2%Fkq#RyjVum7n$DXkiNYB)$n1m(s_;#_&};{Yqj% zyDc<(+jLjqi%!=BOdWxT zE(`*2ZRH%ALhhAYp|ak6LIaltXvCQG7mE<37mnmE~azIRRH z(X3+mbxn-PME+6^y+&s}7<4~_LZ%#8cikb%o3(~4w~o#0g;Q(S;|B*Q_8_)c4cKKS zpd}wk+!;i4i;v>mRIWYL=8gEhBR2*mdHpuFT?#z>=6?+k6tL$z-RGBx-)osG4XFp7 z)?Y<(>v;vTwA><)<~yUG@4VXN5vxlyKB(5n$FB8cQ2rqh5szlU0<;k?)g>ODZ1F_{qb9|evw6a#sgzX5}(dq3qKls#JZ{?@<7 zR4X_@>Gw|kS}PclwI2Jklgpp4-M`GTO=s4Kv~*T$v{2jr$nWt>9!ydyf_B#@t|}Bb zNNXyr4*C8s)1Losm_umt!!d^c3ZXO(hvdR$iuUlsZ3bzFe6O z9@YtOqZFD)hKa9CttmQfD>iG(qS-BNfY9W=hTm#i4lxymQ%4s35`6jc$A90W@NaBX zAnbfiP|N>+MrmaD_tC|lp`pd~twC*le`|G*R9R6(RmFVAi?1fC&=QFR;nNLg%AwbM zHtYD73!jVvV?gf=ZBdKlJhK-0&F22?P_dZ#KGz11d*&#@D^w`8bY|gAV!re>6X5gt z^19k%+7^oB)YVr8-fDW=5i zxB7AU3URY2HYUzlElg%2nHTa0e~wC6j!s?5NVm1p)`ZUe5M0kgq22PF_oECtk`j6)FJBu{FWh1I!VX2 zFa$>?GYz)#^oZOxOd)8u3a{vrW*un-N2#zZ?WDjozJXfR{&EgtB*&kAafRk97J{eH z8S#OKsE3OKzfgvxmm5_Y0?%OX%A0)_FgI#DvnI9G2e&`2JLgcS1Y$yaYd``Ai??y*g-E*$kfJK&@PGiokYC+-7+Xh6~FQlNIBDAD% zxM{efw~zVIa-##5mJLLsE0=4fompzmn|}|F>)_8xmz@y;!OJqNjAfzXQxqsZOqZ>TDFczq?wn>NunaaMr$ zv<9?%a#uvwlU$_C9=|zpiYUtbg22Hg(8DK3j(feo(c!cB!amz}AaS20rpS)MMQ@~} zWo2wzxEh^e2YP(koK~fYe_~owr;X32exsiM8l2Xwe~j9a2)>pTt0}9YDM8Czz7+IA z2lHyZZ2P%&n_fq*a;Zz{Y#xT?!dmRAwxVyhkrnn#j1c#Sq(8CrWDW3<&ntwBU;-|b zg*#Dm3edzuxpGv#Zblv0sHuI9?P7#nb3RvY5?!8aDPa^WHOq}WP>@Gce6sYj{XP*D zfv=7qjZ~;M4O&%-Zl-5P{&G%5h|Y#&bp@K(*xY)2-}7-P^v71e5Hz(Z`JEszElc4I z-)wmO0VDlG*E2YK>~_lj!iT;mD7VyWD>;-s3JwS^{BJK?0!fdRmjU`TH$O4J2K53B zNu||hMNQ{m{1qB6oL$DBDTYJYdL81--?bE+k+IR`(v5wRnUY-F53-{Rj#sfUw zag$yZS-2mN#$SN=xCLg)pI^g_d#QAx*ybDUnbP)Plz+qL`CWk8{m>QBy@N5r8!jhx zYjCsJF63ed>iYa=Zhh1e+|9mOH|26e9;#Knc|T{=>kIZbZX17u(Oeuh)~3`sZlkx@ zFLPDGuR(nDvH36XW&$8^&=kJDN#Xk5CA>Gp<_dYAjf2=;+TYy;2Iv;J{*T}%j{zc3 zJCL4X6Dcnf;l`AQotvj@q^3xo5nSNQs0z>MN_J&ADqBAS>{Uj-b=p0V|Ct{Y`h}=@wK!O=vJ5nb%lEVR}kO-(DeMbo=_nhYZEh5Cwu*W#IKR@ z8-HYGfWLgF1=ZiwC=v{ikqWc}V4z?`;yx-fD#M|Rw-afqjl|WGwrK)9sQ@HoI*(v{ z30I@%Xv_L(uFR(UqfebrW2tNWKYqMIRQrula7|(fhzot`f%E?YG$qz#J(YC+<*A?L z4z~puX>6wr8h6~M@UspYN>dzC!QH7aH~GZ@oJ%}1+Q3Yk}EC*qhO_#}UHK`W&xZ${l1nXKBw>r!`SC?9{o+rWH@5 z(hg2Lm8Cr-f@CO8CH-Kzz+5(G4aa=T8n-&VCrpej$|*BK^up%pAT1PUBigB<`l6TB zRz);7$a;+bJ*5xLf8MfZk^s~Po6O6zIC3={jBV1)wXUVk#h#?PAbBShG%0fyan3GR zZ+WBrT5HKg0B275%kFHp1RpD^f8i_E^*C)Zk>bmQ&i-JFfqNTmg8z{;H92~V{Zxme z1zLOSg<3 zopWEFQaN|=zEt>wxAfemh&PV(l#t8hJ9<%UCv2M2rOkSD{@3x46g0-Y0X~K|;%N@4 za>HTfFv?f*6#SDG(JFkLR?*dL@|UMa7u~lIAadNtUZ^RWV*(b@I+A^ga&S=)xpu6; zKsyJCRP2S*5kJG#8IXqNbJKPu&Xpkz)D?#EGyB{@6{B4^%3YmeLFzr8s4)LWNWLAf zElB#`U`*mwa7^W&-TX+=L3eRPk?Rlv{BZoP>d+|30vHK|)aEhGaJ9l|du)XHA9qVp zj5HwBmHjHp1d5DfoTe@7KcpfPT1dtOz+DSMUrWQs#Ryy%ELnewLnE9>B-~*V7l5v< zguqG`xEH@Ef)|(cv3yKh{mX$%t(gMOW>9vAALK;*X9t4f-#ZY0dnH6%jSZa~ZT{{! z{L#TMfc_pu>t~+*;r1YMT0?V1~H=Q?87aq*d$3Jx6 zFnqKhqXS@qXj>U)_zWqo0+zjjatf4l-}%jXJ@)6+fV1$>_z+J4_8MjjxA(mof_J%L zxrNdr*yq*3R+K`;!KI~U{8U@<^6>mZb026+Qz5Y$8*e$0xhv!aCC2N;076pZj`dLz zF9Y39SK(+ z9^$V^KAUnhK(m@uk|OjuXsWGKUkb>Bb}J#p1(-xW2#SN@_FOopFo1?NOZ z!GnM!N1Pk@)y0C&@np!%ip-FL2h5u#zbH)*KMA=Tp_ZAf2utJn94XJgylJEvvdZxC zi{W7PJg=_jD;-u_O>k~ebCzk!=R&Ll%Vt%eR|Y&Qw00={GXvIxolOCVy^EIpE0^SZ`UqITve)D{W!9=78tn*Mw$6<>WXO z&S4@fUXD>YZpE;kgU}P&N-QIeulZjPnJNfbS5m=)p0%!z;`G@EO>Tz{4+=^E^i6%i z-AvEHXbwph9TLFm^w*~+WUPGa63_ME{5}D4b4Qh>7E>D*<^kmaV`14hwR0LYCiH&?jTzmd;P}Hd}0uxy{JeEQ+QXr844efYYFtOwH1`w>t|*%;Y{P# zMtZjG$<0QT5d>xk@zc*67vTQZqUp}T#ISO?#Xp9KwdRcv34iNZ!sFSQ4ukWOsn26u z2a~yhuni(|d@hL`#r}K=EUaz`7trV|KI%=ISybv-dWA0Q zfSOLCrKfhl(!riOoDxt#B|Ld>$%A+Y+g}vp5+mjau9I-3?-|hDdn5WnO=sT~(m>EV zKcpcz1w$a zYO8Z7cdI)$Yb(|+sLP%^WN4RHJ&k4HaU5+1#iw%od-SJVNBa_o-4MgtP9rAw0*5&F z2_wh)Y$&!VZWb&&EZlQSF~`w_?zw4g-^byL55X+{Z%+PEA!~aq?Esyd2j1)HnV$ng zEy`XR3V4H~fKnjT1uPGlyR<|EWe{+nF(!NCzH=92N&gc;)M~fFehR|`&Y6+M4=!X+$jKUq zT+9NNK0C$EBrOu42UNQ@6-6*ut@5@yqT(D%m0-g^a#c7A*>>s_1D&Jpf4J(Mcs# zutSx-lxFeSc^@esCX?WtN}9BHuP(?H2B3WFa<6J)3;a)g3)oZkK9VaI1U~i_C&RWar>u+hm zjx>&hx7nfcle9In@>MTXi{!OUfco!=j>_wQTXx3<2f!^#b2ovHn_kTV9))~wINRS3 zQN|;~7fc-<^*HN(4+VUfH5lx!7;A)Pt24**`2BQ{(Q$CYGQ_*o9B=@n{77(&C|27n z{wrF?4@BMN5)z;?qvI6l#g5GCiyRjf`-0gWIdjTbQEW==wco=Eu5HSB!FidFQuf2WzFrlpSmUqTs3Tt89NG>~h80&4lu?L4Z4Pf9MRw8D z0I!6&2A6zfg_109r&ugo5Og9RT|gzBP9E2eHf>-v!Xvr{g`twe9cOPo{f zkoxqnS6AfAo;c#NcrbM7v|v~>QEC(ko!GX`kNhSW->2%xCzQzcyrhtBB@WrM2NqZB zoU-mZ%$5%}Ms_ye`{=d;$RL<{Ed>L}^08hLv*^*h|J$YlA@E_WK*F z4jMXHuCE|Uox-Wcz%5;a*I(~{2~R#8LSM6iLK9q2x%eNx7#NrU$ou-o0QJ{`8913) z8qwMt8ycJ0I?~zN+kn7o9LpmhfAp1X)AiKRfg{Hq@7pk4W=h5kvbfW4`c6^LF2gxzUu`;Vaf&wBXg zzPsRn#G8V|Q~rw{Zy?S7v-tnTJOV_P?iiqkHB(Rm_KzaxKZY#`S?xcI{b#DuKR@aL z{s>dhZTIS+BJCc?n*aJkPJ_M*|Ep91 z6VMhBHM4hcRCF@SU}L&#Ks{Ed1!y(Ve_81Z=!5mY+Du5_ z!C1oD!Pwft%n<}Cs|Y&xU~LMrovl77ef0Nu`OoIF-@o9&2AQrK84Qf~U)EeD`ai5G zWo_eP{a5q-bw7Zp{Tz+|y&;QZ+mNe4>fM4i@V^>TAM}d+uj&EJ{$FL+^9pek#J?&2 z00$QbnqX5O3cd(%uj4in0gfg5@-UFDLKC%|+KOmtESXzXibDo{*? zW244Nl@8PdZh-0ls2Yg=HtT#-nHFg)wcoc3yU8{PgS_zFG2CCmTR=qNsZf2&RF6F3St3&gZiDGwWb>uhRmmQ*b3v5t3KvPHUtx>dFpB zX5Rom3a%4G=$6$2Gc)4%jz|CDIJb5%6N0@s25wSK$X1)oWb#_zHrN!iy~lz1qmB`D z3d)$cJFse?t!1v?jG6a385#GZRo#WPoQIsq{(BAc-4ORgRo!j1>G;fB3T?JG=G^(EE>lB0o4P7mb47u-hP#<0C(b}k!@8(9NTX(9k)mTw^f6E1WDPL zHz34yVmm)RWL$+F4lN`bQBMZh*l7-DV#XBD|?gJSV^v zNvUys%!>qVt_5~EG%mYTi}Y++PYWKWhI;(c&M-g#cN)X z@n~Hnj)&8#17v(l>t1-Wf#Doi`Xw4V6wz>EHXj4tp(Q=j+G5Ll|GD!G{@lzA^g4~6OUNBPO#g#+jn-luQ^m*w8O<%4ss=9T- fmnQ1gMa$y7`yEVIM{$YzrwzYBh~cyFU(5OihdU)S literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index fe84e3b..221c4f9 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Mon Apr 27 22:52:06 ACST 2026 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index adff685..17a9170 100755 --- a/gradlew +++ b/gradlew @@ -1,128 +1,78 @@ -#!/bin/sh - -# -# Copyright © 2015 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://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. -# -# SPDX-License-Identifier: Apache-2.0 -# +#!/usr/bin/env sh ############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# +## +## Gradle start up script for UN*X +## ############################################################################## # Attempt to set APP_HOME - # Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum +MAX_FD="maximum" warn () { echo "$*" -} >&2 +} die () { echo echo "$*" echo exit 1 -} >&2 +} # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; esac - +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java + JAVACMD="$JAVA_HOME/jre/sh/java" else - JAVACMD=$JAVA_HOME/bin/java + JAVACMD="$JAVA_HOME/bin/java" fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -131,118 +81,96 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." - fi fi # Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac fi +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, -# and any embedded shellness will be escaped. -# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be -# treated as '${Hostname}' itself on the command line. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" +# Collect all arguments for the java command, following the shell quoting and substitution rules +if $JAVACMD --add-opens java.base/java.lang=ALL-UNNAMED -version ; then + DEFAULT_JVM_OPTS="--add-opens java.base/java.lang=ALL-UNNAMED $DEFAULT_JVM_OPTS" fi -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index e509b2d..e95643d 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,22 +1,4 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem -@rem SPDX-License-Identifier: Apache-2.0 -@rem - -@if "%DEBUG%"=="" @echo off +@if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -27,29 +9,25 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused +if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" +set DEFAULT_JVM_OPTS= @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute +if "%ERRORLEVEL%" == "0" goto init -echo. 1>&2 -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. goto fail @@ -57,35 +35,48 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto execute +if exist "%JAVA_EXE%" goto init -echo. 1>&2 -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. goto fail +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + :execute @rem Setup the command line - +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% :end @rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd +if "%ERRORLEVEL%"=="0" goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 :mainEnd if "%OS%"=="Windows_NT" endlocal