From 0a3ecc6638fbfaf085ad12b089f0f37cb3b0ac2f Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Thu, 6 Aug 2026 16:26:12 +0000 Subject: [PATCH 1/8] feature: upgrade to Java 21 and Spring Boot 3.5.16 - pom: spring-boot-starter-parent 2.0.2.RELEASE -> 3.5.16, java.version 1.8 -> 21 - pom: packaging pom -> jar so an executable jar is actually produced - pom: drop spring-boot-properties-migrator (a 1.x -> 2.0 aid), add spring-boot-starter-test - maven wrapper 3.3.9 -> 3.9.9 - remove the unmaintained Gradle build (Gradle 4.6 cannot run on JDK 21) - bug: tolerate the unreachable demo quote service instead of failing startup - move the RestTemplate bean out of Application to avoid a self-injection cycle - replace the deprecated JdbcTemplate.query(String, Object[], RowMapper) overload - stop tracking target/ and .idea/ (both already declared in .gitignore) Co-Authored-By: alex.vyshetsky --- .gitignore | 3 +- .idea/.name | 1 - .idea/compiler.xml | 8 - .idea/encodings.xml | 7 - ...__ch_qos_logback_logback_classic_1_2_3.xml | 13 - ...ven__ch_qos_logback_logback_core_1_2_3.xml | 13 - .../Maven__com_fasterxml_classmate_1_3_4.xml | 13 - ...jackson_core_jackson_annotations_2_9_0.xml | 13 - ...terxml_jackson_core_jackson_core_2_9_5.xml | 13 - ...ml_jackson_core_jackson_databind_2_9_5.xml | 13 - ...n_datatype_jackson_datatype_jdk8_2_9_5.xml | 13 - ...datatype_jackson_datatype_jsr310_2_9_5.xml | 13 - ...e_jackson_module_parameter_names_2_9_5.xml | 13 - .../Maven__com_h2database_h2_1_4_197.xml | 13 - .../Maven__com_zaxxer_HikariCP_2_7_9.xml | 13 - ..._annotation_javax_annotation_api_1_3_2.xml | 13 - ..._validation_validation_api_2_0_1_Final.xml | 13 - ..._apache_logging_log4j_log4j_api_2_10_0.xml | 13 - ...he_logging_log4j_log4j_to_slf4j_2_10_0.xml | 13 - ..._tomcat_embed_tomcat_embed_core_8_5_31.xml | 13 - ...he_tomcat_embed_tomcat_embed_el_8_5_31.xml | 13 - ...at_embed_tomcat_embed_websocket_8_5_31.xml | 13 - ...idator_hibernate_validator_6_0_9_Final.xml | 13 - ...boss_logging_jboss_logging_3_3_2_Final.xml | 13 - .../Maven__org_slf4j_jul_to_slf4j_1_7_25.xml | 13 - .../Maven__org_slf4j_slf4j_api_1_7_25.xml | 13 - ...amework_boot_spring_boot_2_0_2_RELEASE.xml | 13 - ...pring_boot_autoconfigure_2_0_2_RELEASE.xml | 13 - ...boot_spring_boot_starter_2_0_2_RELEASE.xml | 13 - ...spring_boot_starter_jdbc_2_0_2_RELEASE.xml | 13 - ...spring_boot_starter_json_2_0_2_RELEASE.xml | 13 - ...ing_boot_starter_logging_2_0_2_RELEASE.xml | 13 - ...ring_boot_starter_tomcat_2_0_2_RELEASE.xml | 13 - ..._spring_boot_starter_web_2_0_2_RELEASE.xml | 13 - ...ringframework_spring_aop_5_0_6_RELEASE.xml | 13 - ...ngframework_spring_beans_5_0_6_RELEASE.xml | 13 - ...framework_spring_context_5_0_6_RELEASE.xml | 13 - ...ingframework_spring_core_5_0_6_RELEASE.xml | 13 - ...mework_spring_expression_5_0_6_RELEASE.xml | 13 - ...ringframework_spring_jcl_5_0_6_RELEASE.xml | 13 - ...ingframework_spring_jdbc_5_0_6_RELEASE.xml | 13 - ...pringframework_spring_tx_5_0_6_RELEASE.xml | 13 - ...ringframework_spring_web_5_0_6_RELEASE.xml | 13 - ...gframework_spring_webmvc_5_0_6_RELEASE.xml | 13 - .../Maven__org_yaml_snakeyaml_1_19.xml | 13 - .idea/misc.xml | 18 - .idea/modules.xml | 8 - .idea/uiDesigner.xml | 124 --- .idea/workspace.xml | 943 ------------------ .mvn/wrapper/maven-wrapper.jar | Bin 49502 -> 0 bytes .mvn/wrapper/maven-wrapper.properties | 4 +- build.gradle | 32 - gradle/wrapper/gradle-wrapper.jar | Bin 53556 -> 0 bytes gradle/wrapper/gradle-wrapper.properties | 6 - gradlew | 164 --- gradlew.bat | 90 -- gs-spring-boot.iml | 58 -- mvnw | 406 ++++---- mvnw.cmd | 334 ++++--- pom.xml | 16 +- src/main/java/hello/Application.java | 51 +- .../java/hello/config/RestTemplateConfig.java | 15 + target/classes/hello/Application.class | Bin 6460 -> 0 bytes .../hello/controller/GreetingController.class | Bin 1219 -> 0 bytes .../hello/controller/HelloController.class | Bin 4496 -> 0 bytes .../hello/controller/TopicController.class | Bin 2344 -> 0 bytes .../hello/declaration/CustomPredicate.class | Bin 248 -> 0 bytes .../hello/declaration/TimeClient.class | Bin 1383 -> 0 bytes target/classes/hello/model/Customer.class | Bin 1407 -> 0 bytes target/classes/hello/model/Greeting.class | Bin 588 -> 0 bytes target/classes/hello/model/Quote.class | Bin 1128 -> 0 bytes .../hello/model/SimpleTimeClient.class | Bin 1720 -> 0 bytes target/classes/hello/model/Topic.class | Bin 1121 -> 0 bytes target/classes/hello/model/Value.class | Bin 1111 -> 0 bytes .../classes/hello/service/TopicService.class | Bin 13054 -> 0 bytes target/classes/public/index.html | 10 - 76 files changed, 477 insertions(+), 2354 deletions(-) delete mode 100644 .idea/.name delete mode 100644 .idea/compiler.xml delete mode 100644 .idea/encodings.xml delete mode 100644 .idea/libraries/Maven__ch_qos_logback_logback_classic_1_2_3.xml delete mode 100644 .idea/libraries/Maven__ch_qos_logback_logback_core_1_2_3.xml delete mode 100644 .idea/libraries/Maven__com_fasterxml_classmate_1_3_4.xml delete mode 100644 .idea/libraries/Maven__com_fasterxml_jackson_core_jackson_annotations_2_9_0.xml delete mode 100644 .idea/libraries/Maven__com_fasterxml_jackson_core_jackson_core_2_9_5.xml delete mode 100644 .idea/libraries/Maven__com_fasterxml_jackson_core_jackson_databind_2_9_5.xml delete mode 100644 .idea/libraries/Maven__com_fasterxml_jackson_datatype_jackson_datatype_jdk8_2_9_5.xml delete mode 100644 .idea/libraries/Maven__com_fasterxml_jackson_datatype_jackson_datatype_jsr310_2_9_5.xml delete mode 100644 .idea/libraries/Maven__com_fasterxml_jackson_module_jackson_module_parameter_names_2_9_5.xml delete mode 100644 .idea/libraries/Maven__com_h2database_h2_1_4_197.xml delete mode 100644 .idea/libraries/Maven__com_zaxxer_HikariCP_2_7_9.xml delete mode 100644 .idea/libraries/Maven__javax_annotation_javax_annotation_api_1_3_2.xml delete mode 100644 .idea/libraries/Maven__javax_validation_validation_api_2_0_1_Final.xml delete mode 100644 .idea/libraries/Maven__org_apache_logging_log4j_log4j_api_2_10_0.xml delete mode 100644 .idea/libraries/Maven__org_apache_logging_log4j_log4j_to_slf4j_2_10_0.xml delete mode 100644 .idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_core_8_5_31.xml delete mode 100644 .idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_el_8_5_31.xml delete mode 100644 .idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_websocket_8_5_31.xml delete mode 100644 .idea/libraries/Maven__org_hibernate_validator_hibernate_validator_6_0_9_Final.xml delete mode 100644 .idea/libraries/Maven__org_jboss_logging_jboss_logging_3_3_2_Final.xml delete mode 100644 .idea/libraries/Maven__org_slf4j_jul_to_slf4j_1_7_25.xml delete mode 100644 .idea/libraries/Maven__org_slf4j_slf4j_api_1_7_25.xml delete mode 100644 .idea/libraries/Maven__org_springframework_boot_spring_boot_2_0_2_RELEASE.xml delete mode 100644 .idea/libraries/Maven__org_springframework_boot_spring_boot_autoconfigure_2_0_2_RELEASE.xml delete mode 100644 .idea/libraries/Maven__org_springframework_boot_spring_boot_starter_2_0_2_RELEASE.xml delete mode 100644 .idea/libraries/Maven__org_springframework_boot_spring_boot_starter_jdbc_2_0_2_RELEASE.xml delete mode 100644 .idea/libraries/Maven__org_springframework_boot_spring_boot_starter_json_2_0_2_RELEASE.xml delete mode 100644 .idea/libraries/Maven__org_springframework_boot_spring_boot_starter_logging_2_0_2_RELEASE.xml delete mode 100644 .idea/libraries/Maven__org_springframework_boot_spring_boot_starter_tomcat_2_0_2_RELEASE.xml delete mode 100644 .idea/libraries/Maven__org_springframework_boot_spring_boot_starter_web_2_0_2_RELEASE.xml delete mode 100644 .idea/libraries/Maven__org_springframework_spring_aop_5_0_6_RELEASE.xml delete mode 100644 .idea/libraries/Maven__org_springframework_spring_beans_5_0_6_RELEASE.xml delete mode 100644 .idea/libraries/Maven__org_springframework_spring_context_5_0_6_RELEASE.xml delete mode 100644 .idea/libraries/Maven__org_springframework_spring_core_5_0_6_RELEASE.xml delete mode 100644 .idea/libraries/Maven__org_springframework_spring_expression_5_0_6_RELEASE.xml delete mode 100644 .idea/libraries/Maven__org_springframework_spring_jcl_5_0_6_RELEASE.xml delete mode 100644 .idea/libraries/Maven__org_springframework_spring_jdbc_5_0_6_RELEASE.xml delete mode 100644 .idea/libraries/Maven__org_springframework_spring_tx_5_0_6_RELEASE.xml delete mode 100644 .idea/libraries/Maven__org_springframework_spring_web_5_0_6_RELEASE.xml delete mode 100644 .idea/libraries/Maven__org_springframework_spring_webmvc_5_0_6_RELEASE.xml delete mode 100644 .idea/libraries/Maven__org_yaml_snakeyaml_1_19.xml delete mode 100644 .idea/misc.xml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/uiDesigner.xml delete mode 100644 .idea/workspace.xml delete mode 100644 .mvn/wrapper/maven-wrapper.jar delete mode 100644 build.gradle delete mode 100644 gradle/wrapper/gradle-wrapper.jar delete mode 100644 gradle/wrapper/gradle-wrapper.properties delete mode 100644 gradlew delete mode 100644 gradlew.bat delete mode 100644 gs-spring-boot.iml mode change 100644 => 100755 mvnw create mode 100644 src/main/java/hello/config/RestTemplateConfig.java delete mode 100644 target/classes/hello/Application.class delete mode 100644 target/classes/hello/controller/GreetingController.class delete mode 100644 target/classes/hello/controller/HelloController.class delete mode 100644 target/classes/hello/controller/TopicController.class delete mode 100644 target/classes/hello/declaration/CustomPredicate.class delete mode 100644 target/classes/hello/declaration/TimeClient.class delete mode 100644 target/classes/hello/model/Customer.class delete mode 100644 target/classes/hello/model/Greeting.class delete mode 100644 target/classes/hello/model/Quote.class delete mode 100644 target/classes/hello/model/SimpleTimeClient.class delete mode 100644 target/classes/hello/model/Topic.class delete mode 100644 target/classes/hello/model/Value.class delete mode 100644 target/classes/hello/service/TopicService.class delete mode 100644 target/classes/public/index.html diff --git a/.gitignore b/.gitignore index 57f1cb2..2d513a0 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -/.idea/ \ No newline at end of file +/.idea/ +/target/ diff --git a/.idea/.name b/.idea/.name deleted file mode 100644 index a156ef4..0000000 --- a/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -gs-spring-boot \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml deleted file mode 100644 index daa2f90..0000000 --- a/.idea/compiler.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml deleted file mode 100644 index ba88c4b..0000000 --- a/.idea/encodings.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__ch_qos_logback_logback_classic_1_2_3.xml b/.idea/libraries/Maven__ch_qos_logback_logback_classic_1_2_3.xml deleted file mode 100644 index 6fec8f4..0000000 --- a/.idea/libraries/Maven__ch_qos_logback_logback_classic_1_2_3.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__ch_qos_logback_logback_core_1_2_3.xml b/.idea/libraries/Maven__ch_qos_logback_logback_core_1_2_3.xml deleted file mode 100644 index 9eb8596..0000000 --- a/.idea/libraries/Maven__ch_qos_logback_logback_core_1_2_3.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__com_fasterxml_classmate_1_3_4.xml b/.idea/libraries/Maven__com_fasterxml_classmate_1_3_4.xml deleted file mode 100644 index 33c30b4..0000000 --- a/.idea/libraries/Maven__com_fasterxml_classmate_1_3_4.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_annotations_2_9_0.xml b/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_annotations_2_9_0.xml deleted file mode 100644 index 06441f4..0000000 --- a/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_annotations_2_9_0.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_core_2_9_5.xml b/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_core_2_9_5.xml deleted file mode 100644 index 1205e0d..0000000 --- a/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_core_2_9_5.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_databind_2_9_5.xml b/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_databind_2_9_5.xml deleted file mode 100644 index 467b779..0000000 --- a/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_databind_2_9_5.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__com_fasterxml_jackson_datatype_jackson_datatype_jdk8_2_9_5.xml b/.idea/libraries/Maven__com_fasterxml_jackson_datatype_jackson_datatype_jdk8_2_9_5.xml deleted file mode 100644 index 65b251d..0000000 --- a/.idea/libraries/Maven__com_fasterxml_jackson_datatype_jackson_datatype_jdk8_2_9_5.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__com_fasterxml_jackson_datatype_jackson_datatype_jsr310_2_9_5.xml b/.idea/libraries/Maven__com_fasterxml_jackson_datatype_jackson_datatype_jsr310_2_9_5.xml deleted file mode 100644 index c85f307..0000000 --- a/.idea/libraries/Maven__com_fasterxml_jackson_datatype_jackson_datatype_jsr310_2_9_5.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__com_fasterxml_jackson_module_jackson_module_parameter_names_2_9_5.xml b/.idea/libraries/Maven__com_fasterxml_jackson_module_jackson_module_parameter_names_2_9_5.xml deleted file mode 100644 index 4ace22a..0000000 --- a/.idea/libraries/Maven__com_fasterxml_jackson_module_jackson_module_parameter_names_2_9_5.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__com_h2database_h2_1_4_197.xml b/.idea/libraries/Maven__com_h2database_h2_1_4_197.xml deleted file mode 100644 index 87c599a..0000000 --- a/.idea/libraries/Maven__com_h2database_h2_1_4_197.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__com_zaxxer_HikariCP_2_7_9.xml b/.idea/libraries/Maven__com_zaxxer_HikariCP_2_7_9.xml deleted file mode 100644 index 6d6865c..0000000 --- a/.idea/libraries/Maven__com_zaxxer_HikariCP_2_7_9.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__javax_annotation_javax_annotation_api_1_3_2.xml b/.idea/libraries/Maven__javax_annotation_javax_annotation_api_1_3_2.xml deleted file mode 100644 index e74f3ab..0000000 --- a/.idea/libraries/Maven__javax_annotation_javax_annotation_api_1_3_2.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__javax_validation_validation_api_2_0_1_Final.xml b/.idea/libraries/Maven__javax_validation_validation_api_2_0_1_Final.xml deleted file mode 100644 index 6978c0b..0000000 --- a/.idea/libraries/Maven__javax_validation_validation_api_2_0_1_Final.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_apache_logging_log4j_log4j_api_2_10_0.xml b/.idea/libraries/Maven__org_apache_logging_log4j_log4j_api_2_10_0.xml deleted file mode 100644 index cbe5ca7..0000000 --- a/.idea/libraries/Maven__org_apache_logging_log4j_log4j_api_2_10_0.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_apache_logging_log4j_log4j_to_slf4j_2_10_0.xml b/.idea/libraries/Maven__org_apache_logging_log4j_log4j_to_slf4j_2_10_0.xml deleted file mode 100644 index 1407c58..0000000 --- a/.idea/libraries/Maven__org_apache_logging_log4j_log4j_to_slf4j_2_10_0.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_core_8_5_31.xml b/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_core_8_5_31.xml deleted file mode 100644 index a6693a2..0000000 --- a/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_core_8_5_31.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_el_8_5_31.xml b/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_el_8_5_31.xml deleted file mode 100644 index bc00163..0000000 --- a/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_el_8_5_31.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_websocket_8_5_31.xml b/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_websocket_8_5_31.xml deleted file mode 100644 index a47a3be..0000000 --- a/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_websocket_8_5_31.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_hibernate_validator_hibernate_validator_6_0_9_Final.xml b/.idea/libraries/Maven__org_hibernate_validator_hibernate_validator_6_0_9_Final.xml deleted file mode 100644 index 5a26bec..0000000 --- a/.idea/libraries/Maven__org_hibernate_validator_hibernate_validator_6_0_9_Final.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_jboss_logging_jboss_logging_3_3_2_Final.xml b/.idea/libraries/Maven__org_jboss_logging_jboss_logging_3_3_2_Final.xml deleted file mode 100644 index 5f7dd01..0000000 --- a/.idea/libraries/Maven__org_jboss_logging_jboss_logging_3_3_2_Final.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_slf4j_jul_to_slf4j_1_7_25.xml b/.idea/libraries/Maven__org_slf4j_jul_to_slf4j_1_7_25.xml deleted file mode 100644 index 6073e53..0000000 --- a/.idea/libraries/Maven__org_slf4j_jul_to_slf4j_1_7_25.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_slf4j_slf4j_api_1_7_25.xml b/.idea/libraries/Maven__org_slf4j_slf4j_api_1_7_25.xml deleted file mode 100644 index 20e8163..0000000 --- a/.idea/libraries/Maven__org_slf4j_slf4j_api_1_7_25.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_boot_spring_boot_2_0_2_RELEASE.xml b/.idea/libraries/Maven__org_springframework_boot_spring_boot_2_0_2_RELEASE.xml deleted file mode 100644 index 216fa5d..0000000 --- a/.idea/libraries/Maven__org_springframework_boot_spring_boot_2_0_2_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_boot_spring_boot_autoconfigure_2_0_2_RELEASE.xml b/.idea/libraries/Maven__org_springframework_boot_spring_boot_autoconfigure_2_0_2_RELEASE.xml deleted file mode 100644 index 416393d..0000000 --- a/.idea/libraries/Maven__org_springframework_boot_spring_boot_autoconfigure_2_0_2_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_2_0_2_RELEASE.xml b/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_2_0_2_RELEASE.xml deleted file mode 100644 index f4f17f8..0000000 --- a/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_2_0_2_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_jdbc_2_0_2_RELEASE.xml b/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_jdbc_2_0_2_RELEASE.xml deleted file mode 100644 index 1fe0fd1..0000000 --- a/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_jdbc_2_0_2_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_json_2_0_2_RELEASE.xml b/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_json_2_0_2_RELEASE.xml deleted file mode 100644 index 7f64d70..0000000 --- a/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_json_2_0_2_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_logging_2_0_2_RELEASE.xml b/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_logging_2_0_2_RELEASE.xml deleted file mode 100644 index 73c5114..0000000 --- a/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_logging_2_0_2_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_tomcat_2_0_2_RELEASE.xml b/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_tomcat_2_0_2_RELEASE.xml deleted file mode 100644 index 15cdbc9..0000000 --- a/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_tomcat_2_0_2_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_web_2_0_2_RELEASE.xml b/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_web_2_0_2_RELEASE.xml deleted file mode 100644 index ab4ca86..0000000 --- a/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_web_2_0_2_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_spring_aop_5_0_6_RELEASE.xml b/.idea/libraries/Maven__org_springframework_spring_aop_5_0_6_RELEASE.xml deleted file mode 100644 index 45ed002..0000000 --- a/.idea/libraries/Maven__org_springframework_spring_aop_5_0_6_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_spring_beans_5_0_6_RELEASE.xml b/.idea/libraries/Maven__org_springframework_spring_beans_5_0_6_RELEASE.xml deleted file mode 100644 index c046b8d..0000000 --- a/.idea/libraries/Maven__org_springframework_spring_beans_5_0_6_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_spring_context_5_0_6_RELEASE.xml b/.idea/libraries/Maven__org_springframework_spring_context_5_0_6_RELEASE.xml deleted file mode 100644 index 9b830cd..0000000 --- a/.idea/libraries/Maven__org_springframework_spring_context_5_0_6_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_spring_core_5_0_6_RELEASE.xml b/.idea/libraries/Maven__org_springframework_spring_core_5_0_6_RELEASE.xml deleted file mode 100644 index 597e34e..0000000 --- a/.idea/libraries/Maven__org_springframework_spring_core_5_0_6_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_spring_expression_5_0_6_RELEASE.xml b/.idea/libraries/Maven__org_springframework_spring_expression_5_0_6_RELEASE.xml deleted file mode 100644 index ffca824..0000000 --- a/.idea/libraries/Maven__org_springframework_spring_expression_5_0_6_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_spring_jcl_5_0_6_RELEASE.xml b/.idea/libraries/Maven__org_springframework_spring_jcl_5_0_6_RELEASE.xml deleted file mode 100644 index c0a9cc7..0000000 --- a/.idea/libraries/Maven__org_springframework_spring_jcl_5_0_6_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_spring_jdbc_5_0_6_RELEASE.xml b/.idea/libraries/Maven__org_springframework_spring_jdbc_5_0_6_RELEASE.xml deleted file mode 100644 index 671875f..0000000 --- a/.idea/libraries/Maven__org_springframework_spring_jdbc_5_0_6_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_spring_tx_5_0_6_RELEASE.xml b/.idea/libraries/Maven__org_springframework_spring_tx_5_0_6_RELEASE.xml deleted file mode 100644 index 6e29e18..0000000 --- a/.idea/libraries/Maven__org_springframework_spring_tx_5_0_6_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_spring_web_5_0_6_RELEASE.xml b/.idea/libraries/Maven__org_springframework_spring_web_5_0_6_RELEASE.xml deleted file mode 100644 index 521bb85..0000000 --- a/.idea/libraries/Maven__org_springframework_spring_web_5_0_6_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_spring_webmvc_5_0_6_RELEASE.xml b/.idea/libraries/Maven__org_springframework_spring_webmvc_5_0_6_RELEASE.xml deleted file mode 100644 index e4279b7..0000000 --- a/.idea/libraries/Maven__org_springframework_spring_webmvc_5_0_6_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_yaml_snakeyaml_1_19.xml b/.idea/libraries/Maven__org_yaml_snakeyaml_1_19.xml deleted file mode 100644 index 33ccf19..0000000 --- a/.idea/libraries/Maven__org_yaml_snakeyaml_1_19.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 01b5b5c..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 751276b..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml deleted file mode 100644 index e96534f..0000000 --- a/.idea/uiDesigner.xml +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml deleted file mode 100644 index e90adcd..0000000 --- a/.idea/workspace.xml +++ /dev/null @@ -1,943 +0,0 @@ - - - - - - - - - - - - hello.controller.* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - HelloController - aslist - compata - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1526804939552 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - file://$PROJECT_DIR$/src/main/java/hello/controller/GreetingController.java - 15 - - - - file://$PROJECT_DIR$/src/main/java/hello/controller/HelloController.java - 55 - - - - - - - - - ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString)) - JAVA - CODE_FRAGMENT - - - ZonedDateTime.of(getLocalDateTime(), getZoneId("UTC-04:00")) - JAVA - CODE_FRAGMENT - - - - - getZoneId(zoneString) - JAVA - EXPRESSION - - - topics.stream().filter(topic -> topic.getId().equals(id)).findFirst().get() - JAVA - EXPRESSION - - - topics.stream().filter(topic -> topic.getId().equals(id)) - JAVA - EXPRESSION - - - topics.stream().filter(topicId -> topicId.equals(id)) - JAVA - EXPRESSION - - - topics.stream().filter(topicId -> topicId.equals(id)).findFirst().get() - JAVA - EXPRESSION - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - No facets are configured - - - - - - - - - - - - - - - 1.8 - - - - - - - - gs-spring-boot - - - - - - - - Maven: ch.qos.logback:logback-classic:1.2.3 - - - - - - - - \ No newline at end of file diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar deleted file mode 100644 index 5fd4d5023f1463b5ba3970e33c460c1eb26d748d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49502 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%0A$pwhjXzyA0ZzErH{1@M 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 OJOEd-=rxTO#Qy`$*1Hh^ diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index c954cec..ffcab66 100644 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -1 +1,3 @@ -distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.9/apache-maven-3.3.9-bin.zip +wrapperVersion=3.3.4 +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/build.gradle b/build.gradle deleted file mode 100644 index 09f1083..0000000 --- a/build.gradle +++ /dev/null @@ -1,32 +0,0 @@ -buildscript { - repositories { - mavenCentral() - } - dependencies { - classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.2.RELEASE") - } -} - -apply plugin: 'java' -apply plugin: 'eclipse' -apply plugin: 'idea' -apply plugin: 'org.springframework.boot' -apply plugin: 'io.spring.dependency-management' - -bootJar { - baseName = 'gs-spring-boot' - version = '0.1.0' -} - -repositories { - mavenCentral() -} - -sourceCompatibility = 1.8 -targetCompatibility = 1.8 - -dependencies { - compile("org.springframework.boot:spring-boot-starter-web") - testCompile("junit:junit") -} - diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index ca78035ef0501d802d4fc55381ef2d5c3ce0ec6e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53556 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�H$uJM z5b&uBBCA_wdL?^xw19P_F!l$XIUCIG0(Uznb36A^l7CS!0R}%?tUXwj0HwXsK4>8v zWE@fGYQ(q1F-!wr2v#*y7wWza-i5khqjQYc`6WHxhz85!iY%{Wb*z~zziBKpL+~P= z5yWtFJwj0m!TPZcI??gVUnnQOG_s*FMi>bxB)n3@mOYG~$F8 zl_Xm}#nH#t1z6WP61iq!0zB{Jh{o+KuI9xVM*x|TC7COi#tnUn_I;MA4`P!sk}}W2 z$gGS}m_|3n{2>Nib`R}0pU=AR9)Uh6;G*?1T2ZSB5`4PjrO>Bt2=i6u=qr=bN)Jho zMV?Wtn1yFbC*Io^`FFE6o|ePN6GG{zD$mtIc0OSsefFkNdF;nI-VNeuPS?6%IPVoN zZsFOKggP&tnTdglp;!r1nb~ME!H<>dW?N62A>Q1QI7WDZr;ehh?{L3L=pIMlpL9<- zCZ-fg1i?An;l=twL*C@`7quCoH<3MF6KapUt`yRJpF@_5T*SKkjpGkuc&h|H=`ud? z`ZbMU&m4ld%TU}+A+8V~1;8C{f84t#jj{05Rv(nfKmS(5<=Ac8!Twv+zNQ2KAo$N0 ztE8Q?i=mCpKTj(+=3sG#PuZ69xtt)EQ_E$H(y>G9(Tc1>K{$_6M z*(L~w^!?vvr`|bde{$}8^!2_!m&7A22>lTX_-4~b$zzFP^|OM2SO6_YC(5x3nDFZF zLEs;<=Rhe2kWFopSdxKt#+6GlvG$4b&}%<@1KN1(I;X?0JG+# zOZ+SI(Rz6pJnLxoojp_o=1!h~JgSvFTm#aA(MK;!EfdNVDQXa* z&OSYBpIIn<0tfRSotyL5B*mozW{+MLZ6NMLdlU~=0cuYk{B}v^W)@XIJ)rGX--$xE zOcvV!YR_%}tq!75cM%KJ4z>o<-#?T-I%Kk_LSFz{9lHk$0c_9Q_`|<#-aCblZ)o=E z*hH(RzI&AO5E03$9B2e^8%VO=Ic`s>OC%|BVCLoQQbv;^DMQ^Uw~-6%GO^F}H0Q~q z^f33U->p7+w08Mu`8u@@tTTdOW34aQ*zLPo3M*ZgM$1;R*;#AtJ6(i#%35VYXVR~_ zpR*$Hu4*h>k<4nGL6_ctd(c>3Fj`0BNeVt%XZj?1n3pFSWG&#xyR5p9Jv$6nTu7ep z?1&YWZQu<{`E%?dM-RU+EZMY2%EDea9xT>s>$*;qAlk-5oOIejvmMX=Dq4!!RUk=a zamTctj!;C0!kjqf;w{^1TIo=<;5h(Fc&cSFE^CdtNLq|vxH@9x>|8h1&ggl0X!ym_ zxDkU%TWQgqxL#tcz=HsPkx1(`m~!V*zIMr!EW@nJ8EsF5D1i?_3bVt6HC-~|(pC+o zolB0hY3Npl)MYwqOg)KHp8bH;7}-IT!ab|vHd#`jh;fZ<<}KC7PEI6)jPuAiRJGC5 z2&o+9RNmrt5uHY7Ei0NyCNA<4mLnKiFYNv_Zb#Nii3WTZ0arZ8AT4M0>{%QkfFKHD z$$+eh87@<>*<{1qeS%#EY7=9pnWpm2e2)YsTnSN=OZ;bh@jzvAJ7{9b^qHwKQXd&- z%P@H^nn=iub17MjB9)=GFUvK6%wfa84NFp5%?$!9s);AdXonKo1(r8TF-+CxrZNsr z&~Nv31)}ejFF>%}r3{F{mBb*6PpWF=m1;g?!&1Yw@g9xX(CztT)5@3!PJ$MraL?jJ zjIfepZ3R}0DTSdM7v5{g4CqqENzH&qX~|~OOAZ?k(03=3VqR=omosOJO0#<^kry}S zMOVziT*;@o#igZ%dH=|V33S4P3X#diBc9o-J2t^IYq9m{K7GEtHmM_yBtV6$dz7+GSDI~g-K~b{o`Ud#% za0>r2$Osa6KCfwq^?pc*f*-YeG33x$$Cz>r@k4A{>e&zlHn~AYPNFAkSGe@|SF%2qflcY{3Q}TP1xU;;lixI`{PI_{1MwPU# zb8@!|+^PX>d@Px~2o3tYZS<^mg8`s&^A%j$#_ecM)T0-=M6*JcsBjG$6!qH-)6k^r z=hP|(rciXq{A45YWNjc*3tE28s-&}Y*eX(?Dl3}SRu~$6>Iiz?;9=wGO3&_yuud9e zI;ydoyIqTk1TB7ZTT{o1+!@^A%5#rZX4&G?bC6Vjp}Q)V%s16{j$h#-0dMi5>oaC* zU7@wAR|uZ!g;*b6%$SP9WYJtzOSYZDh1c(z!EV*QKzo%BvfbkQv*RPPRQm&M)gPX{ zsGE;rsTtrJ$#Y-96Z*&W0@1o8i1XD}SJet-l%J+a?+-Q*x7&~$2T(*W!GkT;zTp0% zNA(Z6)VBxSak^X6;6eB5FV>%~$+vsI)VmXV3FrLDw`e5ziZ6n180=s3hq09zred)+ zgJxaVKHB88?P~L<=_F^?2OWvaMvl_Lf>sx1GE2t38EFH4*y%WGwX9|A`ZH11xDv-% z3(>w@i{-S_vscw(nT*5!zMm)OY9HA?0x+)$lY58XGTd?$B3bT8G>2Nx$&v++LtnP3 zw}ctz1peYD;s&U(-^Myl#2TRgMq>XF?%dT=NcS~K*x?!t!7>qNE z#XC*r*1Tmas=7$c($69)&0Q|gv4u14v;$|>JCPh{TE18`JLEk$4XUNT)N=8{H?x*& zvob>*k&1|Mkkd%B@&YU_Lcn6yuNS9U<3xC>F0xW3NJsSKU{z_OEIUWa!kVhos3p^e znKBiVqZGn&Zfiz_FCObw-B89YT-{>XtOQQPL1W`9eIoGH-yu`;QO593{jOJqGn?rW z=RZk&t9S(Xl|LZ(OCOgW*&y;4vV)EVx-q4}3kS|HZRW|V9K(LmDf^v;cNIA<6Xu;r zr&oQ^+#ynltMZM`QGV&B_LCdX;Ne^G^-p>$C`a&0*)GRI%e-E{tr+g{@f;iM4wUfPv7pnd_ccS(@ z4{d>u?2E(%@tJmuYw(j8bKAF*cbJo=l*&?B*~c9JD0L7D9LGrhr;Cdt zncS<5VKKJXK?NvGezTQjVUEao!!?}QQz%e#pJ`pN*=dEnReH3bA86g#Q&aLzn9ReZ zzJ$1Y2xzkQdOGVMvC7*9JIRk=IPkJQ2Q3hL%S@dl8N9sAYwsaPHJ_V#Ur9yFWa?cX zjz$+PT{j#E`o?A)2J@8F_`LjHqe`B}I=iKBH6G%zkONe{6sF|Z1v_YQ5&iJov>WGX zipwqW?lIMTBKC>nGA2tsNMx`5CdJY5t}Sz&K$ILDLDC^Pxs_SN&B&jwR}-G3CYZ?b zgKQIgD&Y5pU|OO#CgM zDGuh11j==SAiOZK7m6XE5XW7K(-=sL% zH&+Fz#zLnR(xemV8{F6vc-V`jR7;uVCP}E6Ih=qbmD+TbZ0%-$&Jvj$24?|h9`H!y zP_Tq~oX$EP6%+(9dat$vf8(7vrhU`tFbifgmbiJH(c??;^VknrH z0hsB`p0zIK60yzL%uq8HIxikY-MQKue-X0Bb=6c(wEk*{u0TF8t-_|Q3?O!7wDN;z z>J}_l#!p35Wa#!8&${i&4N1dhNxC7AoA!|VwT*p2*5ZBdic8_~ zkfY8g0D2OPVnL0=o~egN@WK#FU(X>U<#}TGn5vFj1{rPxmoMy%^)Wv?A{ASoTusuuqHD7a5BYf}yH8T5&ox(ckKBEO7Rd?Y?Lp&5oNE!c_F zq_zlC1$F{`-KoyC!}LT)RKJ8?u*ioiyHCbjkW@hWoNawAxb?(^dk1pHOkmE}1>J0> zG}DEB*XNnF=GEwAtr6@@RUF?=NFRWh9Yu~`=$C7-iLKM&68Z7$lSa2Q*@8# zr=^)HLw~**-4mMU9p_K_q(NUfgw!mT!&mU6UzRR3?O6+Kf?Bml+DG)4;NHTg#V->s zyl2!8bbaR#xq4a%wC5$AyIvN$3K^|=d2<_Bszp}&D?5ICjvp_Di}EDG=9VygTzAmMB#^O zss~=SJf03Zqu>_Z_sevE`Gw-k0H0vQK&)s_8m#@KSCn1IhS-8236Qy3u!>h&Myz`1Kd8B~HlYtAU=gA11kqTr1`MN9eyqp7elU7>IHRBL9eHY4UWJ;U)t{yN*Rm)~+ss$M3* zIi`3)<{@3Z1heF9@JR!C+xWC##A~Hh6;Jo%oqCK$fPG6;Q%&iwSVez+S&H&4Q3Lap zUzp_C?Bd3k@N0J(XK%I*Y8R~CI>_d(Na+h|_@M&n3!V+t$ONDV-MniLcA-)o=n`-A z<8ttu7TbY&f9C8tiFVKgy;}5p4$ktRr@!JYKa+g+S!26-yZ6r1b6BM82c`o(|AP?0 zWsdI&53A&;EqYJ|$mNdP4zuWK+h<-`H>2EvRYzSDeze~owhCzF^0Iu^xV^Sv!nqE-4@O&@C z!xw^61W&#Ioa2BSBx>;v{M8g!r2;OpS_^Wo%k?M z1ce90s~<)S-q0se_|)Ik!#!_j=fCxaOQcL`BqD`8@WsGWMqEx#v)r zTb_n1GZNvTYT}r9Ag$(i!8X6 zNU$YbD2sh6*}S%!#>qseXVzSBf>J|g&tP1*6;F(7o@z5yBV>-A-B7jDD$%}mKu=Sk zf%YTL_D!P3ujNo-A&!SXL@>`t8oeE<)7Iexa;)be(pOWnJo`y_%5?g?Bb{Z}ptE2I}2DbF^CCr)96 zZd?xW*TqH)B}#ln^QHMl0vFi9DB#20TVb)V^Qgcn0)Pn5QtC|S*aXu1d0YZVxclWn zla0V*_UL8ZB}?}GpxUEvE}5UU{g&yp2-u3POD?+vzbH_ZIN zRg;d~&1^c-`zGviyarVb*dbjO!waqeW4;Cq;S+k3wYM35$?xwUuWHYeBT!~ui^?u2 zDTZnl*=D}kWhrQysw44&$Nj-HI2T1J7ejOO7yPtWc&(=}{Xst2-Xpm5Hw^?R(nORl zSOwG`MxuD_>usNDbhm*wP?Gs$a<)_xk^J>MS8yA#9>Iynllll{WARg{G;EHXW5~Rm zL-|Z^83y%jy-5Zok}|{6-5&6+f3dejs1#g2J()gyET`p4#!=Gv&R=kKKGLVG{l$(k zuBnqP2gKL?<)D89(n(*PI=2Aj@{|2D7901rk8$xu|E<3{jctG{$?BJZ`OP_jqll%=o>SRg|iFp>7h4N6Qe#g*&gbN`CDKxlneuB#GKMN82a|&*-r|8(MUx|XCNs?v_@JrwJ}g0 z1b>lmV2^)q7zrPHc~=+}f7ci!e^K~w(iTHcLQ(?qQO+vdSOVfHybl9#9F<`NjAfiL zpzfSzYhGQp%_aHC$W(cOU0HnZBS5*)rKKjoVXk#yv8|-c70uVW{NZaZa+h72-E7fR zVcaym*Yi3l2bwmQgK^|i|uC9JmO6AKTOo5vSaE7!I z7ZHBuWomktl`=e+6bx-^L31&#i>t|oUVeMQkI}O>)vi3Otn+MRh-9msb!l8`zjS>e zMnz@@b3)gQ)5J>%)w9Zk?$$!iRb}du99&z~D;Ki_0S#o?vL)fjY*wm?^GxM${*Gun zIEbK*(gVC5#6>583s9<3>=)c3k{hbUdh)$UU|bAPFuY&}(krSDl(Zn43%S=hmgshs z=rhpKIIsC!BgObZ!2HuPa&6Q#rAL%7pzPV<=a#n$B&0YL-_V(;Nhr&F=vu37+#xim z{vkE!+&$}q(@;FxP`p?e9ZC z4vpX_#JUbq>_JIgbvIfvrRMIGnav%=hkdOyHPk2j&C_|64`1BE^$=?XOI`Or;6f`i z%+&w0(j-K^MUP-Qc|Xl$J1UgL%$O@>;R1MDR;90qh}(>`OjQIL#PO^Ud7^a} zKEP||e^%jto&@%3V@I!Aq8DlAuW`A;?t{==&x;q%Ah_q{ix0630P2@y;*klP4#WSD zaYvrc6eb!k*X9f+Blw4B+{c_A%nYIP2d0RBGh&eqBaZ_z#;*Yt=}#OjhOqCy=#yQI zhLnTKKJa9b`vB$(Ao&k6%Y3HIpu=gwm5)Ip7dYg$+zm3+8Nuv4&&&(s1N6d8d!kDL zlIe#s9t-S|d?E&24++OCMt$N4hjc`}+dEZx>O6oyo_|611-z}D z72Qwu`{x!>AM|UH_ypY=KYux@1-d~&Lm`*!P$2dQUO7(kmUGD(27|Z}pD-<%rw|?YSLpf58810bgRZon-0n3jtyb004^rTxa-a zKd7jOsj=&SJqSxx_cXv!#rz}NG-1cK6k?auMoCFSYP&ciI<=EVEUAn&zGAbORkS*B z%c8k{9kQ{32LVMvK~;o9gd!qZ+b(zk77BjX0nkOz|t%ZyQwv6Ar9!-%hi0EWRDop&s8J{t(y0 z909e1K0*rT`AAn#<;Vb(bB}h&+k}H;$ou5^)5N2{!G|CKe)3JY>CrILmm~o5W0!tN z9QZxM2S4Fvh-nIpfqDROrU(*+G56EtRg<3&eRzWdV<7qQ+Xp}&Vm}(thcbX3{5}<+k7`Q(^&cHM; zpl;S8UR>zsRN-u#ZSFLxXXd&w^ZzvKkH|Sx|QW;}y zwwjPUwZ>^iUL(>(T;Vp?Oug3rW|qX_4^=p`p$h~p-0jjdiZAZ8#u6qq`J`B(vzM0q zNULLZBad0hD+w7&%@y->WE`Y&H2F)MZLeV;-OxonwCUHW9SFHb;wf~iO&b;(Y@u? z4%$Tw*5v5}98V zAZ>y~BgD&16*=U&=dz6A*+(*dzh4#d=V|EhLBCRaXjJAGzl4-l>$eh+yQQ<~dAmqa zl9#Dzi85)r)=V+bZkEbESsx^rK}j9w%QKNhO3EVOuo4|as4O`0gg{%5M33={#iFwY zV;t7oFqNM>lkPhc4SLqt@NKudj9#nk@;Mm_B2%2BatkFH9*8KcQl|t{KtSjgY z*dyH1Y4R-;uFe>yuk6y09p9}tk*IiQ^&8^Sb@1RwZbDM_s%t=P>0%2-4+(#p&v01E za#7~6OOU}-)7YC^v^1Zg8OOp&zdawbSLKP_iyYi*wnEqBrE)tmr5bIJ9x3%`j7r}x zrGnd+LZ!r@`U&7y(%e?A*VWQee<0^6K6LGn9LX2e#T!d7ldXD>cKA|dyXwhakc>^Y zU|}vjw2zC)R^_3#xlE0`peQcn#`>Y_{xiPi0P;tf?S~YbRn&_m@tTckq9Zo#x#_-- zXdr7e1=gl};Kd#_?fo}C;+H;8`Jv}5%78(8)LH9o3C7p&40<_JO;wcAkjx!LfDGk8DQwau;V^g~l&8@j40GToR?g^-kw zg`U~VD4<;(?gO>o8QOw*o2eOY%b-hogBy+^-P~}9oIk8=OqN)mPV%ErQIVr$u9Zim zPWVp?=}kFPByX$Q9>3O3){Eu(Mmz!xX_{dUCp)ZOqg4dAitL=*7skIWF`qgcKR`=| z73~K%jpmF&%RNio5*}ZrrMQ@dS9P9qEzVREVS!Mjv5?wQ z$NUT#V;GsVUyHZuVn+B#;-QoqrCZjcW86wvJ2!mql*$(h9N|>;flzX+%cPISgz!D)|S2qu8H6sywRqb zH0|YusE-pxerVLq91EJ(4y$S#*5sVlS{7Q1Vm^3dsVzb!C&%owKGo#j+`M5C)`bgSG;KJ7N}V}!HM{-L%%=~hF|}OP z4B=oEPu$ARBWjggMLMW@qnJ2F=a@E5j$x(taAwVba*-i(rC~K~U~CT&AZ^_$pKLC_ zcrJm`yAp)aa#0pU5qG|83u#T|UXiQLGw56RvP9?Plv-;wZG0inQw`1tRbIDlZMG=$ zS|gNO>O<1ZoG2U9Lc!4dAc0qg5MG))j%e(Yjl)iQ)Ae*@?MLAFvMW%2jj zZ2vR`>O-0iRM!3s%B4PpaPN0j&1YI~KjGefFmdX8yi?5`G;JSPJLX19CW%R>L$-2l zg0ubJ)Vj=k4Sqv6*<&4k)JnT|?F343%AoH?&=Y+|^>*VWRx+B?3toG)Nif@!Q1Iad zAo=-XKjdoIpdAq?5jDKyD4h?#;w42Jw}jb;b*m9wl&veNO;Nd&u%acq5R)&6OCxD! zcTzK&>e)#3gsx=jR&3DNKxMOeUipkG=-Fjo@&fs9jJ;EIW!=8+orlHDoo3JJSd@`y+1I$tN#2dj6pE~%ELv|P#LU> zoiF2g3Sa$N)aTgCV{So-dAT@qt|W;9pT34JdcC5%fP$a_bA0s+=%|1Bqa8i?P%GQFXn@ny5sv z$hoFJZ8|eCPH#@tHZK+Tk_}5%!xkj!5;*zf_RumpDb~VeFVHCD+&r(RPP=$s%-meK zfpkJYx{;+d6gVYZPvz&>>KD{MD&A_eUz; z-J>?U)P~OOTL_uhm5ERMn+V;@p2SyC3*99lwtX+3|X>OZn3?WV`e1N zXMW#8K>SF|`4Jx?KQ_Q1E%qsv(Z^0Ie7$A+R*LA{#tw0PH|hO)PDff)ym7Y`Z*&E^ zDZ+Yc_Mo2gbbJf_&bLba=M&AU<83pI@xe zAfIp-=gbZ;@$sWxHKEQuk7E3cXJ^T7d}w9M9Z>>&r;O?BDyV5{s3_nYDCrkn+umNA zOZiEk0Wn2Ny@?YgUS$IccYX#1?rn3#Sd`=nY;)0h7|LD6 z4JU?z?sUhmpzmdYC~N~f`AmT&Mf)%bA!>^fQlb9wjItGcQk(q_d~vMLb==xB60|tB zEF;4Y&$XPOOxnP^N)nQpni)u`BLp{Cu{|h{TG373ctzG70Szai zdfAf((wJP2MV02XykIG=+?}sw7xYe%t{B6UaVTXMqI!xa^+=NHM?&0k*l~#_s6E4Q ze)jCi&R!#Bp-eV%!Th|L=U_jRTp9|PyePmbxDD~5)DLo3j)xuNDrB1@@7j4;1@$KI z^*3w#-=Vm@(fLKcGAtIFAS|eawsoXFid<^@6CwsQmC@&vsL}E_w*8+L5W71w3t^A!F zl?Lt|G9LC=8i4Gwb@DA@+6j_Ik?3s1w|^#r>AzP&-KkbuNJijd=jchdM4=1O>X)08 zKux(&W|)oV8+Rz6@XMlw3dvGNmfk3{DF$t5h*cZ3eq{q4TKgu1J`^u!)RrnAr7jXi zE+v{qGR{^f0gk4a7baDwfg;VSNLGH@$aO{Y&X>RdrQ|@vZEB2Igd-?QyEG`O^kZ8w zy)4Ycu&uY5osWQ{YPMF;Es_aEC@wWyCVHVEufUY#pd8om7#d$T)hG`-V-tnXBFJ*( zn^lHck;P1$k=Wq;AZ(qI6ugCD5*jA_21gs!uFjz*zZM<6srgenF)rCbeo%1*xT?fZ z2vyO1MWI!`SmoTHmLg4U81JUm*YJ%Y@;xzaF~{IC_pSR0M6DLd?BB4>FuvCtXo10OHYn7xB7?}dW9r^o3f0noO8z zF>xgry-GF@6OL`HwL930GNbNg_h<-BW7jz&8XTs|i)sx%VBH-Q#88$Icy+pX!RTK9 zcxw^A8AC{E;u3X*UM@Xm%5Zh}4W*!o2PTvgPls}qtCt*d^J&#!4AO+hLPy4-JZ;0} z)T!r7-3@^#<{=_gkS+&>QH>fC5Rq5jOx0K0-*8oJmN=xdepoqZA&PgVvptyZc<;W0 zX95C&fYzzwnx0%i22m7!auQA+@Zw=&)|kCx@Jg1AVo43 zIOTE=Td=~Y&Lg0d{(~LNCgF0hE^b-V8o3hgviLq-lg|e#AySvbG7Ir|PvIiGjR{X+ zv?YZl{&p>S#N{aQt$fC97*TabZKq+3|BUl zBFl@DF+;NCYxCAoK=CVxf{-T@@t@oJ~7q;_6QAcfWv6uFimU(pZO(^ zF-0ufSPgBLiQYW+*)U8s`<-|_N|@r9^hVDn@C2FKoQ+7sxSc7#yoFr0U# z{|=&N0M`8FhB)*yhb_{b-T^_m=Syi-sgDEWO zE3~Y^lESRO&!w-e?yzhJP2^EcEXmhm{^vN{o^&=(9mlO_jB{NS8<_S?B+k`|W5b8tCkk`ik! zP~h89#WaF*P$$MsOLBLn(4~TKt}W=VgxtUi9R(u{^I_s56?k)T2=0@3{ANXIJhj$1 zsop=_rnp7pnDsO_%p48jW7TsnZtN62+zodXtB-J_dq?mQYM3?SYMfCnZ&t9ZQ2iD< z%s+p%U9>l>s+z3c{<^B~NU2WnysqvAu(B6BSm2}-)mhB=P@bmuALR|h=r}|(Yk_Ld zuX-YtlQG&CU87jzYOT)lgk64hU*=LzTZYkbSx#1!+t#_VtPf!J*XxIbz7!^VP2&!f z$*=J6Lo)4DABzQsAIElQO5W@6#@P3G({;4-Pa$L6xcRq3uFsoqFWi7jS^IF~k-0Lu zxVf?^CFn-|oMv@(tH~H%C1qN^JXBO)Si|rLX%Faj^15i~>OA2)9`zw>p6#0-vw38w z%^KUDx&}Vh7|lSweto0PKO&?3qAF9EBr}9l>_qB=Tbxp(zu3ZPNJ$)AB=eC5uVL^5cMRB{MgKHK|1?ka5N82HCX*|`5o0^Kr*!6s(rJl$ zUi9}JvbAXx_uNlBK;!3`uKyRw>7UW_|3ai?sav_>E};Wga5TetCGoy|Q49fRB%)cB zf`|DgC-jxaUyzAdZf{stdw8BGh9z53oRlIDDYvtqbQZKI)r}C@TpCxalCuyY##ms z9Br^GU+*Occnm#%zBrDsIt_h!DmCg5lM{?WO}oZmK1#GmU=Uf>J0>3pfW??`@d;jn zQ+MxF&^~MjP;FocZ4pzt5>BK;j9D=SU_v)HS4;U`<7O~6pjxceCb_})9L$|h4?(&( zeC{8N-OG%~Kd~r-7HX~cdB>EC*?_3#-Eqh7hzH)|UkJf;3=op9PI;r0b!x>)zA z;p5gSir0i{+gC)(u2$}|Z&nu|G0ds^P~tNfwe%-N1+A&pUu2%1K6B~K-NJQ_d;V$_ zcb1uGMXEV<$G1CiS02>P_rkrV4Dx~n9G^cImHGw$V9}~FbZ(d9eJ2labLk9G=H42C zLU~ggxxVqjC)`8g{u8=@;$65e|Lg=#c%F(PU~+M6z^K1o%pfO$OTPFkdI5+%DQ2%W zLcxjI_rv)O{Wz@+Y+6_?kEr=uFZXuQZppLE$nmq#$oAl&KW)1a6+wb*6q|}hgE0z> zqwhGL1zL5tJzl_+XYpE6b!@0lDs7aK-ddFRex=`|#E@Oi?NT-ES?$rLr>qLlj234~2cbg)dCFsEaUxhCoE zww0TaG%V5#wg_G`j+??MojaIy<4@DgatbDG@`VVOOyd4xC4jX{iP@I_$JlVdg=)*2 z(wel+EVi;yhs+uJ)R}`lfn&}0E!WdnC@b9hYfv8jKcP`aN9|S#2ut9dNuaAKa=6ZAS4Z`GuXW zT8W2UBIBT)zI;ivj1_UmSc%Dey)IGhVLhSUhYTD3Sk_cC$;-$9Ev5Te;LeN%zbX0{nOfuo7z*QMb^k3f#%fd`zl&1JA5gzOCnxado&-u%_+4DYBck!@s#A< zk+9k$Z`H@otY;3_U7CjqPDmA~Z6qs)ly>|;OVFp%{n65d)dIb~SkElpuf-SpHMw6e zfRe=kPA9%ALxxC(v9t~*XxUb!Lq#RoT>@WK&Pvx^JwpqFPCo-A0CN7ZYHQ37Hcvz> zEbopS-zUWaMV8I(1m7npodZ2Z^lX5#$)>j_3`s}@$kC<(LFp>tphVF-2BKU@1qTUrnmoVYOjUiM)UZ^ozdL6Q8~hHW%PC5LhQ zBs_;iO|!EG^~HCyoJRKM&WNq_0+}5r?P?I8Zapm0&tmRc8s87)<#tP-$ZJZ(a@d1V zrTi`?sO#+ER&s94`aX7NxxV=uEvpK(0D_lnSq}^(YQNYr>R8_F_`!a@RU|5gP0jRU zlO>{4Qc=(jk!(>lSwNA8v0Hi5I3235_G;YA2U$n9lFR+kRXFd6HXAm@kA^(kvGZ@4 z$ZPDaAfmj`$ohP}c&48ls=w+4-QE0RE{3%vMb^UvI6CT+zQU?DjNh@cSKjCB-U=vx zH|Mqg4CH<{#JV(T!4M|g+Tr^ok zq9qm#qcJfxqQ!U#jEYP)A}z3OBrq_kM8B8yo)I~w%=|<8WUZ*(zvHPdBjN5%vDyX0 z-v)NE6UL{$M)!O^9^(HI0JZrqBhC!68-dhYu_v9*z0&A$uGwbqSy6J*~BQg z7L03dlL1HDWS`Pr^}s=9I3E^bL^ZP)jG8|PDdLFKa3+wNpkLg?TV{Afm399sb^47Y zI?}$f;mZOnf#RpzrpB71eCy#YID~miHph#Te>sBYtvRHA(;8Vr{hS^?_3R0#EYnRFnTZ;&44bWTgAcK-dcy~?t$qUrAwTw<7ryWu7g=J$OS(UT zN+cMOR%{Ss>N3KF2ZMk6HQI{yqNOU+paXkg_vATjx0A;%)t0=hBbhGG;bZXtU-|dm zEop(9oct!8V7R0PpJiHfMaI=9X%ZKKL<*)ttaxPjQ5HXJ1o5)KT)QDie_5&oL2HfE zcJ1_MV^vB0aBqIq@ri@}rZ!&u?4XAl=cL9_P`ADWbPVBA%qf^APzGsGm&d5MjZUY@ zX1EsL)!D&nc(T>&Tck+M{=Syeid4Jlw`cJxG$2QmnT!!h52Mv8)WcdOW^B@8150}r z%6)i0m)C>n4n;%AyjiCj`lf%!$JL<~ruSEf}2q{)TvJDv4E8I!H5|tKJ8d zN;J!19IOdr1O^#R`6BCqyzAlhDiLB6PTOJHHQUOiq}(f>Y*t6ZxwzY}FjEt@M#WaE z#n~pj9y}fWH=Jy^_t6GOB~hp+lW*3(wsQXGJiPs}lW+Zr#Qk>TYie2|9F~W{ib_ZH zT1|J=LCuc52_76NZfTyvKXP3JoCe)jR@})ZWJsw34iSF<&Z|t`Q#Gpy$T`Qn)!d>^ z4=Kqiqg!)iu;|QqpuuMX(#RB@(l-hbnL(mj}F2LsgwwtRm$e z;>p;v3>W6B5e^6~`+PV6rhEexRyU)}uq-#Aj-Q-@FgU}0363wojO?NfvC8((hnsq< zx7;u`!puGdHiIQ+L;!#+bAd4m2AjcxGY0P9*ilZL_j{BI8~b2ky3mqzf1l`FC+$8u zLduO30@ck)Ij49|NI>Kd^Jg;OqTLmD)nOBao<2L1H@N}yH@yKu5k|sZ!nEI!JKY!0ajCD+xk}j#bA0onRWj}^<*xn%QMxQG_tvgu+zmapC zKg6h4eVcxj;O%PZNxjz8a+uVpYmTq7NX|(GICWQj-E|AtC(i2yS<|sk8>(yv2o(zU zj*pb5wEJ`jcKg)mHDHVeWeqqLw07+TJk1Ox)A!m*?d9g-@P^#;0PVdw7#QsW7iyy} zt3}0@Ej5xGSXJ#8?waSy(&*hQwxb8{WK0($)xL_g8qK6xsn^ainS4zuEmZbOdqw5h z^|PAVR3;AP;dc*=J6QUSvmK=m+~rYlRaJ4A^KxbtZT6K#lm?6qJ$xh)q!{NROG+pG z?$$=`v=#`^iTiaa?Zo-Fv&gR%I@4!oT{&~hFa=UFA6!fYYJ6g_`hSj(v*D4I6X@;A z)CjUxE?Xrk(^xGf_%1Fn2wlV)nh7@H&E}?C4>Bej2MtO5A-ioUoJ`P4BWCv@d$osVx0k5HbVIb`K9FSZDdmXbO+FU(VmfcVWw?4a^wERqZ z0%yOzT&+d;SdVZzwXMwf`aGc)US&7jxIATx3cGD4=>XEr+~F-M(abJK7bklpZV6oF(x}wL*Q}q_dWDYFXW0)b1?@Z43nRbxCV<&Fg$- z5FIy<)2tZE6Om?vBrl$HSa-Wp^G!321jwK`v-Mob-y^7Wr;;k>gIKXnsB#?`-M`3& z!I{g=T1}w#e~r`sVg)HGwt_g0;@8SXf;o$Ei&<;SI9p%!lFwWk5I~RBMY(V zJ^K}>W3fAQeiny1_x`~z`%$e0qm~Y}6`l;0l4#ux8|VY!oHZ;PsP*omSt;HqZRWlR zB6k-I@<;dK)sTdc2zSs=hM$?m-^~Es)sWOR?&~$VR7V^0=p1sJJ#O6gK+sk+xJO>X z*QYoH#I|RmwP$GM7fJ(8NmE`?TV7$-95N6Fg?(O=8YS1@`V~sA!1@*#00^CUOvMeB zseSBQWczm@0~;qT8Z4+l{ASD_tp%RZi>wTSCY*M*IB}=uewB=4DI^v-<=(w zlT8mztmRo1Du}aho(8}ElpxB677Mry!i(F7DdNaBM|`X!w%I$ri9Q}LyS~Ajp1tjo z5d@{<-SQ-GfkSFb8oAgf76~s7|Cxk{w{wQ4+$YcHvamH|Z2)@I6+u;P2Ot%wirk_6 z0BvLwDHTiI;>XCYOwl96=;V|UqLYe|Of!o32>N0{&3^)D!Zb*I$(R zfAZ_;-2Mqxr27X}-u@GdLvR0o!0XD>Q}R?(lByDtvJ;aNv}2Pq`$~^fGs^a~luC@u zs*H>c%&d*f%xdV2kOq9Uy`STz8JE7=t04 z|CF{%DAr@Y5X%>2lqK!%QIWi(XNl1l)$|!TXi7M zo){E*mvAjx*_@2YqN)4TM3_l9j?ANMA$G{LD--m-NEYvxLk$dEQixD|c;r$l0cO%; z9CuTj9JPCdIdx4+F9Nw98zH#$m$r`0Ns%XF@;3?>C;t|8{OdpXeC_{J7~xa!{iFK8 zzbXqDSzG)^ser$3j~#tT=KZ8?DSy(onEw0if`)%Z#EqPV?QCp5A%Zd%wkDs%OxI70 z{(ptVlT>s+nfYjZU~myM&7n3`+p|cA1RV%v+kV3dxNR2FF`mUe|3-M_WJvKfgba_MxO;Fc&AQY{-4lU+`y=o`gKO z@ICM$@I?XcL%(!1O+t_EO5nAC*YmZo@Kxguz<<)stuPilVX0HqWt;qoV0*>*TMdkDTiha*-sp3LP?b zAOR`-NZW9li*1_jgwtdTTE4~v%WB6Xc8duYAwVL63~#=^IW(YJa^8x5iH~+P>WPkN zC&0i;uXnO<8;S|7>m)G=yOJvSoa<*ZrG+u0o==^}kM?ek*}4(?ic{`vvXFr43w;ar z{BbB}Lh7ph+Hgy(b|INkII#sn*o+=mRl)}KUp7CMB>Q`90Fy2&Ng^=6B~v*i_6QKM z!#Prs0gIjFfJ-uw;E73*r686I2YI;+A%r}Xw*ziLVOOV>8UNRL!@fzzP94t17ms+N z1{Psaw?E`6)Obyc4_2D5G~d1poou5JOHbvoNp|39im|J;g8UYgLvu5ag3`yKX(S){ zq9Gc70hE?Vr!APSQq0c(Ev81=@d6hYgBhBQCPiu{7i9R6~sH#@ZA%TU6(SX zrr+}Kl&!y-BJ&TEnBvbSc=CDuEu{Nb%l)?|s9@mu37!8hUp6>W@UPMpq95i>T5zt1 z?V(n}GYV+nqJ3WnT}$aKKqY_K)ARa=pepOM+wK+8oTKrHPve9nb;I_HcJoOKKO`j2xWK&4P9U~HBfTN9ymDTn-VlD#rFs8tq*4-s z!7u&nc2A!UH1B`!cK`idWi6bXENso>?f+Vt3p$#89@ua;`BxGnNmqVBA8q7ghP}P& z+&Gu0n;A2)i^wR{-=92yfk}?FPd`8%sWOcXs63Cc&Cq!}jQdWcCy`Hj+mEyp!kk?~ z=Y%UgoJ@YnB|r0$wbJ+x5MFK&Iy%#V>Y!q10xQ{41vP4FvY9B=ln4{<5F6ysx(kA| z2-67T!)ii~{l?rSLP`gB;Ny2_pdL%x{t4oM&RTuNQ27*1vEC+A)Ly!3g@Ym$uF%sv zdGz;Ws_}4Q_$Q13p=QGGwh6@brmB=Vf)=ga>Kn_KCEgo_3A^=815>iLxJpQfq*ri( z^Y|XdoYBPP{CCZ|2<2KA*`ng|)MTprb}cUR)+>JEiuH#nZ|Dr^Iw}#k)v~q|ZFB&} zmI~$`QU>h!WOG4lm+#L0k1Ov%WXp68Sk!aO+e>n7Zb%C_L?&V62_5-DO=eCRiaKT> z1NYs4Envw3o!H4#WM>iOVxRZlNI;_zi-XivwN0x$0sSQ|yZsml1zA!d@)#x~fxjIj%rIH1V`Q_i0LLMg z-S_<{yoFY@Tnt{m?~2hge_G^|t}fsVFDgP7yoCutdwQ`3(*|- zIq~rQZ+gH#o4)d=J!Nb5*+1+JKAFw`Rk$TfW#$vvjP}R0-Ne8q@2)_C81Y=Jr*~mw+j+EYB}u`1(rqd(w0R#&WWp|B z$PHMNN(19wbh-BdOX1-@n7Ijh#3*mVD{#;wTkl(yI#!M9eD#)sWjy&fw@(x5ULssc z#6>Gu$jRrwUxwn_gEl`vumO)I11N&ZVfDWl%BQ}s9}$wZv-HMhp3E1>l$S+1 zt-a=Sm`z;W)Gg#SL65?K?3ue{;hpnGxL2HMawPU}KlSkI=)EM`3!0h-`M1VpTO1Un zt#8Fb@jR`<1Qd=HqdW9-6C@#C2Nq@cB-v4+J%uun){c2M_^%}I^o*-#FTYr9^h-43 zDdj?@;uAB}7}?kqcV+8&;}d=*vj8ETVTa4~qwkn_5pNq(;cN(uj9JhKg}xLV@DW8U z5&`wU$j81w{9gy|ubJ(H6yZ+%Q{g;6I!tRD@#FBvz86bS^rg|D%46+KxhDCYi-eQXPn}=G!bT&Gpjc0)|)ThluVM+ z=yU;^n+MsOzky%x{@lJo?!Zr>!mctKY={Cy1ADoS14{S;Ui19q3Cl1QQ9R#O98g?i z0N}yWT&CcvIdHBSL!`x!&S(}zM-%>H!sV@F$A-jNH$gjtDbx=_q9Z8x0ij+g%+Y07 zxTC?a4XI%dXI%P7R4Mt=JHxb+=H_KRI>?PF?!SxS$))(yUY6~day9cMe-)vF7j;jn z^j5dsZoE#cmVHT73^Ec5&b^OON4fBw>X{H3H)?Jbf%ABWGd=u1368Iu^~*VXp=04n zMo{nKJv^GMg5Bj1QSDb5Q^ovidJ!k3kuD2-1+y9O1lyyl<8t~Itu3dP57=mD0M$?r zF_|?mSr(39<*?wo!vAj$`Cnf}0Mq3Bn;HB zaz{Hv_w6xG&?E-~1cUrkD@l(vc0&3RG22L-UkLb)D-+qcZr~;Z$-%Obwg!GNB&B@` z)SG2j^Qwbh_xve^D%82CSDXK9IbZ(c(c_iZ=XE=$iqFi{wIKso8z%7kIO9I+db8W< z_w?1!N4DRW?>t*cbr5dVxn#rzUyV>@u!%JyCGYM$^sM#p^mK~lC9#l5cAf*HFtelqM%$T+vi?Dh0-czyF$9rpC*i}W(F9`IrQ>+&vj!$LyHN{Jw{M1AUTy zCadsJ>96^;%M~g=`PfJPR=7u@K?y-?DZzO*H5O;C@d^ z^UJ#7VOEwcv(#7LDOcwX@(jO_?`<`LJ7=F%0$vealnikU{acm62CT56Ne4Fd6#MX2 zpRbTu#Is79%e0>CE;`bM&&f$XAx#cdY=<~u%lrclr`ALMOoo=W~gYcNZIV{~UEg$aF0*BD6^F2>CeNnTX}J9!KzadQ4kmp+W!BaJXAWmzmGO z;VImJY7~a)7kRBrO~zWZ4t)B;Jh+9b;g(<_o7%1VX$i6#*{`V}eE?ij+b(}oiLiM`GF^xIaP zh$cxnT+WBNek$mL4O0u>nzmnw0Mw~{Trdr=(?)WAPVQp;_po}s5wN}^eJAS~Qmv3n zmSXJ%awpB*#xD%JPpE%#cVaFA1$Kp^uix(!ZEYwRjai(QJT!ww zGyG{hjDm>Z>s9HFcECK{>|}*xjy7b+ifoK~1-#|C8j+Wt@+YBh)}llrKbRjfnnhv6 zdDEHg)eKZ@uedah3aW?HM3l+fg4Mf*#WlWQNK8^6ip9gv!9b*nA&ND&G*YXpSogV5Yzx zd}qFZR%m{Y)<1VPi>4-00Yj5>`)y0)JSo0OZVd>!t1RCe5?&9l)aPwKC-6#KD(u)v^$P!LaC`wg9Zg-Sdx>5z~nU0o?HDF zb$7RZ`MtuBQ#SVyCR*tyU<6W%o3|*}{8=h{a+J!f)14|pAal2e%%;%YA5T&a!{lOA za?wQd#H*@3cSY^y4<7rg7RRp_Yr_0F7aYPz|CwO9LOWj*Zcugf=w4djSFa4yTNE{I z(cYy1(;BN++>8=Mr?Ypz7eh;i+`!y;r&Zn%ZmE%1i2>GpS{t0GIC4T$p@3q+PP#wc zE*LhNu*^rzB)-#wUJ*?K=ZX-nN#G( zvQxf+5P`?FGw~;aN69qAz+_A#zBR(0qCM4`cOA^xMcR${(JNv2d=W#Ey}|BOE43@^ zHN$tzHPiOg+2~j8`wpql8y(4dWc+Zaj`SI^8%3_8G=iBx)sxbQi`)B+rYEVff8zop z3WJNP$Kq^*mAq@i{LS&j2eQtX@C@DuePG@#BMJ=oQi-2hh+VqMHnq8e7kDjPbmGIN z1DM>ZGh0;~v&FNDK3YQzRBEOLQl+Jzp9N`@ugd9G@vP^SRj@56z--J`3KJY99JRKy zcq9~z5-q*qL%haz1QXrR4wK%Q>^1td^)jMd&jv8e>*7K_;gsT8P^4R0s_9mFMjI?e z{EQ+}Ze!oy>WkC656{B!h5h7=x|Gij(?P(fAU-?SY0{v1ERkP>8lP0-xJcip^A;q1 z;5VIO7r)lPnQNMxIMs3DcyIw^VOy0<#!L`|W zQ%2pQrrgDMIh+z=vK|7^T2$*b>i``QW;o|~jADj}&?0yE2HbU)Ic*d3?62EeUF&ik z;e{283NT{q;HY(Vp8|+jOW)hPwQ*Hkw&Ghh$@C4dY-8-wos0eH1p@^wW>oVp<`C2; z#iNFr=3tMjl@l0@es*NFs$(Q^@(ekjU)*qQBnf+im!rY8bc@lR;=N#9&%u~M6vtXLu@~Fw7~zShp5_G z{r{-wF4YO8&viT>-`F<;=I_wRx51&5W603Ec_g7EMMbJ;TEX@DE8mp&PmBTSGKoKK ze&|S`$53PX`hV;Uuk=UZacJAScuW;bUlFZ&9W;8e19j&sh)*|LUed_I|VT!LOhX3N<96LN9k=NMEKN%O^5{6`td^m+$qtxeOq z$`^t9t6rAz5@7Nd$IbWizO9F8(eEjlbcyz;soC2mCtE&xdX7<2k}Z5n99e6*wMNRH z`{8FBTk)}8%vlyK^5I5=^II0Vwi}U5di$h~<6HI4Ookj-y*Fn9thFAlTXyx0d{i=e zsZ<8V*kW2=7ABT6!?kCx)AHZTjJUq;MNxasQA~D*+kR7dASx3QObIuD7pu$NBgZIc z9b$Z%S?FV2LfZgYTp&ue5jTF_WycIRU^W5Hk=zGJ4}bQaV&GG>S5z`DPCEt=!Uj z#*(`$O2o?LO6V2vwl7at z@QRC!_!E(eb?t8&=QxNCW0SJDE^1Dw=y*q5K%%iKKe$%Y9*?T3b|%3<52b@!NOT&J z%ASlb0J6cQv;;*cpgdKkiawC^{TNFOEXzpZH+O{U@O5MmQx08(+}!|Lm=T7h#+%Xf z9;>QH7%!@!wW$MN<=fv@pd_ASTJfL$R~iDy-|I^J&GG){s`FodubQ^gf*SIlM68KA zQB?TBT>>J1qpzD7poxVF&@JC3{0k+8b4BY^#Z}^TG>_(gcfG@PK2#kRAvG%Z7fw3A z4hoySQoIVU`--a>uhmNzCxlIBFJ%Mm+m`@as5+nZSZ&)$&9$8*=1bxdA3e^ z;Z1`dirpv4?7{9~HV5f$-KB>&U^W5NMuKAe(bH#T0kN#aU8IHi?zF?XBlhBy+fjYU zeWCZKTwK!~xj%nl>I4-2v4$O+P;~v^>eG(D?pt9zy zRCBU=@K~i~#-dc{xoLO(_pDV34(N7s?WFn2D_SYeP3ZOdh_?JH40yT}j)%?CrpChb zU`0oWPW@S*$G)Ibi z0o-p_#Y^7jWw=dEjzjvU+Cp|SD$WJDFp$pkZdnZlr?oX~c`~TW76Y|c5OvKZP@DwX z@9OH%5)9Z{z2CaI4YUONO*vX_2B{W*luoTGv<_IM*BiJ0qz#Z4U-%eEkshR~Fg$L$ zZ_o9TA3ck`Dc>Qoo^Qn1&DYX1MuXs~lNQtb8Q2B;7%DDiP7QmtmmT>VmOx*o@Ava} zAvYs=WAD-(QtwH`Wu2IFlV+Z!{0-PggPs8So3a2fp;!2vh)c`|rXN;9+xmnIP1>;Y zSo*uiR&Mw%KMYm+)StEbI7nQ#BdAqFyd8I=lihTbCM)+`e@tp{dl9B(cX&qg!Tx|i zHEegYsGD`^LeeoEt4+?qx$_e0m?=eB&^-$&f(;8`M*0Je~WfkLFTSB_qLr#Un;^imfV0Hb73uErgp`POj|0alOCq z2;6?9j1Mr;FKD$Y=$1vE+J3sv$+SNN+ZwNSl7*#zb=CA8CPVdzy(6~t73U$*VKB)S z8s`<>*i>#55d3z}vdkygSRB_t6Dry2Xb*vpN??c^+&Xw47B>M`c#MUZSFvOcxp)j|3z&$SR; z+F4&$!&qzrgX|iVBh5d$!(2KP9!K_ZJwgl+<24>IL-rA_$2y>yBM=Nt%6)pSA>}N6 zdUDMtMXA)g7bGuQF0TDFt{hI0j&j{0cpgC#zhe+YGGG@wHfo-Vj(k^J2(_NmY|f4y z?+@bh4vx|`r!dCwZ{nqY%i!F7A4?nkS|~JayO4&{OZwY=*oOe3gkg=-M=RkJteO>H zx9zre%h8!))600?Dc=KK5{9C)wfW8x)zB1TgL1jLRIa)gm4Pr}sSZ?C>Sa}FYe*Z{ zEN|>}-#clZO}+gO!+*NHnbtZpC7*6@@qbU={%utM*FNU|!%|FA()}xW%h#aU;3_NI zn7-#0NhL;Qi}vFiiTQW50N6O*XLd=z<*2EeDFxX_K~JH4F#j{yYeBdh`xg{A3s-{a ztd8UC2|l+!Z}0E$JIFu0jcZQ_hKfVtLu>#SWh(QTOvdG2HjphSPvFAcR7tJa4?IHK z_i`d>L#CUDiWycG*ZYN5-D5!pyN_d|8bF6EXdv_EY|Unqk`M<;_O}4aktvN3!BP(f zR6&mT&mw(KZD(uz1?}TJaohvmm6VG|V(?RKhW z>)r?39>@;pkaPt_u;Zn z=`T`(jm${Y`Pw0ZjG0Uy{rX-ce+I548vA_wL_#|j1Al&oZf#_zEo=>yr=mCD8p@x- zq;)c(^%Xja99ruciXiQm;EhtNOHQsTc|)*78aFwyHkkeuM?s71ODWI!%= z2v|m57c?QM(^v2Q8GhBo&XLYV7X#h6)j`eqjB(6R+=6x^k3=wcr|#4-kj+M?7<+U5 zw8e7p7VZ2Iy^ntDt7_g!F6YY@R8m~sXJ{j!(IBsTbj3DT;DqZUEjEOP}W!cw(XdQd{t4{@N0BwKhO zeeYB zVc&2TNFZWt5nZ~pRv(mNw3&)Drj=d8&|xNdkWhjw46#p5 z&?EOXo>8;KZHAKTvolyyERY%)Iq)!jvF1)L!DGm9k^}-I_dXjpje2|}0(^63ov+oY zR&?O}?)PwY71kIDZek>DCOW*=tV#3yX#GP0HBnl1VR<;JzpxB0KQMvNnOW^N)yRsP+0ZKbhI5@cghs85i$Ah~><{GmaoK>F$l<7@@m zkNf-6)!~Os~H2L#;zXe3dEjx@Z#c8XS=1y?F zKFIG3e)}7mPCFz@&LA+z7;#~M`-;CYqK`|S+3bCN262^o!+br+PIQlx3pFEMSs6pr*6=;25LB?-~(_9{L z;s!oQ1Z|C!UI^bwd9sS>Oi4MZvcJ0TAxFFGp2w(1t!OVzh;*ZFN#Q3V9*cpG1QVze zd_!ElcJk+yXeETb@~Vg$vS*N~^w-${i}`B$ibQI6wnDm7F*P?T=998nMq{|rK@F@Zm<3U5fGY`% zXmfVDmWWt{&b<}QH4l+yWm!L#gP*m-_Gr7(NsD9Js2@Y;?lTHE2c|9DFQu#eg|WON zj*MHb48iyGp_&zy*mN5nEq*XsWa2q5ty7=Pi>+&i5e5{Dhl+k;c<4(c-C&PEu#CAu zc8YVr>+DM_C**$?v4OEB7Ktd_2{{P0dNP_TyCE)-isKd|;O3*`C*#>fd_`_I>Teq+ z+2)^CZHq`qhRZ8W97J|DcipI)7)TM`>y52gDKDQecIrjAPxt~ zo^U*Bf?+AH-dGojd#b%dDvFGaVKNKZOEeI}O7KYekg5q097f_!`HbPoT$L!y-GNCd zfuOyJ|V<~p1&NNY+KF+1* zZOG=s*BI+0srNv0PV`44+OjL4SK=?Xw-2P-K%cvVEXvOkF4w{tXAD#_;kASq>DdDs zp{v*fic>86eSyX6%0QB%yzR-Vdk6%P zX#Go#)u;|e$@|xuz^JSIpu&Cp^gzpk%q<`%7Hj$JArr@J{h-k@-wqs#|!ZC8>KY#S1c$RQFW1-Cu({B=)HVxRsi2fV}0A7ruZiglW8%MvYmV={vSa>gxq*v zb!8uQfM6lpZxYLeQD>82Tnlo=Gnfa$JcoRgP$qlv<=F$pCQ1>*oX{rC$$l!w>V-qT zT$qeZBlGYE0z=h;?o3 zrBp6&42|3-X9WWM!c9sqJ4A-BRQKj_ONI85_C_Q3NN1&PmPq4}XTTzm&LaFHaHs;` z1i#;I<-ME<;-nx7eCfU5r{gIx9exFgj$2kb7h?C>;82T7^15Lf7izUOA67+i~zUjk) zP@wYF$hNr9`Dg{tazc^aAcq(`4G8rwb1S@0kE6CkazSzQ1)O zFT8x>g2ZU1TqglAUV;EjFe1OV=}%4geW5O>ZL1H^Bh$CAHMTQ$(Eqb9Ql9)@4zWyb zG;2E1bvLR#A@Ow0d3QPl;SxFmBqjor*U!LG4d%@q5&-(0o@+e`$v1D^u0%0UX|ScB z!H@+LU3W(tcSpG$uXf8VSD!I|dinghETh;ysW*3P9IS#}gGr{vTA{alfSx1=6}wK* zJ8E*6vpTLg7;Me$e#c4iH!gkImhvR4_TZg7i0Kpe6d3S4R2l31>Ni!JHxp-ynWOr2 zpW>J-nq!&PgF7w(k%>3O%FUry6XHHK9lGe69tCI7mU@@cbjtWKO)2t1d`!?XhSiV# zfZ@m0)T`C#N;T@Q4{c~R5yF-UhtiJA6ME+y;1sz|2ooqNRqEszXX}hL97RBNn@f*{|d*bZD zi={%gD9boJ3+=+CHW|j~4=l*wMv3eolu6AJ`Z~z!VCf7kUsf63=wz^USJV~}2P|Kj zFqnx%?#vyB;m*c3@pN5zAJ7tv zIPu7!u_;{rbp-Oyt3fwJ0s`s<#OWgY7rphnu}~G-NnyHHi~5{BHugD5G?4F0BKQH_ z7$5%0fA0pGBMr*Qi(}Ga__UJs4nG-v){Ta7nUjsiwDV-l%DFC7rQU> zn4KP9uBb1%TDmT}n5yr$UnM0COTm#{ZEhZMyOy`kEF7Ml);g|yxoJceVh)wvnSi_V zy!|4~gFmoaj`fu`;Xwxfa4Som^Z4yVVX*2ZPMV#uCMV|6%zT$t(hT#JacW8*=kC5j zM}W-jOM%U3PSmsaFGqKMUcT63+G0}MBuaz(gn=J9ZTvEFa;|)m1n+c{Y5N-FRthCV zoKv$a)?I^!*l@rwBuwh^jM->l(%r4Dm&p!_K6DEyT++Ts=gK;%X8SW_e+bmA0+cV+ zI+r|8wUBJBg#%tjm+h8(=9xwsnr&_Gxt-eJIg3`Nb-2usQpRCEb=N+GkDN3T2cbHtjVCS}!+3ye@#T-t26W&Ci0RsX6Cdu--aVtL)mO z)qg_eOlg_!8_9sF-&4mShPd60FPI zJ~~2%$)uN9F1(&Wx{OJ8Cd6tOs?X9pV3dXlJ9yfi$+d## zhb7OWZCPh1hg+BiM)E7M2Jm`Lb1h|PWM?goiy0<1ZZf8# zCa&0MK(xoe+?Y634zmSqXWP$wV8Gr;(I~~R@LQWTG5levz*@>-N`$TIf!M<`W=jUl zP>xN4N*L1owyb7uHg}|%q^LB&SiUOVjN_%_A-W$pl88eC0^hh4ydBMBsD_ofC~(cM zt42n&FhoUK4bmgH*b}Si2_cK^$3v|JvMe1$9f zu{x7OR(ixG`Pj-h>MH#XR0e9rey4he+PVT7*4cZ1&+q@c&(W~TB*&_8A zeqBU^!PCXx<8O($cPt=a8D=M(BG&~O5sBHI{Tc(q4t?2tjK66zlWxo$Y?wrQAk&Q{JeJP7`w$7e8W&?R|_(}%PXF1AOvt$rz}j3OFQwmJarzxTrTbVm@#oP}AEc=bMYx%IEnO>%?rc1D`G zb+45})SH3B4YK;;ZgZ1!fPhTAU`izo8fX|ELSyz` z%y1SDxxIF8BGOWk=L>a7gec9Lxa=kJ{_G}nu7^EL`F#c`;JQ5q5D;S%noB-J1ZK4g zA!u~LN$tj;>PfIo4u-ARk?2^})k27kO{Gg<$wiaRlU0_&dP5ySH;;Rms0x*oYgOwb+g}-6DftAw}7|73aWwqB*#0Fk%#g=akp-mZ*fc1z)Y>^KLBh`Q##f>rQ z-}MC*tYTl5?6lfgzD@HszA9)Jg#{0hJr`kcbh6^y8_;REP5o;10p*4{A#Z)neJ4ls zc7GrDHQm>i{fM5@2!43TE9(}k%#x3s?-f;fUB+lVeVcX+v(N^)%Q2CUVxWvR*P1Hq ztde+%o;P*yp?+CoF3Y{J%gcFW_AlOJp1JLfOgiqO@C#^@fOAJr&&x%Hn*qL5ptsfs zuQ4#AJEnTW?u62?WYLRNvTS{s>Dx4ptHdjk5XXtSdW&mtt<=~mx;e0@Cl@TJ+RVQ~ z?qHXcrGmykp-G^^&~NhCBF&sSK61RVw4^dSqe7G&Dxt(4zd=m0H(6KlK^yvU_;~Rw z%|K5e5ks|gb{MDEmT#sy5DlhYrFmPkBb>Gr0l(a8CAo}1f|Poak$l!oZQePUiQ1uZ zDY-Sj=>k|2$2lWkE!Kw@Pkeb<5=Rk#-k?YB66SsRBC32p67zXLiIsYbravW26gniE zP^UQf4)x#`Yka6j8EfJ2s6z;ML5Iw9XvK*}t90VTh3x3E(M$el^+Y(>&s&7nY`S~H zvO-2^RU{uJSa$s@7GCWkuYvDp>k1YI`uc?7)Z@PuF(Aq`A3HBmv1LwlJ3fpf54(k9 z#ms-#vRG=NpC0`@_A+0kkN6p6`^}VTNcI{37tZ_ep3pK}o-68s4rqQC2$*Mw`*f7Z zsf?}!b1zG?$}noMj`gH*a=XHoyYD-EWb;f7UU6j;Ym^lqFd76Zshwq(OcL)-*D<*r>u&zKlR5PU!Ub$Q6^?!y|+2b^6VOSt-_^ z%Zj-Kwug+V*7zm|^-FH%If>ATTAX%Y2v4`;K3YdBfAuY*jdSIZdth&*-na%thggU> zP55NW&^X>@q{{1@91&BWP^0ykyA)$7v^*l-h%!9acAw`0CMETx06Yk#7#z8THCA+7 zhUPF&qhd0}h4K`maf~H-aJiLv1LF*6Q$UPNE#MTmqBsZAE**)!*B}OgptX6AFlbH` zelmf<&@?UQz0J^Ih~f)wfk>SPh`Xxe^0mjV3yem;!b5_K zkI%6kdAHdv<@x33tG5nv1oE{wa}q>mujS?BRlQt|r39Vv!+WOtjvcSZ+4BY6Ub}eY zTaMje$@;HO3L4^Vkbg<B<2*zN2goBm-=O4XuI)X% zz8YgjIC}QMPWaXS^%mVpR&{YJt3D!y0YvG}?3bJEHi1&w582Qa?-gh{CC8h%AzxQq zy0%a@4Tu&V(W81d;YXNj=U5SLFRQZy zcfd)~HK@`fUIVR$Ge@wFD|9>2YRaIGqp3+MM+JK>8dKZLGigfG+99ioRVoRoVslF# zUm$_*H`j!FfE8U+2;sj5Ps^r{%!G){lSvojYDmo1kg!e{)m#$eawb0BFrOMpvm-st zE4~3bUKcf{$4dbq;}I=4i_+P_;=@A72OQtmpG1$@Z+u^ck449?ZOtgqVY1@ zZ{+Z~!Beiu8ARl`GonjbyIZ{;AYB-|Ic*t;Fw5UH66Tu$L71&IVN2jhJbyt8ssWy+ zx&@ttD$isCH5DnDR49BffwHnzO;I)ANC) zqJa+%=sRO~U-7z6>44p9f(o-b!H}`kqdQ`HeCWOL)NHn# z3#r4>m3ZUNbbZ8LV;grw{=x!j{nk}jl*AJdC!ymr(jA)7k^G;sgLduwG1(3$&BUS6@z zUh0GLzCvxTO~N_kT6+R&_HD=U$IC-^yI{#ZLn4B$OrtpNPzNnYu)JlGebSoAke5EP z(|yL~wczW7k}q&ua+zxN(p0h{XNtEaZj!t^hnDDG$;Sd4O*Msc*C1l6A&8wABG$!s-l)&{$j{CzLL{$%t%8a?!@hpW!{iWjf>Yoo7&hK0?1+v^3&y z&upm#Spa!u@s;{3_SKFk@3T90D$j8HT$j_XI$-pnJ>Cvt@Fo9`Y5SSwd!D{C0eA2~ zRigX#kWuD=`g*hEgNM(_;~R>Wg-?Rv$IJMlT^+(j35&_)LT~O1YYQuAqk+Xx4 z`4!k>wiaW~7pr$8UyIR9jtj1LK_-i_j(D&E-S>K^Es^9I(%H{|quk_fUgw4=P&L2P zI^jclwgL@I zdvSq#qc{xFX@(SE7zCq_{GR1L4(La2c|HzoaDIqXWy|ca1$miYg`gH>Nix5p-6-1- zk*@|y-JSw;V*CLbw`dN$>57KR1!tJ&%&@jw(lkFDBB^A3w<1jD8|{#Q!?3 z%>XaRcyw7XRr+3S1RH@dXwNIbnm{#eR2H&ej`zEwwdyEV}2i}E` z*{yiz!bZG-S70@4O}2YL3m<(S$ZFVpEpW#!a4k=GpPX)f1J5&&12C*o0ye^#{)MTE zgx>%VPv9>%2;0BxR;BO$&u6;tu^#(y4-A_k=p(cbA9P$+b`XP{8^nMRvR!ZsgQF?# zbQz1I@EP%qrW;|fM0PNK2fY5v`r@3bXdeb?myaCRORF5aE4GUn?QLIyUiF56p-y5| zCGL}pD>D=mhC9QOp((^E(lBlvcvKH?7jHPRb~*K+!&VbEY%drr+Ygg#)R>vtuNwLj z+76wiuCaD)*;U<3y(4TrPzRwC>$-EOHV7?f*@@9_*qCip-|mcd(USsKmkA~G+|_>@ z+Gh#ecb(g`<6Ng=?_8`OYl0Vs6N*VjNVaiEd8iZHUOtcg44r?mpPo_Exo6d8a$Bow z3BqraMah5_^R))Eo{eTK%=0#M!S@ZF^i%PRa>k6ASgfv5uH6zZvO{UFS0g`vyj^KJ z{aQ$NtqkVqIvtNghbP{n2u5FmyPg<3uw8)~mj-%E#UzEJ59wRCZW-G2wIjNeVPTtz zE_9eUu*FStC}J&xdLh$f+&i`TF5xk_NRNS8tw;@|`chYF(@0;&-=5lb`oDBMKv8nZk_Bn;-R z_kk)ffhEmn;VKZG<=I7$_-~yzU}T+&u$ab}xCx7_7MR!sK7M4L{Za ziY3XMotWpD>CIu({=}D4bll)52GHkI0hvWyX=|=123Z2G~+6Oe6;8X%oW2>KhkL(BxYwr)y4F zz3F-$z5Umd9m@;Fqw`gITq}^c}ShpKft<&t#Fi5X{#66orY0f}mq9sVL zH*2O`a$4`;_ZWZ5F5vL_U}=7%jdqhF3BvK%i+}YMESElo+jdiDImb%~kYhE|^wpYV z9!vJlBCa~cb2Zu%R=rTRC3wF#?BV3klJX(m%<(U-XUsZ>-i4t_e)Y>2DBm=7>IVv# zMW1ly$tX$|KAQAlRy0P#ghKzo0CVP|3BsS%RKxd4?JVZt9!lEM<=#WHrDl7q&y{Le zGAKeDgVP2hdM7%921ZA#(8vj(3`GrtyquSDx+o)f!?p&}&WFmd8jT$T;x z0ZcEz>y^tj8;@}~m6yq7NSMPSCk1yOPT(Z)0~gnlKE|PKW8U?}pmQ_r64>~$V>$IXD3UmIY)&R|H#^@?lB$Ry3=4u+4VVCNa7WV4s5o?}>7y9N1iI6^pNX6i!4 zXI^voflM;=zo!^_oBH_{4hFdaj6$|fdoVU!XKT`2$eiarh6+PFakM0!_8N4)hrl9_ zh(v&IoM8YSxMWCy4`S1Yso$-X~g7AWAwNqd|hG5-WL{GUJcQm=1cq9A{$Lf#)gT~ z#S;v}RO;QiO)(hDC)^ssSZv1r(Ra|l?m#$^Z7942h>BuC0|9aUKCJ&8E9T#9f&u~q zI$|lJJix(7F(&Q!WU-Kyio>7+!&9&^sgB7QC(xj!p)f3($Joh2ahs8(8BOYx zBFZVJg|@m=8I@TmAZet2pK@x6WM{*>>9n7BZ6xRl?$h&B62@ zAckY(`YMX?u|O&r*<8jtvAk;Cfjw{Nyay{zjNU?Cqg-c)n_YyXV>FUb-#&y zK3}ldPx+zj3buc~F?v-Q+JR^TO>XcY!Pz#CE9ZE7!&9?UOPS8O$O`AGT4aRgy(3F{ zr;#VRyZ2%YK-&gGM0Vlb*^7Mr;kRntx|pYeh|vjhd~&@sZ{#Yev%8hAgp3%k&V+4M0v^eO$__iD zj{53M-z;|ZJTMnlj1_Mv$ZrrLoRk1zj%+AfG^lsdXVw-`ylX9k#hqqZi+?>p`Y6Tg<9Ydgr!N1wjyeIZzZj%xfsGG%lhUg7GP(PJ=HbS5Z$_mP|f zjKg_m5N1o<7Or8!>b4L}gUbg(kK zlLv;*vYe;dW%@M|3t9(sBJS-UsyEXtJ5rVr-y>JS-puI0-puMSqhe#sJwC8CW7Y9zxoj)blmO&LRZU-w})h;h5yZSZ%D#DWIVP{N~Zg# z=#_?B9}Y9y_~Lx#AP|wEyE_BB1w%d^BUFj{g^E@P1)(A2S%!`ITcIWxy?6_AO#zya zc4KpVV{>77{ygv!N3~hvOw)ANTM|v&Cao7(++vM5ustP*^7Fe)#ND^=Xlzm@+?cPB zHeo?BE{DxyRSS<*1**1HJ81=$_xmP4Uoh}k-%b6ba`f$#QfyiaY71a)CIHOMG`|mA zzd2?8eA*&hUj6?1CwG`x14fr-G(;|98 zeI#qU$qbf=5^@J@>3=+Wk%uDgmXyYEpLXiD%E8qB==S*REh06g-m6z~QiMJN@OShX z+1mjjDdIG_QC{i2v@~Sa>K>=>8>ri_x2keC+CspgkX(n&td;rmtA?%;S3dg{D*GMM zQtuT)b?ImgtwR|!c_jE$56}pfyF^rkZ8PSPNOU4;sq!2tujc-ge2U+~_SGYRS`w)Dhz*RzvdialDZ+5wRt(0}qn2 zHi3;aB><1wVEp=)HvtpRfDCf&cFD$@E>oXkXuo|IhE2jpxvd&DiCVLZB(&t>I z2Gc0APSg4QuLer3n>+nUzY@Ifcfe$f)Vhm5G;7%*dPRM|RM66P%$`42)3}@Drw(__ zxR??AVA?dWswDl{&of9HBZ=zxOu6N)ZGjxceWwjpabp3D+zYI#^>mW(ZhHrf-5>(z zlKK0ud!1Z7EBQ(e>e&Vss-K-0x%X5HGl~6cBC1u!7=oBMEp!!nvLi@oidDudLs$a* zUu}mQwo%s6tlw@cv4}CjTtiFNa=|c>Z@zqqkCnJ`ECIJr+ao_3MfgZ(Sh#`r9D}S& znTu;xYq?y9?bKdy3unJFiVQHS+U=)CB$8k?mpb*u zJfbEN@xULK<)?ig|Ct6pe1xFKfI*-VX8V1>k#Oc$5*DIvXULpq=TNsus7(3oe79rk zq5Nfvm7(M_>%r@cWv|lLsd|CaxnXMLgg2S8g;@CF-35QuoU2b;wRd)}53xJAM{(_NQ;||h zB=7)5}m37tuE{8(oj2!aw#7Zh`^kwqF7SBo?U?E?c zhJ=?;(W_A)!T__zak@fEch%1Kr(;gZU6Osh-_F3j8!N|}!oUKVx6oL9h?~pWR+iQq zh$6hGjH(m-+GwxCmHYzCy4~buN!shUZO(OB#@ah{(#CNYNR8Dp6~Ce5(Ufw(6Hn;Q z5r++5wA(Q1>Uo6}KBKqx$+QB&9w;=j@Tt9>V zTEBwhXgdc0k4QJb7s0;@V<(_*U}>W-Vr*k;CvUIwz5f6D`t4CNmq%6xoRY7yvaU7~ zgMC*wC+5qi1;Jm;hX9Qjg%oTa$2wOptui^SH#=`u^bl0ng%Tr4_pj_)Wy{f}$*#=r77`8Z=m`G^)G;3-= zk`1G0!HG1sB@lD4n2bssGhh{?*7ChzJntBSq$5(p5bD@JmOztt;HBkT!7MoNOk$~4!>lz} z8xvtfy`RCruS!rkSIcni@3=A&C)XGmU}m=-=|({tbWzDC2jSqHbVxxrqNa8Q`DnKc zSqBn26Jhr3G(**$f%YXph0JLOIf=ht!)wz?ybiOQbuvnf41Y1;bn>1Q6rG+-#eE2Y zm$Rcv(RhlvOUwQBOmfD9z@&a|650UOI+4YwFj?;*@+8a$-!H=nct-jun_Qq&5=1&l z>qWcKtdZ_O+Y~4l9E^{0rfr8 z!Z@;uO7|8#c$kxZSO3ao!PKri8SIUr0BY*%>iig*b4{leF0DePS~$mf>W#1GVES{L zvuj`BZ`!-1Q@g2&E;6Aexxzqwvs)(n;WOS}U0l0F8n79k6lewac>2?!$sT=pWEydI z%2=4x3D*?FR~PWo>;u=s&S&Y=jdSb5l&dAh?hC^e@A2?H z#k@oQ_`&_=`E%%rpbPSevfC+HfUwhxUSq5vL@np0$PYSuH5Xi?C|?IUnLw`TFKqC$ zvge|4qO}NDofooQ@ly8;f)8NBsuaU2SxDwM8O?lGLOB8-^b=G<+X5h^kjxp9v!mgk z9T5b8;JU|ciR)m!Mj%mba&CB8DmG;+O6!oR)Na*4Y!Em3$EuBX0ppW!SLyIp}tB3Lc5y#8vg&`qc7j%Pg1N~)&IFFn3 zSGJfh_`i-Ju|Ql&-#n|o0LEyJ-^XZqXIndc^M7MgNQ)Vg=;A{O_&8T=URyU~GA+Es zB7iK^?T;RXhW?uF)xJkE-efchGTEfSiiENcG=4`Q61g!#A%C}OD%1JL$C1>=7SEQp zXC2SX5(wbKiOf*4RQ*PP%}_Ii2|Nd1l6{2KTeyqjs~hSQ%Um$TTaj8u3~}YOiFb#}Vb@Tvt`+q2fwGX=^3*mQDXf1&E{)4eX7Aiqk-L z$Ypz+fe@%dCXg_2u4pDs_p3f-6z|Pv66R$_9#y5i_{<#q$0kmtwc{1ArIWT@Mu4z0 zhEqw|76|NL`dA7VH8Wp`c%w|kwA)sIb6l>;4FLy_W^YtsB~c;2v%RO|1ME0JN>J_S zR>J9{Qrr3tQZuwcO@o|}Smn1})OfMBXC=|u(SnZ9WOEf70iG|i)u4)aOpnwaL4Ivg zT2vz+a6of51B^wCzc=Ym)9!c2>fe@^@8nl4CtjgE$WWp{+jcA|Fe9_!(6b)6F=0rP zBqv6hLmI%lHuH5g#i`pa(%$jjZiJHY+<@NzzPQZi^?X5$C(`k+Q%~J?Qx{h~JsyCq zfciwR7FikRMzc*eF&${8Xqh3Bl+!P=XZ;jftp(`0K8%r;IB@UdX@%XF-BH}}xJoR) zCHR7z_0n86)xd7Y-*2h%RaUV}bkJPVBSBs*z4Van!)G)%LdDCjM1g7W^hwAqgnwoqFN{ahS1VOpL#z5IdLpx4sY^qT^T8S4q}i zcEch!1ldo-p-?1KI_Wnvs$Ctf-3%S8n>pGa-0tBB0)!Dqf|w_eP{)0O#H#q|0<0uE zD!djon5YCg61}*9dxf2>W&MKgf$<>3=%-RFrvwNF$I>RkHAoEmi=9bhMv9|z+bRi7 zizyZ5(e!dMF|4cblv$=*`sk+*%^u4ANwsJzLjf_Tonr2aI>$Oe&(*Q1L(UYm24cH2 zCaP^b#90;E=%BclGz03oP30NL6m#Ah)G38T!AykZQ;IOsp+iBbhO^&cu)_szTo}O9 zMv6;2lfXzf#WU!4Nm(Wrl|hOz)-1HRqf$zDy3D7j#jXxUx0GxXVNSlP)o9U}*gbN_ zWW8OB566+!z{GRsSgs;3kPwhW*Pm`{HAhDO6!i?|(D3tmT34uQ&$m{r^J(fd17VBmlO53H<*I809%Yxf}ul$Pr-T0}%fw z>^)$3_+X4=ji5Q#d^XuyB+uBNNTWA~pEw%78 z@58WKBHu!2-vSJJzvdkeAZq%Dyet1D%>l4=7#JJc1L9``V#)tG?|Lr7t1*Bo;Rd`* z^nYg@@T~E^L--@~)Akets709lw~XgG(>EyrG7bc&oo_?N-&c+I0_q>pr7R8qYb}i0 z9EP9*98D|$W&U<9>hG(@+Z><)@`qaZMfUE`#b;lsTgC>wVn={cfZ%UHz_Z4?7m(jS zU;<7B+G(4a{TXe!Ln^o%P?_%lmHBHs;RE``AJ7CWE$zPPZdgfc8(RR3u0PZ^o^}DT znR=2*K>s2J6!n{C!rxbo_X~jN-yfjAcL8B1eO>$igin8p>W7tETm?WC0H9L+4GDPG zc#8`D5%sT^;yd=YO#iteo@(y?4PE2SFY`y-@74O>hM%Vzhd=NL0R#FUO8-mK|2M_M zr?v4^Kko+%welZX{&~cCDx32I&iBoKX3y^f@E>Q;pY!)^ck8L@%@07-xBp!O=PAm! zRNr37Z`U{7n7^)X^BAV~FQxnz!{%w?rz$dkC$I4q`#tgBegZ$O*PmElpTa*?2KfO$ zsry^reuDk}b;?Z^FOFcP5z1MzXYCt3jZ`_`VV+PvwwpB-V*;5LH#M!)8MN=sPygr1=U}b_P?s@ zY5d9`B!Q0qg5;m0Sw1b%({O)3$a-Ap#72PxsJ&ATyQ!hWvYH`V0EcJL*ph@pSL< z2NhY>KT-XUx%BCl-4ED+>VJa$K4ARA2Hw*GJT>h9U>dCdjp^z4!%ubhKMM5J*!+Vg zt?@USpJ2Zi==jD1h7jz91(n*Rm \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn ( ) { - echo "$*" -} - -die ( ) { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") -} -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" - -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/gradlew.bat b/gradlew.bat deleted file mode 100644 index 832fdb6..0000000 --- a/gradlew.bat +++ /dev/null @@ -1,90 +0,0 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_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=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/gs-spring-boot.iml b/gs-spring-boot.iml deleted file mode 100644 index ad195a8..0000000 --- a/gs-spring-boot.iml +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/mvnw b/mvnw old mode 100644 new mode 100755 index a1ba1bf..bd8896b --- a/mvnw +++ b/mvnw @@ -19,215 +19,277 @@ # ---------------------------------------------------------------------------- # ---------------------------------------------------------------------------- -# Maven2 Start Up Batch script -# -# Required ENV vars: -# ------------------ -# JAVA_HOME - location of a JDK home dir +# Apache Maven Wrapper startup batch script, version 3.3.4 # # Optional ENV vars # ----------------- -# M2_HOME - location of maven2's installed home dir -# MAVEN_OPTS - parameters passed to the Java VM when running Maven -# e.g. to debug Maven itself, use -# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# 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 # ---------------------------------------------------------------------------- -if [ -z "$MAVEN_SKIP_RC" ] ; then +set -euf +[ "${MVNW_VERBOSE-}" != debug ] || set -x - if [ -f /etc/mavenrc ] ; then - . /etc/mavenrc - fi +# 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 [ -f "$HOME/.mavenrc" ] ; then - . "$HOME/.mavenrc" + 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 +} -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 +} -# OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; -mingw=false -case "`uname`" in - CYGWIN*) cygwin=true ;; - MINGW*) mingw=true;; - Darwin*) darwin=true - # - # Look for the Apple JDKs first to preserve the existing behaviour, and then look - # for the new JDKs provided by Oracle. - # - if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then - # - # Apple JDKs - # - export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home - fi - - if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then - # - # Apple JDKs - # - export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home - fi - - if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ] ; then - # - # Oracle JDKs - # - export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home - fi - - if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then - # - # Apple JDKs - # - export JAVA_HOME=`/usr/libexec/java_home` - fi - ;; -esac +verbose() { :; } +[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=`java-config --jre-home` - fi -fi +die() { + printf %s\\n "$1" >&2 + exit 1 +} -if [ -z "$M2_HOME" ] ; then - ## resolve links - $0 may be a link to maven's home - PRG="$0" +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:]' +} - # 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 +scriptDir="$(dirname "$0")" +scriptName="$(basename "$0")" - saveddir=`pwd` +# 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 <"$scriptDir/.mvn/wrapper/maven-wrapper.properties" +[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" - M2_HOME=`dirname "$PRG"`/.. +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${scriptName#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")" - # make it fully qualified - M2_HOME=`cd "$M2_HOME" && pwd` +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" +} - cd "$saveddir" - # echo Using m2 at $M2_HOME +if [ -d "$MAVEN_HOME" ]; then + verbose "found existing MAVEN_HOME at $MAVEN_HOME" + exec_maven "$@" fi -# For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --unix "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --unix "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +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 -# For Migwn, ensure paths are in UNIX format before anything is touched -if $mingw ; then - [ -n "$M2_HOME" ] && - M2_HOME="`(cd "$M2_HOME"; pwd)`" - [ -n "$JAVA_HOME" ] && - JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" - # TODO classpath? +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 -if [ -z "$JAVA_HOME" ]; then - javaExecutable="`which javac`" - if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then - # readlink(1) is not available as standard on Solaris 10. - readLink=`which readlink` - if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then - if $darwin ; then - javaHome="`dirname \"$javaExecutable\"`" - javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" - else - javaExecutable="`readlink -f \"$javaExecutable\"`" - fi - javaHome="`dirname \"$javaExecutable\"`" - javaHome=`expr "$javaHome" : '\(.*\)/bin'` - JAVA_HOME="$javaHome" - export JAVA_HOME - fi - 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 [ -z "$JAVACMD" ] ; then - if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" +# 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 - JAVACMD="`which java`" + 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 -if [ ! -x "$JAVACMD" ] ; then - echo "Error: JAVA_HOME is not defined correctly." >&2 - echo " We cannot execute $JAVACMD" >&2 - exit 1 -fi - -if [ -z "$JAVA_HOME" ] ; then - echo "Warning: JAVA_HOME environment variable is not set." +# 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 -CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher +# Find the actual extracted directory name (handles snapshots where filename != directory name) +actualDistributionDir="" -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --path --windows "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --windows "$CLASSPATH"` +# First try the expected directory name (for regular distributions) +if [ -d "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" ]; then + if [ -f "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/bin/$MVN_CMD" ]; then + actualDistributionDir="$distributionUrlNameMain" + fi fi -# traverses directory structure from process work directory to filesystem root -# first directory with .mvn subdirectory is considered project base directory -find_maven_basedir() { - local basedir=$(pwd) - local wdir=$(pwd) - while [ "$wdir" != '/' ] ; do - if [ -d "$wdir"/.mvn ] ; then - basedir=$wdir - break +# If not found, search for any directory with the Maven executable (for snapshots) +if [ -z "$actualDistributionDir" ]; then + # enable globbing to iterate over items + set +f + for dir in "$TMP_DOWNLOAD_DIR"/*; do + if [ -d "$dir" ]; then + if [ -f "$dir/bin/$MVN_CMD" ]; then + actualDistributionDir="$(basename "$dir")" + break + fi fi - wdir=$(cd "$wdir/.."; pwd) done - echo "${basedir}" -} - -# concatenates all lines of a file -concat_lines() { - if [ -f "$1" ]; then - echo "$(tr -s '\n' ' ' < "$1")" - fi -} - -export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)} -MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + set -f +fi -# Provide a "standardized" way to retrieve the CLI args that will -# work with both Windows and non-Windows executions. -MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" -export MAVEN_CMD_LINE_ARGS +if [ -z "$actualDistributionDir" ]; then + verbose "Contents of $TMP_DOWNLOAD_DIR:" + verbose "$(ls -la "$TMP_DOWNLOAD_DIR")" + die "Could not find Maven distribution directory in extracted archive" +fi -WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain +verbose "Found extracted Maven distribution directory: $actualDistributionDir" +printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$actualDistributionDir/mvnw.url" +mv -- "$TMP_DOWNLOAD_DIR/$actualDistributionDir" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" -exec "$JAVACMD" \ - $MAVEN_OPTS \ - -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ - ${WRAPPER_LAUNCHER} "$@" +clean || : +exec_maven "$@" diff --git a/mvnw.cmd b/mvnw.cmd index 2b934e8..5761d94 100644 --- a/mvnw.cmd +++ b/mvnw.cmd @@ -1,145 +1,189 @@ -@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 Maven2 Start Up Batch script -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM M2_HOME - location of maven2's installed home dir -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" -if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -set MAVEN_CMD_LINE_ARGS=%* - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" - -set WRAPPER_JAR="".\.mvn\wrapper\maven-wrapper.jar"" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS% -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" -if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%" == "on" pause - -if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% - -exit /B %ERROR_CODE% \ No newline at end of file +<# : 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.4 +@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 -eq $False) { "/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_M2_PATH = "$HOME/.m2" +if ($env:MAVEN_USER_HOME) { + $MAVEN_M2_PATH = "$env:MAVEN_USER_HOME" +} + +if (-not (Test-Path -Path $MAVEN_M2_PATH)) { + New-Item -Path $MAVEN_M2_PATH -ItemType Directory | Out-Null +} + +$MAVEN_WRAPPER_DISTS = $null +if ((Get-Item $MAVEN_M2_PATH).Target[0] -eq $null) { + $MAVEN_WRAPPER_DISTS = "$MAVEN_M2_PATH/wrapper/dists" +} else { + $MAVEN_WRAPPER_DISTS = (Get-Item $MAVEN_M2_PATH).Target[0] + "/wrapper/dists" +} + +$MAVEN_HOME_PARENT = "$MAVEN_WRAPPER_DISTS/$distributionUrlNameMain" +$MAVEN_HOME_NAME = ([System.Security.Cryptography.SHA256]::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 + +# Find the actual extracted directory name (handles snapshots where filename != directory name) +$actualDistributionDir = "" + +# First try the expected directory name (for regular distributions) +$expectedPath = Join-Path "$TMP_DOWNLOAD_DIR" "$distributionUrlNameMain" +$expectedMvnPath = Join-Path "$expectedPath" "bin/$MVN_CMD" +if ((Test-Path -Path $expectedPath -PathType Container) -and (Test-Path -Path $expectedMvnPath -PathType Leaf)) { + $actualDistributionDir = $distributionUrlNameMain +} + +# If not found, search for any directory with the Maven executable (for snapshots) +if (!$actualDistributionDir) { + Get-ChildItem -Path "$TMP_DOWNLOAD_DIR" -Directory | ForEach-Object { + $testPath = Join-Path $_.FullName "bin/$MVN_CMD" + if (Test-Path -Path $testPath -PathType Leaf) { + $actualDistributionDir = $_.Name + } + } +} + +if (!$actualDistributionDir) { + Write-Error "Could not find Maven distribution directory in extracted archive" +} + +Write-Verbose "Found extracted Maven distribution directory: $actualDistributionDir" +Rename-Item -Path "$TMP_DOWNLOAD_DIR/$actualDistributionDir" -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/pom.xml b/pom.xml index 63f5cbd..5aa53f2 100644 --- a/pom.xml +++ b/pom.xml @@ -5,21 +5,16 @@ org.springframework gs-spring-boot - pom + jar 0.1.0 org.springframework.boot spring-boot-starter-parent - 2.0.2.RELEASE + 3.5.16 - - org.springframework.boot - spring-boot-properties-migrator - runtime - org.springframework.boot spring-boot-starter-web @@ -32,10 +27,15 @@ com.h2database h2 + + org.springframework.boot + spring-boot-starter-test + test + - 1.8 + 21 diff --git a/src/main/java/hello/Application.java b/src/main/java/hello/Application.java index 7cf8faf..3dc25cb 100644 --- a/src/main/java/hello/Application.java +++ b/src/main/java/hello/Application.java @@ -12,10 +12,9 @@ import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.Bean; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.web.client.RestClientException; import org.springframework.web.client.RestTemplate; @SpringBootApplication @@ -23,44 +22,32 @@ public class Application implements CommandLineRunner { private static final Logger log = LoggerFactory.getLogger(Application.class); + private static final String QUOTE_URL = "http://gturnquist-quoters.cfapps.io/api/random"; + public static void main(String[] args) { ApplicationContext ctx = SpringApplication.run(Application.class, args); - + System.out.println("Let's inspect the beans provided by Spring Boot:"); - + String[] beanNames = ctx.getBeanDefinitionNames(); Arrays.sort(beanNames); for (String beanName : beanNames) { System.out.println(beanName); } - - RestTemplate restTemplate = new RestTemplate(); - Quote quote = restTemplate.getForObject("http://gturnquist-quoters.cfapps.io/api/random", Quote.class); - log.info(quote.toString()); - } - - - @Bean - public RestTemplate restTemplate(RestTemplateBuilder builder) { - return builder.build(); - } - - @Bean - public CommandLineRunner run(RestTemplate restTemplate) throws Exception { - return args -> { - Quote quote = restTemplate.getForObject( - "http://gturnquist-quoters.cfapps.io/api/random", Quote.class); - log.info(quote.toString()); - }; } @Autowired JdbcTemplate jdbcTemplate; + @Autowired + RestTemplate restTemplate; + @Override public void run(String... args) throws Exception { + logRandomQuote(); + log.info("Creating tables"); jdbcTemplate.execute("DROP TABLE customers IF EXISTS"); @@ -80,9 +67,23 @@ public void run(String... args) throws Exception { log.info("Querying for customer records where first_name = 'Josh':"); jdbcTemplate.query( - "SELECT id, first_name, last_name FROM customers WHERE first_name = ?", new Object[]{"Josh"}, - (rs, rowNum) -> new Customer(rs.getLong("id"), rs.getString("first_name"), rs.getString("last_name")) + "SELECT id, first_name, last_name FROM customers WHERE first_name = ?", + (rs, rowNum) -> new Customer(rs.getLong("id"), rs.getString("first_name"), rs.getString("last_name")), + "Josh" ).forEach(customer -> log.info(customer.toString())); } + + /** + * The upstream demo quote service is not always reachable, so a failure here + * must never prevent the application from starting. + */ + private void logRandomQuote() { + try { + Quote quote = restTemplate.getForObject(QUOTE_URL, Quote.class); + log.info(String.valueOf(quote)); + } catch (RestClientException e) { + log.warn("Could not fetch a quote from {}: {}", QUOTE_URL, e.getMessage()); + } + } } diff --git a/src/main/java/hello/config/RestTemplateConfig.java b/src/main/java/hello/config/RestTemplateConfig.java new file mode 100644 index 0000000..0ef3329 --- /dev/null +++ b/src/main/java/hello/config/RestTemplateConfig.java @@ -0,0 +1,15 @@ +package hello.config; + +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.client.RestTemplate; + +@Configuration +public class RestTemplateConfig { + + @Bean + public RestTemplate restTemplate(RestTemplateBuilder builder) { + return builder.build(); + } +} diff --git a/target/classes/hello/Application.class b/target/classes/hello/Application.class deleted file mode 100644 index 245a020cdb693ce4216257a9f5aa3bd787671f48..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6460 zcmb7Jd3+RS8GgQ8v)K%gE+mwDxHloNlu{_91w%+A=>|$RKoM&@*_|Wejybqa!877`CZ1J~>+$Ruo)gCncy0rphv&!f0=!Vci{hxqbuqkH!AlgpR6gBU zk1D(@4iz^w;N^Hl95>^Z1ckmfhS$k=uaDskal8?4is8))-V(!GW4JYjx5e;wDfJx< zSc7*aAn=|Bych3_+w|D8Xh+6b^-NxZZJDwj282{YY4RYG)3Di3=i4*sBzk|PoyMGDr?zBsy9SU z?nV8jf@_W%hfT*E%o`nrg5~P2X%!rSOCv=M8hXJ=4e43evd2<-nIY9ta;?**ZR9An z?lQAry1Qt2vgNQqO{bNkZS&G*!Ps9K9W?9#o!UH)vU>ioZkzHsSgdhJOsb!s9x?KH zE7egf=FO~U6eZV;>SjTpIe9F7TtB6!@_J!7m2suJ?NU`t+P9y6OW`vp$gkVOQg{SA ztJO1qRPD)< zB@;R6{wPD2PaTwtd^;!O>e&;0deMuOf&&V^EHILcR5EB;ZfX`ydrD?LM*y`%a?Zj; z1C&9ZQD8?T=i|{S5FM1s5QjjuhuNgoYP-awAB%Q#He;h*^9<~?Mo0BRPU4XTQ1A*V z-gPEx6g})K_zLsr5O?mOq68Du+UTRH2PMpY^9Vg@i@*rH3AHPRZmI$MNmubh z{7A*+*rnpf_=$p_s`!~S_U9^ofrrTl_IGs* zbWJBsnmH}g)!);RZqtTL+i|av(A5ri^mp#-=ud9B zzOQw(wT>zhVm^DIriukPrHCd~G>e4-tx=^Fz0t6;qKGHAzEGP8rVCC2Q&m*nq6C_} zRoUA!2h*YT*=_OLL`Z|cV7TRWG9*rWRCkPQcatX5POsa^Vhjln%;zo_>H?WD$2Hh2 zs;!bs7yP}3jpRzsZ!QbR&_~JOJ6yTU$wRg-H_sAk3R@j)3bKPY4;!u=81@=NvXOI& z4fgJ)WJ`owla_f!)M4BD827&#$FgafN>SaG?RPDK-UyAp@!n=NGjfw#V2G%^?ZsSc zvPUdPwuC4GS7_JtIiGf!g&}s5?NQ+IkTy#v59U11mEPbckfO>cA+zwe$Hj$WQ5;ob z@hmuxK3gzf#u+19lA~;$?#PKrU~R?JUKyiuDb#EV6{6 zB!|J^9UEkrm-BF1Zr|n6oB?Imk;A|&Ev}c_7AgF22}H#(obMp40?B0W%q}x?MP{jv zDIL|B{T+`l4w3q5y^|B`XnGs#_P-kVZunm?WK#&4;&;-ZLxn$dC}M>wG_gj-X`E3} zlGD*iIqe+hP=Fyh2&|fdgjqOcoiI{q?|8*YQV+gY5Qd{uPl{MakJFZQqQt6Jd*ngT zGeDmA9t@im$n$5?eVlkXcdqdn1K5V~67r{laeybpF!|$u>8t$Tyx~*?k~{T$K4bF3 zfg;v3&@s;Zr?&aRpb%Eb96BOyQc5sA@fj>hztcNz{&` zZo>o=fxfnLh_&tCc;B{~>TR`6wM{j*V&TT7+ATZlNVuqugg4ZR+a7!P9@HN_i}?PH ziH3w)eJ|#WWA6P>ch=mAd5dbs(Kvw%svwQ4_Ke#^AAqG)y&UtP(ae?fcoo0Zt;VIi z?!r3Kt;Z20kwc5;#4ftD88M{M$2*#g{W!p@!qdx@I7o+@`P|Px8GseYV1U|=U@i{f zFx@;t+Qq1Pj4J9BT&3Ws_j{FKoF3sDL5?SpSH^S)pQ?DR-7t>C?Ys%cbdzUJvriDj zl%zO@CzGv%)H3#0^D5-QibhD0?SV*T!+FdHrVG6|BvdI2RXi`)JSm`t0`v;;*Hioz zzQr7y>!=90g%M9I@WS1CH<}X7<5=k3T*w>cUMxCVomiYXT9a6kIa-@onmJmRSe7}5 z3Ih|?j|_q{`q7XZet) z)UTX5G{^)fgiVpmQpf;-Cn2KUgUv@<6BkWj3*(cxcmiAH^%C!T7TcyLdLWc&4S9@G z2Bn|?i$-0`duecyy4ZzzCw1+kE@|*`8T9S7UZh*Aw=j*ZHCvdyOCvortHD>t= diff --git a/target/classes/hello/controller/GreetingController.class b/target/classes/hello/controller/GreetingController.class deleted file mode 100644 index 1149660667b8bd33f1ed25bd2d4d556a0184f111..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1219 zcmb7DYflqF6g|^-OLKy#_<+zlxxYx|+pLNS!% z@K8IhW&6?&l@d~0T>GA5TWis;=0_lz$BuOLDnqhdsWYV3{U$*T)*LCGhh9UdSG?gy z41Alrb*>y^cbqA`?*t5UwSD2bzA2@Z@47-+8%hXGG>KxzMTB#$j+dd@q1fF~r32#; z1@{zz@=}s}L}7f3+H*WncLIkvtV!u>t{oDA;bF~JEh}gnY4#L_ANlI7btD>A!;wvk zpT=5S;$0{L{fxKUv5e`%SUzSk%=DIc$qf`q+EZ)!ytN`2>Z8~cdpvZ1zgPOTuiPd> zVcQRtEuJ_==drWOEt$7JUyFh6626EFC^5`OBlORiC}I#p48!r0_P#|Cw{eGI_CKDR z+Inh+VsUCNm}VIIGruny2g24_+%3{h+&AQwY2X}bE8)?UuF2+x(9t|@_T6H*_d$YJ`L{RaAwBD4`Y72|k}VvH}nYdEC!4K(-JWfYr$d+wjzujAq7}jAk4~Of#YPfGtv&s&a7u< zB}5MAuyfz{?cDcaJC*>G*faD{qV)P=sBg)cP7Aj~0;N)8Ro zXRwgNHc@(A=%So(BZm*;BUyZO13rdVgze*5e4-nl#HZxr)hu4i;nVnx44)O=&t>uX z9KL`rX7QygzAR#2$>FP_Xd7-dHY-<087GJIQx@5u078NMgO_cQoG20zrG zU-fKv%Bs~JBeXQ+C$1XvM$s|cxneo=ZFlathDU0~HEYZcLffr`Bd%HY{BX2t_(mnP z{Gcg(GN?OtIN~@Z^O7A_M?J@L%a&tR!qS*5j8pZq*5ZQan^RTG6*WS~S6Q%U)^^R3 zdB&LM;pr*OLwaSOXPmMfD=4|=jj)=S)a2B+p6c^0!xYWJLRVQvZ7q`?dUd-}w)}a!LhtULs9KKW6@z%8IMuRCKkvNIa6`Lh zU9+C085 zvAp8Bq3=14?_ zu0hz6jXK8gehmdFE{wBc#ZYlTRcWk0Pz$`ZYJ9SEPSvci>Y2kz$CDV+aQa~D-)SpU z21QF_s*+Z`K@~(*O_@>?E97uZ6|kDcT1#Uml%l%#inBzHheceU`$n`8rn2m_0RPyirV3@ z*mqpyo8qT!$bx@*YOMdQp4d@66r@O8hSO)_bI<%^KQ&oDuZ9?_%&YF z@f-YB!?9Fk)g+boW>wv{=54PLs2V#+RV^3+mHbY}@9_s6f5e|!Gjo-aQlO+IDMLAy zQCEwW;j3p9h5szxdPB#XcuQdXg>`I|VEQp;%^D3SRKa4vII0_-%j7kg-5I>CV+qR| z`cvlSM4FH!`KaO8v!3tT#<0@xz^LIGrcoSa-us55<0fupa9hXwFp|MLI__XX$3^^A z$0ZqFkk2bJyePv5WOxY^8dRJM_inHnHaGKNa^@;;*h*@wZHa95jIV}WE3J4f3%lle zHbKiZ>Fa^D4SQ`5PtuNp+0cuN=_;dEmNHRCot)LMzg2H+^YOKMsW7<-?cV}CWX=j# zwS1aTcN)Q%vB<~C?t$?{XN;?~)g(Y|2g*aivX-# zu0nqO5;BE+b_v~ud~OLF3VD4A8w>ddmawUi-@Jq^Z&I)Wr#bGAjNL)yJ;-4fHe)xo zV=qUAJ^~uxcnJG&hP--wAW9hLmxgCCK`mm;ztDwsq_5pUe)=Z1PTazSXYXJe=iBo; zmhsS|%h-7fJ)Grt$>(kCW@as8PqO%MbMYN1}!O$#%bp zj$!S)3zK9gCR6d1{q-JiwLb_bAXZsBw-!0i!$X#%{=#Jqxs*tmMxx0>LlQ*h65U%+kV i%8Q(Jkb8u@0Sv6Q}7zpJZ!eFO?-%S|!6U z{ZH*oC!Og-e?Wg!r{AvRON2ay2kmO5bI$jD=d%C&``6z@v`kiosx{>a}|Mwj*?Pl_%- z5TR(gyzY6vw59O9kkKQ{587tf3xwA`4D2pH_Jg0zCbzxNJhWTV58j&gz`?9X(mxgf zcM!I?COje68Rct>2aF0Ez5_02E#dL+qi&N2`!>)RON>o#)gSYw*%Y2LDtwRs67f*JvU@#b3a%4Jwi^MgXzE%pngUBr@kb#$JDZ9| zOw+Z!w%L#>!>fxKL>T3Sqtc{BjaoCR#?j4p!ub{1I$g+JTNO<5;8aB)WL7jw)2=N$ z{jxw&*>)T)fYEF%gQqI;L?U)3<3Dl%HXR>Y9)2)~eqOaBNECKoH})B=d~AT{zVjCD z)u`v#k|#2185PJNu7u@xe*kP1?SX_Q?iVuLm2Giz%i7xCVl;OsT%`XM=AavOE$+2t zXWI{Ukb#?{zB``eZ62Wd@Aqw2c(Eg+nUN0YyD)nEA(6&4_(IY@Kv5J;S93Jq4N%cl z=R!Y-J2&jNZolo+A4Zji9|bMGEz~rh*U1^q=RGCq<0dJTL-$pK&e10Z8FZ#ZFAcg# za|V4!*9^Kzw+#A%?iutYePz(sv~18fG{z|E z_i+{XGe%P}!#;&m5&K!}W$Yl0bs8rVJHtM)^e3_3@sgt%tjd@Wx^Y~WLD({|9F%7*8Nh=z9KDHc4tt3+6 zO^QTL=QK^iOi0A?&*TR3V=Cy*gi1OIr8JXuB;o0pBn*?D#=n0Ge(j~_PCTdfyJDG;u(~xoN|9|T~M)Frt#vH8;X6*^le`Q|( AuK)l5 diff --git a/target/classes/hello/declaration/CustomPredicate.class b/target/classes/hello/declaration/CustomPredicate.class deleted file mode 100644 index e35803f64936c9dac92044b2074162814cb240fe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 248 zcmZXPu?~Vj5JYDYLD0fNKfn$fudz~NV`62Z2~>9Hals=eByjj~7Jh&qWjwLNVw0Vh z$?WXw{dfXcV&o(AF(kM~)`l>R4mrPbrg@RE<0Y5EtmkJ!5UZ@;(I#2_ z+qeIS5XNOw3AtC=226HMZOYrJlBp8h$i??0VRn^Tmn@Y+^NJf)7OZ0=jJxeT0>QDr W0OS&SaINlJ<-oJ^+k6aK5_|y1tUr+e diff --git a/target/classes/hello/declaration/TimeClient.class b/target/classes/hello/declaration/TimeClient.class deleted file mode 100644 index a077c3b314ee91fac7a75e48cd1d292b119702c1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1383 zcma)6YflqF6g|_H-L@%Al)A1LI*PW0fBdOc3!3FdX=bSyCF6(M)+l3>uxd_F(D7n;_%BvUsz)o$6fLQFzo z>agBJAq!rSI|>oHN6hKMF+bs1NsQTZ&KyI60^WMA$Xg6kW(ah+dzjskzU?07+G9f; z1;ti9i z66kH0!O*oMdGXyQF9)ntVg{A0(quIl8D{?@g(h5OB9H6}!+7CHIF6UKMA6|sSE912 zdaI5tT&eW!cvZhBHf)t;Ps=r@l0krnj*M1BHXX-8?5~{&qxI+6+h$2F(nW=%D7Cs~T9kDlG z(2>&4pl9ew#p!j1#2Jz`be>WiQK5sPq8OolicTQD4&u|uavftBCCeZoG)&NGJcu!I z6=||xqelZ<*U85)N%&C73gMNK?#x#h3^O%!)zE!PmPqg&ilO~vlbevZfhn@7o#JNn JyGf@A%-=-ZS;_za diff --git a/target/classes/hello/model/Customer.class b/target/classes/hello/model/Customer.class deleted file mode 100644 index 06e7307b01f2d26b0448a3cb8b12af11a1a0577c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1407 zcmaJ-=K;NhX@e zNHp;W_@j*HY4<`#F->}(mwV51&bjx`-=Dt$tYJNcN(Kt1j%8V^X-r~8qE#K1Bo8Hd zq~oz9Pb68(U(KW0?Y1jjrWSF=$vkjHiD&=#Y*Ft`(GOiQDHA}=M%M}^#o#=C=8O20guu=%g$(4FY=QCj;J1FG7u-b$1Ex^CQe=$b)Di7p^XJWSK;&R}hh_5hA7F4$A)kZ~E($ diff --git a/target/classes/hello/model/Greeting.class b/target/classes/hello/model/Greeting.class deleted file mode 100644 index f875277914303b411d510e45ee094e441fbdc76c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 588 zcmZuu%SyvQ6g`tiV{7^_t@Vw%YXh2%JH<^wu>@UI3NF)hXs4tJ#MHkM6fA-ZKfsR? z?0D}nny=iIsZ`u_L?aE5~tbZix&VOyFV1G@(H7!)yNU|j~okHUn934`TMyeH2I zyl~|7l30YJbB4l&2t{(q&}?;A`|Uo1)`^Ckq3Vi|-_E839^ZR|fGU<7`CicXVj=Uq zs3l|ZNNnzy2SMaa2^%=qG3QC9r;m7YL#wH+HZ518th3m!(Q2=5Kr_8)7W@24NX_zs z>QuhPL<##Q3NTEpp~%qqPnDte_wc*Hg!^<1((mJ#E~e8N6sn zK)FV~YQKZohjS?Q$sFn{l@yf8T4~!LE8#^{2wb815djHCUyZzsqzp?VIVoi}2%X6| s#3p;X{RZWkf{eV710R diff --git a/target/classes/hello/model/Quote.class b/target/classes/hello/model/Quote.class deleted file mode 100644 index 3ec6c6c7d3ee5544ff04f2ad4753558e032a5fd4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1128 zcmZ`%?@!ZE6g_XWYgdbm!3OFO5OCf2Q5C)+e2~OXi^f1^{Mc>HC@JkSS`uUYpES{t zXyPB>A7#Avt+LsbGLW4Yq(1eeAmerRIfm?byB(^z74U;03)y0rlGPW4c^up1Zyu+LvM1_3aiX z=~j=zQKi75RnO{IPN+d(uIUBtoA|Qr4$hpmFWJJ5& zZgeJS`KV^%8J?TCk2yZQAhA1Z(&Zx)Ma*+@-$V%u z0`rr?C5Aw8O!c;X;dUaD>Gb<<(53&HWyh35i8ivdYMo5~wej_Ta3iwAyX&z|Z)}#{ zVvatVPM&BW+Vk}0Xdqe_DSA)$g7)2?5Fc)kE6og{G`>Nltymi(U(!YieTYKwGbM&F zzDT%o0tOUNp|d#x!V;D#5_oV+VpGH}>2h@KX*oGIinRk8T5GR;+Hc>#d&NqAkt8#ZQb%-NV%80vbdzZiAbf}XF?Sb6Tf^xTwzyApT2@Gei~XilL#A4EaA zpipehJW(hu#a&kHT?r!p(N=HWPu9HkkUL|#@QIfM5}VCZx*7Bp4zFzbVHmqT)`sqC z(0joQ!Y_q^AEhL*`+k~9DYurFmo?F5yp<@ZWlHD;(N;>1a^LU7QJ3;NTS>xF(Wy|+ zlTXx&G_)44`e{y%X-}9llw#L=tzh-yDBWbAuYHg774gYH{3OkU4x7S(i4{?9#E)$F z>2F3VOtfb5WEvSx8n32F5N#;z|Ctzi(T1DtvYF~C{pk4j12Mb4+rx7*z#8^q#Kz4U z7BEx89t_*KRl{v8+PG8067I_5o;>c$_JbPQIIS@Gujwd^=*ywiJYIk9cj%_6==z<| zOT09QBUc*9=BY6Lm+Qn!6veL;_T`+@@@GlhQ~#EoKThUy z-K0;uv9oCv;%5qn^xfKlu191haBnB=V0Lr4*}2>XC!a*F7{&c>ZyFoZ{D}`ip~i1P z#>@YJGS{3spQDTxxUcxGwLe3(w^8_r;(NvgjPW^)qMV_`+95{!bfojKA9Y3w2QY51 z-Y~n&y{YyG6t_{DElo^LZNr+i+Kp1f+D7>|@G-)IG!?>*5^j=!La>m57y`oKAR1ca z6b^A!5DH9iRb;KyO%Z97G7qB(ifgs5S(W_PU^U6(8XO*?p!EXAL2_w zw|Y7X&Zgr*kevI2P?~%3&<`*CM9V!dTIrRZDD3vGf-sD|F?&PrJigIG4lj*@^fQ$; z+MOb8rOEtrv%UURl+@VXzb(JUhNVJtfmnJ{a{*kczb%-wK6||)YMg#NO@_fIExT~C zC%%$}yQso-QAWkZh6D!{h5Fh)6t)-se926~Ax*StuL(m4crt_|%cNnhfF8nS+~n;w zvtllFe?ooFU^PaEZD6Ct(-uzxCkWf9Gt)WjG75pmJSX@8;~NVGguu>^XiySz;Xw+e-rt3sNELhcm{F;|7`QOJWkgvfG5$o)bg z)~b;GLLqy_LabFG;_lHMLd0DWQl-?nH6gcVak~xiHrsIb#SCWmCujCoiFXb8J^8;WJmk&5qkoNMrN96H diff --git a/target/classes/hello/model/Value.class b/target/classes/hello/model/Value.class deleted file mode 100644 index 862a68f17d303c4c370907d46f8531959e3c75f8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1111 zcmZ`%?@!ZU5PsgW{+dO`3QPrM0=jN6s=_yf50aReEE}@YKL1C#6$o%YBJ@^a$};#&e+Cd*F{P*H$}6^e`$gbMD^N$^I< za)bAT*PwcA&R9hWQMr)l?o*AAZEku$3vQwf|nt1$5ipn}LHC`MKULUE=6Va!M gtj;7-rMpO1H9K@9)jq+1Z0b|0o}wnfKoBzTWS> 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 diff --git a/target/classes/public/index.html b/target/classes/public/index.html deleted file mode 100644 index 566549b..0000000 --- a/target/classes/public/index.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - Title - - - - - \ No newline at end of file From e76441501cd34e92f4b41455476532567e7579ba Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Thu, 6 Aug 2026 16:26:50 +0000 Subject: [PATCH 2/8] feature: add GitHub Actions CI running ./mvnw clean verify on JDK 21 Co-Authored-By: alex.vyshetsky --- .github/workflows/ci.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..0ccf481 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,21 @@ +name: CI + +on: + push: + branches: [master] + pull_request: + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: temurin + cache: maven + + - name: Build and test + run: ./mvnw -B clean verify From a22bce2f95f4d84639d4c350612030cf6ea46b82 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Thu, 6 Aug 2026 16:30:36 +0000 Subject: [PATCH 3/8] feature: enable virtual threads, migrate RestTemplate to RestClient, drop stray root properties file Co-Authored-By: alex.vyshetsky --- application.properties | 1 - src/main/java/hello/Application.java | 18 ++++++++++-------- .../java/hello/config/RestClientConfig.java | 14 ++++++++++++++ .../java/hello/config/RestTemplateConfig.java | 15 --------------- src/main/resources/application.properties | 4 ++++ 5 files changed, 28 insertions(+), 24 deletions(-) delete mode 100644 application.properties create mode 100644 src/main/java/hello/config/RestClientConfig.java delete mode 100644 src/main/java/hello/config/RestTemplateConfig.java create mode 100644 src/main/resources/application.properties diff --git a/application.properties b/application.properties deleted file mode 100644 index d3baf26..0000000 --- a/application.properties +++ /dev/null @@ -1 +0,0 @@ -#server.port = 8081 \ No newline at end of file diff --git a/src/main/java/hello/Application.java b/src/main/java/hello/Application.java index 3dc25cb..560a9bf 100644 --- a/src/main/java/hello/Application.java +++ b/src/main/java/hello/Application.java @@ -2,7 +2,7 @@ import java.util.Arrays; import java.util.List; -import java.util.stream.Collectors; +import java.util.stream.Stream; import hello.model.Customer; import hello.model.Quote; @@ -14,8 +14,8 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ApplicationContext; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.web.client.RestClient; import org.springframework.web.client.RestClientException; -import org.springframework.web.client.RestTemplate; @SpringBootApplication public class Application implements CommandLineRunner { @@ -42,7 +42,7 @@ public static void main(String[] args) { JdbcTemplate jdbcTemplate; @Autowired - RestTemplate restTemplate; + RestClient restClient; @Override public void run(String... args) throws Exception { @@ -54,10 +54,9 @@ public void run(String... args) throws Exception { jdbcTemplate.execute("CREATE TABLE customers(id SERIAL, first_name VARCHAR(255), last_name VARCHAR(255))"); // Split up the array of whole names into an array of first/last names - List splitUpNames = Arrays.asList("John Woo", "Jeff Dean", "Josh Bloch", "Josh Long") - .stream() - .map(name -> name.split(" ")) - .collect(Collectors.toList()); + List splitUpNames = Stream.of("John Woo", "Jeff Dean", "Josh Bloch", "Josh Long") + .map(name -> name.split(" ")) + .toList(); // Use a Java 8 stream to print out each tuple of the list splitUpNames.forEach(name -> log.info(String.format("Inserting customer record for %s %s", name[0], name[1]))); @@ -80,7 +79,10 @@ public void run(String... args) throws Exception { */ private void logRandomQuote() { try { - Quote quote = restTemplate.getForObject(QUOTE_URL, Quote.class); + Quote quote = restClient.get() + .uri(QUOTE_URL) + .retrieve() + .body(Quote.class); log.info(String.valueOf(quote)); } catch (RestClientException e) { log.warn("Could not fetch a quote from {}: {}", QUOTE_URL, e.getMessage()); diff --git a/src/main/java/hello/config/RestClientConfig.java b/src/main/java/hello/config/RestClientConfig.java new file mode 100644 index 0000000..9cef05a --- /dev/null +++ b/src/main/java/hello/config/RestClientConfig.java @@ -0,0 +1,14 @@ +package hello.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.client.RestClient; + +@Configuration +public class RestClientConfig { + + @Bean + public RestClient restClient(RestClient.Builder builder) { + return builder.build(); + } +} diff --git a/src/main/java/hello/config/RestTemplateConfig.java b/src/main/java/hello/config/RestTemplateConfig.java deleted file mode 100644 index 0ef3329..0000000 --- a/src/main/java/hello/config/RestTemplateConfig.java +++ /dev/null @@ -1,15 +0,0 @@ -package hello.config; - -import org.springframework.boot.web.client.RestTemplateBuilder; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.client.RestTemplate; - -@Configuration -public class RestTemplateConfig { - - @Bean - public RestTemplate restTemplate(RestTemplateBuilder builder) { - return builder.build(); - } -} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000..c4a0209 --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1,4 @@ +# Serve each request on a virtual thread (Java 21 + Spring Boot 3.2+). +spring.threads.virtual.enabled=true + +#server.port = 8081 From 466b6e3ddfbb2acbceff9626460dea3aa45d7cf6 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Thu, 6 Aug 2026 16:31:10 +0000 Subject: [PATCH 4/8] feature: convert models to Java records and modernize topic service/controller - convert Topic, Customer, Greeting, Quote, Value to records (component names preserve the existing JSON field names) - add @FunctionalInterface to CustomPredicate - use .toList() where the result is only read; leave the mutable topics list alone - bug: getTopicWithId returns Optional so an unknown id yields 404 instead of 500 Co-Authored-By: alex.vyshetsky --- .../hello/controller/TopicController.java | 7 ++- .../hello/declaration/CustomPredicate.java | 1 + src/main/java/hello/model/Customer.java | 43 +------------------ src/main/java/hello/model/Greeting.java | 19 +------- src/main/java/hello/model/Quote.java | 32 +------------- src/main/java/hello/model/Topic.java | 41 +----------------- src/main/java/hello/model/Value.java | 31 +------------ src/main/java/hello/service/TopicService.java | 20 ++++----- 8 files changed, 20 insertions(+), 174 deletions(-) diff --git a/src/main/java/hello/controller/TopicController.java b/src/main/java/hello/controller/TopicController.java index c2e8273..c4e322c 100644 --- a/src/main/java/hello/controller/TopicController.java +++ b/src/main/java/hello/controller/TopicController.java @@ -3,6 +3,7 @@ import hello.model.Topic; import hello.service.TopicService; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.List; @@ -29,8 +30,10 @@ public List getAllTopics() { * @return */ @RequestMapping("/topic/{id}") - public Topic getTopicWithID(@PathVariable String id) { - return topicService.getTopicWithId(id); + public ResponseEntity getTopicWithID(@PathVariable String id) { + return topicService.getTopicWithId(id) + .map(ResponseEntity::ok) + .orElseGet(() -> ResponseEntity.notFound().build()); } /** diff --git a/src/main/java/hello/declaration/CustomPredicate.java b/src/main/java/hello/declaration/CustomPredicate.java index 46f0c44..af828ac 100644 --- a/src/main/java/hello/declaration/CustomPredicate.java +++ b/src/main/java/hello/declaration/CustomPredicate.java @@ -4,6 +4,7 @@ * Use as a Functional Interface * @param */ +@FunctionalInterface public interface CustomPredicate { boolean test(T t); } diff --git a/src/main/java/hello/model/Customer.java b/src/main/java/hello/model/Customer.java index a6df80e..640db05 100644 --- a/src/main/java/hello/model/Customer.java +++ b/src/main/java/hello/model/Customer.java @@ -1,45 +1,4 @@ package hello.model; -public class Customer { - private long id; - private String firstName, lastName; - - @Override - public String toString() { - return "Customer{" + - "id=" + id + - ", firstName='" + firstName + '\'' + - ", lastName='" + lastName + '\'' + - '}'; - } - - public Customer(long id, String firstName, String lastName) { - this.id = id; - this.firstName = firstName; - this.lastName = lastName; - } - - public long getId() { - return id; - } - - public void setId(long id) { - this.id = id; - } - - public String getFirstName() { - return firstName; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public String getLastName() { - return lastName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } +public record Customer(long id, String firstName, String lastName) { } diff --git a/src/main/java/hello/model/Greeting.java b/src/main/java/hello/model/Greeting.java index f2e7772..135b2fb 100644 --- a/src/main/java/hello/model/Greeting.java +++ b/src/main/java/hello/model/Greeting.java @@ -1,21 +1,4 @@ package hello.model; -public class Greeting { - private final long id; - private final String content; - - public Greeting(long id, String content) { - this.id = id; - this.content = content; - } - - - public long getId() { - - return id; - } - - public String getContent() { - return content; - } +public record Greeting(long id, String content) { } diff --git a/src/main/java/hello/model/Quote.java b/src/main/java/hello/model/Quote.java index 2178a6d..b548a67 100644 --- a/src/main/java/hello/model/Quote.java +++ b/src/main/java/hello/model/Quote.java @@ -1,34 +1,4 @@ package hello.model; -public class Quote { - private String type; - private Value value; - - @Override - public String toString() { - return "Quote{" + - "type='" + type + '\'' + - ", value=" + value + - '}'; - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - public Value getValue() { - return value; - } - - public void setValue(Value value) { - this.value = value; - } - - public Quote() { - - } +public record Quote(String type, Value value) { } diff --git a/src/main/java/hello/model/Topic.java b/src/main/java/hello/model/Topic.java index 483a4a7..59740dc 100644 --- a/src/main/java/hello/model/Topic.java +++ b/src/main/java/hello/model/Topic.java @@ -1,43 +1,4 @@ package hello.model; - -public class Topic { - private String id; - private String subjectName; - private String subjectDescription; - - public Topic() { - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getSubjectName() { - return subjectName; - } - - public void setSubjectName(String subjectName) { - this.subjectName = subjectName; - } - - public String getSubjectDescription() { - return subjectDescription; - } - - public void setSubjectDescription(String subjectDescription) { - this.subjectDescription = subjectDescription; - } - - public Topic(String id, String subjectName, String subjectDescription) { - super(); - this.id = id; - this.subjectName = subjectName; - this.subjectDescription = subjectDescription; - } - +public record Topic(String id, String subjectName, String subjectDescription) { } diff --git a/src/main/java/hello/model/Value.java b/src/main/java/hello/model/Value.java index 272be70..b795170 100644 --- a/src/main/java/hello/model/Value.java +++ b/src/main/java/hello/model/Value.java @@ -1,33 +1,4 @@ package hello.model; -public class Value { - private Long id; - private String quote; - - public Value() { - } - - @Override - public String toString() { - return "Value{" + - "id=" + id + - ", quote='" + quote + '\'' + - '}'; - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getQuote() { - return quote; - } - - public void setQuote(String quote) { - this.quote = quote; - } +public record Value(Long id, String quote) { } diff --git a/src/main/java/hello/service/TopicService.java b/src/main/java/hello/service/TopicService.java index feffb92..d0a5706 100644 --- a/src/main/java/hello/service/TopicService.java +++ b/src/main/java/hello/service/TopicService.java @@ -35,8 +35,8 @@ public List getAllTopics() { * @param id * @return */ - public Topic getTopicWithId(String id) { - return topics.stream().filter(topic -> topic.getId().equals(id)).findFirst().get(); + public Optional getTopicWithId(String id) { + return topics.stream().filter(topic -> topic.id().equals(id)).findFirst(); } public void addTopic(Topic topic) { @@ -50,7 +50,7 @@ public void addTopic(Topic topic) { * @param topic */ public void updateTopic(String id, Topic topic) { - OptionalInt indexOfElement = IntStream.range(0, topics.size()).filter(index -> id.equals(topics.get(index).getId())).findFirst(); + OptionalInt indexOfElement = IntStream.range(0, topics.size()).filter(index -> id.equals(topics.get(index).id())).findFirst(); if (indexOfElement.isPresent()) topics.set(indexOfElement.getAsInt(), topic); } @@ -60,7 +60,7 @@ public void updateTopic(String id, Topic topic) { * @param id */ public void deleteTopic(String id) { - topics.removeIf(topic -> topic.getId().equals(id)); + topics.removeIf(topic -> topic.id().equals(id)); } /** @@ -70,7 +70,7 @@ public void deleteTopic(String id) { * @return */ public List filterMinimumLengthForId(Integer minLength) { - return printTopicsWithPredicate(topics, topic -> topic.getId().length() > minLength); + return printTopicsWithPredicate(topics, topic -> topic.id().length() > minLength); } @@ -96,7 +96,7 @@ private static List printTopicsWithPredicate(List topicList, Custo * @return */ public List sortTopicsWithID() { - topics.sort(Comparator.comparing(Topic::getId)); + topics.sort(Comparator.comparing(Topic::id)); return topics; } @@ -107,7 +107,7 @@ public List sortTopicsWithID() { * @return */ public String returnAllTopicIDWithStringSlicing() { - List topicIds = topics.stream().map(topic -> topic.getId()).collect(Collectors.toList()); + List topicIds = topics.stream().map(Topic::id).toList(); return String.join(":", topicIds); } @@ -147,13 +147,11 @@ public String splitAllIdWithColonSelectIDWithJavaKeywordThenSortThenJoin(String */ public String findIdHavingCharacter() { Pattern pattern = Pattern.compile(".*g.*"); - Object[] topicIdObjectList = topics.stream().map(topic -> topic.getId()).collect(Collectors.toList()).toArray(); - - String[] topicIdList = Arrays.stream(topicIdObjectList).toArray(String[]::new); + String[] topicIdList = topics.stream().map(Topic::id).toArray(String[]::new); return Stream.of(topicIdList) .filter(pattern.asPredicate()) - .collect(Collectors.toList()) + .toList() .toString(); } From f03dc37c971e65fc3031f8a1afa3239656c359d9 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Thu, 6 Aug 2026 16:31:59 +0000 Subject: [PATCH 5/8] feature: modernize controllers with text blocks and refresh README for Java 21 Co-Authored-By: alex.vyshetsky --- README.md | 204 ++++++++++-------- .../hello/controller/GreetingController.java | 5 +- .../hello/controller/HelloController.java | 90 ++++---- 3 files changed, 159 insertions(+), 140 deletions(-) diff --git a/README.md b/README.md index 2b09400..bc29551 100644 --- a/README.md +++ b/README.md @@ -1,134 +1,150 @@ # springboot-java8 -The project is made on spring boot. The project summarize the new features present in Java 8. -It contain list of harcoded topics list. You can call the apis's with POSTMAN to add,delete,update Topic list -In addition, it uses -1) Java 8 NIO methods -2) String operations -3) Stream operations -4) IntStream functions -5) Functional interface -6) Lambda functions -7) Optional datatype -8) Foreach loops -9) Default and Static methods in interface -10) Java 8 LocalDateTime API -11) Pattern - - - -## Getting Started -1) Download or clone the project with link -(https://github.com/RehmanMuradAli/springboot-java8/) - -## Available API's - -Greetings -``` -GET / -``` -Get all Topics in List -``` -GET /topic -``` -Get Topic of given ID -``` -GET /topic/{id} -``` -Add Topic in List -``` -POST /topic -``` -Update Topic of given ID -``` -PUT /topic/{id} -``` -Delete Topic of given ID -``` -DELETE /topic/{id} -``` +A small Spring Boot REST service whose purpose is to **demonstrate Java language features** — originally the Java 8 +feature set, which is still what the code shows off. The name stuck, but the project itself now builds and runs on +**Java 21 with Spring Boot 3.5.16**. -Get all Topics whose ID's length is greater than minLength -``` -GET /topic/minimum/length/{minLength} -``` +The domain is deliberately trivial: an in-memory, hardcoded list of `Topic` objects that you can create, read, update +and delete over HTTP, plus a few endpoints that exist purely to print the result of stream / string / file operations. -Get all Topics sorted by ID -``` -GET /topic/sort -``` +## Java 8 features demonstrated -String Operations on Topic List -``` -GET /topic/string/operation -``` +1. NIO.2 file APIs (`Files.list`, `Files.find`, `Files.walk`, `Files.newBufferedReader`) +2. String operations (`String.join`, `String.chars`) +3. Stream operations (`filter`, `map`, `sorted`, `Collectors.joining`) +4. `IntStream` (`IntStream.range` for index lookups) +5. Functional interfaces (`CustomPredicate`) +6. Lambda expressions +7. `Optional` / `OptionalInt` +8. `forEach` loops +9. `default` and `static` methods on interfaces (`TimeClient`) +10. The `java.time` API (`LocalDateTime`, `ZonedDateTime`, `ChronoUnit`) +11. `Pattern` as a stream source and as a predicate (`splitAsStream`, `asPredicate`) +12. try-with-resources over streams of paths -File Operations on Topic List -``` -GET /topic/file/operation -``` -Java 8 Date Time example +## Java 21 idioms in use + +The application was migrated from Spring Boot 2.0.2 / Java 8 to Spring Boot 3.5.16 / Java 21, and the presentation +layer has been rewritten to use the modern language features that replace what the old code did by hand: + +- **Text blocks** (Java 15) for the multi-part responses of `/datetime`, `/topic/string/operation` and + `/topic/file/operation`, using `\` line-continuation escapes so the responses stay on a single line. +- **`String.formatted(...)`** (Java 15) instead of `String.format(...)` and `+` concatenation. +- Label templates are `private static final` constants rather than mutable instance fields. + +## Requirements + +- JDK 21 (the build sets `21`) +- Maven is **not** required — use the bundled Maven Wrapper (`./mvnw`, Maven 3.9.9) +- `curl`, HTTPie or Postman to call the API + +## Getting started + +```bash +git clone https://github.com/COG-GTM/springboot-java8.git +cd springboot-java8 + +# compile, run the test suite and package the jar +./mvnw clean verify + +# run the application (listens on http://localhost:8080) +./mvnw spring-boot:run ``` -GET /datetime + +You can also run the packaged jar directly: + +```bash +java -jar target/gs-spring-boot-0.1.0.jar ``` +> The Gradle build has been removed; Maven is the only supported build. + +Every push and pull request is built by GitHub Actions with `./mvnw -B clean verify` on JDK 21 +(see `.github/workflows/ci.yml`). + +### Expected startup noise +- On startup the app creates an in-memory **H2** `customers` table with `JdbcTemplate` and logs a few rows — this is + part of the demo, not an error. +- It also tries to fetch a random quote from `gturnquist-quoters.cfapps.io`, a demo service that no longer exists. + The resulting `WARN Could not fetch a quote from ...` is expected and must never fail startup. -### Prerequisites +## API -1) Java sdk -2) POSTMAN +All endpoints are served from `http://localhost:8080`. -### Installing +| Method | Path | Description | +| --- | --- | --- | +| `GET` | `/` | Greeting; accepts an optional `?name=` parameter (defaults to `World`) | +| `GET` | `/topic` | All topics | +| `GET` | `/topic/{id}` | A single topic by id | +| `POST` | `/topic` | Add a topic (JSON body) | +| `PUT` | `/topic/{id}` | Replace the topic with the given id | +| `DELETE` | `/topic/{id}` | Delete the topic with the given id | +| `GET` | `/topic/sort` | All topics sorted by id | +| `GET` | `/topic/minimum/length/{minLength}` | Topics whose id is longer than `minLength` | +| `GET` | `/topic/string/operation` | Plain-text dump of the string/stream/regex examples | +| `GET` | `/topic/file/operation` | Plain-text dump of the NIO.2 file examples | +| `GET` | `/datetime` | Plain-text dump of the `java.time` examples | +The topic list lives in memory, so `POST` / `PUT` / `DELETE` changes are lost when the application restarts. +### Examples +```bash +$ curl 'http://localhost:8080/?name=Devin' +{"id":1,"content":"Hello, Devin!"} + +$ curl http://localhost:8080/topic +[{"id":"spring","subjectName":"Spring Framework","subjectDescription":"Spring Framework Description"}, ...] + +$ curl -X POST http://localhost:8080/topic \ + -H 'Content-Type: application/json' \ + -d '{"id":"kotlin","subjectName":"Kotlin","subjectDescription":"Kotlin Description"}' ``` -1) Download or clone -2) Import the project -3) Run on location machine -4) Open Postman, to call API's ( localhost:8080 ) + +The `/topic/file/operation` endpoint resolves paths relative to the working directory the application was started +from, so its output depends on where you run it. + +## Project layout + +``` +src/main/java/hello +├── Application.java # entry point + CommandLineRunner (H2 seeding, quote fetch) +├── config/ # RestTemplate bean +├── controller/ # GreetingController, TopicController, HelloController +├── declaration/ # CustomPredicate, TimeClient (default/static interface methods) +├── model/ # Topic, Greeting, Customer, Quote, Value, SimpleTimeClient +└── service/ # TopicService — where most of the Java 8 examples live ``` +## Helpful links -## Helpful Links Spring: https://spring.io/guides -Java 8: +Java 8: http://www.baeldung.com/java-8-functional-interfaces -http://winterbe.com/posts/2015/05/22/java8-concurrency-tutorial-atomic-concurrent-map-examples/ - https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html http://winterbe.com/posts/2014/07/31/java8-stream-tutorial-examples/ -http://www.oracle.com/technetwork/articles/java/ma14-java-se-8-streams-2177646.html - https://docs.oracle.com/javase/tutorial/essential/io/pathOps.html -https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html - -http://www.baeldung.com/foreach-java +Java 21: -http://winterbe.com/posts/2015/03/25/java8-examples-string-number-math-files/ +https://docs.oracle.com/en/java/javase/21/text-blocks/index.html -http://www.baeldung.com/java-8-comparator-comparing +https://docs.spring.io/spring-boot/docs/current/reference/html/ -http://www.baeldung.com/java-8-sort-lambda +## Built with -https://dzone.com/articles/java-8-friday-goodies-new-new - - -## Built With - -* [Maven](https://maven.apache.org/) - Dependency Management +* [Maven](https://maven.apache.org/) — build and dependency management +* [Spring Boot](https://spring.io/projects/spring-boot) 3.5.16 ## Authors -* **Rehman Murad Ali** - - +* **Rehman Murad Ali** — original author diff --git a/src/main/java/hello/controller/GreetingController.java b/src/main/java/hello/controller/GreetingController.java index cf52f8d..9f5cfbe 100644 --- a/src/main/java/hello/controller/GreetingController.java +++ b/src/main/java/hello/controller/GreetingController.java @@ -9,12 +9,11 @@ @RestController public class GreetingController { - private static final String template = "Hello, %s!"; + private static final String TEMPLATE = "Hello, %s!"; private final AtomicLong counter = new AtomicLong(); @RequestMapping("/") public Greeting greeting(@RequestParam(value="name", defaultValue="World") String name) { - return new Greeting(counter.incrementAndGet(), - String.format(template, name)); + return new Greeting(counter.incrementAndGet(), TEMPLATE.formatted(name)); } } diff --git a/src/main/java/hello/controller/HelloController.java b/src/main/java/hello/controller/HelloController.java index f3602fa..b599c6b 100644 --- a/src/main/java/hello/controller/HelloController.java +++ b/src/main/java/hello/controller/HelloController.java @@ -2,38 +2,37 @@ import hello.declaration.TimeClient; import hello.model.SimpleTimeClient; -import hello.model.Topic; import hello.service.TopicService; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; import java.time.ZoneId; -import java.time.chrono.ChronoPeriod; import java.time.temporal.ChronoUnit; -import java.util.List; -import java.util.regex.Pattern; -import java.util.stream.Collector; -import java.util.stream.Collectors; @RestController public class HelloController { - - String joinTemplate = "Joining All String ID's with JOIN method: "; - String makeDistinctAndSortCharactersTemplate = "-------------Get all ID characters, select distict and sort with ID= "; - String splitAllIdWithColonSelectIDWithJavaKeywordThenSortThenJoinTemplate = "-------------Split All Id With Colon," + - "Select ID With \"Java\" Keyword," + - " Then Sort Then Join "; - String findIdHavingCharacterTemplate = "-------------Return All ID having character \'g\' in it: "; - String findAllFilesInPathAndSortTemplate = "---------Find all files in path and sort: "; - String findParticularFileInPathAndSortTemplate = "----------Find File in present directory which strats with \"grad\",provided maximum depth=25 and sort : "; - String findParticularFileInPathAndSortWithWalkFunctionTemplate = "----------Find File in present directory which strats with \"grad\",provided maximum depth=25 and sort : with walk function"; - String readFileWithStreamFunctionTemplate = "---------Read \"temp.txt\" file with stream functions, having \"print\" witin it: "; - + private static final String JOIN_TEMPLATE = "Joining All String ID's with JOIN method: "; + private static final String MAKE_DISTINCT_AND_SORT_CHARACTERS_TEMPLATE = "-------------Get all ID characters, select distict and sort with ID= "; + private static final String SPLIT_ALL_ID_WITH_COLON_SELECT_ID_WITH_JAVA_KEYWORD_THEN_SORT_THEN_JOIN_TEMPLATE = """ + -------------Split All Id With Colon,\ + Select ID With "Java" Keyword,\ + Then Sort Then Join\s"""; + private static final String FIND_ID_HAVING_CHARACTER_TEMPLATE = "-------------Return All ID having character 'g' in it: "; + private static final String FIND_ALL_FILES_IN_PATH_AND_SORT_TEMPLATE = "---------Find all files in path and sort: "; + private static final String FIND_PARTICULAR_FILE_IN_PATH_AND_SORT_TEMPLATE = "----------Find File in present directory which strats with \"grad\",provided maximum depth=25 and sort : "; + private static final String FIND_PARTICULAR_FILE_IN_PATH_AND_SORT_WITH_WALK_FUNCTION_TEMPLATE = "----------Find File in present directory which strats with \"grad\",provided maximum depth=25 and sort : with walk function"; + private static final String READ_FILE_WITH_STREAM_FUNCTION_TEMPLATE = "---------Read \"temp.txt\" file with stream functions, having \"print\" witin it: "; + + /** Responses are single line, hence the trailing line-continuation escapes. */ + private static final String LABELLED_SECTIONS_FORMAT = """ + %s%s\ + %s%s\ + %s%s\ + %s%s\ + """; @Autowired private TopicService topicService; @@ -46,18 +45,23 @@ public class HelloController { @RequestMapping("/datetime") public String index() { TimeClient myTimeClient = new SimpleTimeClient(); - LocalDateTime localDateTime = LocalDateTime.now(); - return "Greetings from Spring Boot! ----------------------" + - "Datetime now is " + String.valueOf(myTimeClient.toString()) + "----------------------" + - "Datetime tomorrow will be " + String.valueOf(myTimeClient.getLocalDateTime().plusDays(1)) + "----------------------" + - "Datetime of previous month was " + String.valueOf(myTimeClient.getLocalDateTime().minus(1, ChronoUnit.MONTHS)) + "----------------------" + - "Is this a leap year ? " + String.valueOf(LocalDate.now().isLeapYear()) + "----------------------" + - "Default system zone id " + String.valueOf(ZoneId.systemDefault()) + "-------------------" + - "Time in California: " + myTimeClient.getZonedDateTime("Canada/Central").toString(); - + return """ + Greetings from Spring Boot! ----------------------\ + Datetime now is %s----------------------\ + Datetime tomorrow will be %s----------------------\ + Datetime of previous month was %s----------------------\ + Is this a leap year ? %s----------------------\ + Default system zone id %s-------------------\ + Time in California: %s\ + """.formatted( + myTimeClient, + myTimeClient.getLocalDateTime().plusDays(1), + myTimeClient.getLocalDateTime().minus(1, ChronoUnit.MONTHS), + LocalDate.now().isLeapYear(), + ZoneId.systemDefault(), + myTimeClient.getZonedDateTime("Canada/Central")); } - /** * String Operations in Java 8 * @@ -72,16 +76,16 @@ public String showStringOperation() { .splitAllIdWithColonSelectIDWithJavaKeywordThenSortThenJoin(join); String findIdHavingCharacter = topicService.findIdHavingCharacter(); - return joinTemplate + join - + makeDistinctAndSortCharactersTemplate + makeDistinctAndSortCharacters - + splitAllIdWithColonSelectIDWithJavaKeywordThenSortThenJoinTemplate + splitAllIdWithColonSelectIDWithJavaKeywordThenSortThenJoin - + findIdHavingCharacterTemplate + findIdHavingCharacter; - + return LABELLED_SECTIONS_FORMAT.formatted( + JOIN_TEMPLATE, join, + MAKE_DISTINCT_AND_SORT_CHARACTERS_TEMPLATE, makeDistinctAndSortCharacters, + SPLIT_ALL_ID_WITH_COLON_SELECT_ID_WITH_JAVA_KEYWORD_THEN_SORT_THEN_JOIN_TEMPLATE, splitAllIdWithColonSelectIDWithJavaKeywordThenSortThenJoin, + FIND_ID_HAVING_CHARACTER_TEMPLATE, findIdHavingCharacter); } - /** * File Operation in Java 8 + * * @return */ @RequestMapping("/topic/file/operation") @@ -90,12 +94,12 @@ public String showFileOperation() { String findParticularFileInPathAndSort = topicService.findParticularFileInPathAndSort(); String findParticularFileInPathAndSortWithWalkFunction = topicService.findParticularFileInPathAndSortWithWalkFunction(); String readFileWithStreamFunction = topicService.readFileWithStreamFunction(); - return findAllFilesInPathAndSortTemplate + findAllFilesInPathAndSort - + findParticularFileInPathAndSortTemplate + findParticularFileInPathAndSort - + findParticularFileInPathAndSortWithWalkFunctionTemplate + findParticularFileInPathAndSortWithWalkFunction - + readFileWithStreamFunctionTemplate + readFileWithStreamFunction; - } - + return LABELLED_SECTIONS_FORMAT.formatted( + FIND_ALL_FILES_IN_PATH_AND_SORT_TEMPLATE, findAllFilesInPathAndSort, + FIND_PARTICULAR_FILE_IN_PATH_AND_SORT_TEMPLATE, findParticularFileInPathAndSort, + FIND_PARTICULAR_FILE_IN_PATH_AND_SORT_WITH_WALK_FUNCTION_TEMPLATE, findParticularFileInPathAndSortWithWalkFunction, + READ_FILE_WITH_STREAM_FUNCTION_TEMPLATE, readFileWithStreamFunction); + } } From 53bf764d8aa31ae8d20c5e282d51e2b3de28bb15 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Thu, 6 Aug 2026 16:32:30 +0000 Subject: [PATCH 6/8] feature: add JUnit 5 test suite covering context load, all endpoints, TopicService and TimeClient Co-Authored-By: alex.vyshetsky --- .../hello/ApplicationContextLoadTest.java | 49 +++++ .../controller/GreetingControllerWebTest.java | 61 ++++++ .../controller/HelloControllerWebTest.java | 63 ++++++ .../controller/TopicControllerWebTest.java | 125 ++++++++++++ .../controller/TopicNotFoundStatusTest.java | 54 +++++ .../hello/declaration/TimeClientTest.java | 80 ++++++++ .../java/hello/service/TopicServiceTest.java | 191 ++++++++++++++++++ 7 files changed, 623 insertions(+) create mode 100644 src/test/java/hello/ApplicationContextLoadTest.java create mode 100644 src/test/java/hello/controller/GreetingControllerWebTest.java create mode 100644 src/test/java/hello/controller/HelloControllerWebTest.java create mode 100644 src/test/java/hello/controller/TopicControllerWebTest.java create mode 100644 src/test/java/hello/controller/TopicNotFoundStatusTest.java create mode 100644 src/test/java/hello/declaration/TimeClientTest.java create mode 100644 src/test/java/hello/service/TopicServiceTest.java diff --git a/src/test/java/hello/ApplicationContextLoadTest.java b/src/test/java/hello/ApplicationContextLoadTest.java new file mode 100644 index 0000000..e92dbb7 --- /dev/null +++ b/src/test/java/hello/ApplicationContextLoadTest.java @@ -0,0 +1,49 @@ +package hello; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.ApplicationContext; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.web.client.RestTemplate; + +import hello.controller.GreetingController; +import hello.controller.HelloController; +import hello.controller.TopicController; +import hello.service.TopicService; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Starts the whole application context, including the {@link org.springframework.boot.CommandLineRunner} + * on {@link Application}. The runner contacts a demo quote service that no longer exists; the resulting + * WARN must not fail startup, so reaching the assertions below is itself part of what is being verified. + */ +@SpringBootTest +class ApplicationContextLoadTest { + + @Autowired + private ApplicationContext context; + + @Test + void contextLoads() { + assertThat(context).isNotNull(); + } + + @Test + void exposesTheExpectedBeans() { + assertThat(context.getBean(TopicService.class)).isNotNull(); + assertThat(context.getBean(TopicController.class)).isNotNull(); + assertThat(context.getBean(HelloController.class)).isNotNull(); + assertThat(context.getBean(GreetingController.class)).isNotNull(); + assertThat(context.getBean(RestTemplate.class)).isNotNull(); + assertThat(context.getBean(JdbcTemplate.class)).isNotNull(); + } + + @Test + void commandLineRunnerPopulatedTheCustomersTable() { + Integer count = context.getBean(JdbcTemplate.class) + .queryForObject("SELECT COUNT(*) FROM customers", Integer.class); + assertThat(count).isEqualTo(4); + } +} diff --git a/src/test/java/hello/controller/GreetingControllerWebTest.java b/src/test/java/hello/controller/GreetingControllerWebTest.java new file mode 100644 index 0000000..ad8fd25 --- /dev/null +++ b/src/test/java/hello/controller/GreetingControllerWebTest.java @@ -0,0 +1,61 @@ +package hello.controller; + +import com.jayway.jsonpath.JsonPath; +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.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.Matchers.hasSize; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * Pins the JSON contract of {@code /}: {@code {"id": , "content": }}. + */ +@SpringBootTest +@AutoConfigureMockMvc +class GreetingControllerWebTest { + + @Autowired + private MockMvc mockMvc; + + @Test + void greetsTheWorldByDefault() throws Exception { + mockMvc.perform(get("/")) + .andExpect(status().isOk()) + .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) + .andExpect(jsonPath("$.*", hasSize(2))) + .andExpect(jsonPath("$.id").isNumber()) + .andExpect(jsonPath("$.content").value("Hello, World!")); + } + + @Test + void greetsTheRequestedName() throws Exception { + mockMvc.perform(get("/").param("name", "Devin")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.content").value("Hello, Devin!")); + } + + @Test + void everyGreetingGetsItsOwnId() throws Exception { + long first = greetingId(); + long second = greetingId(); + + assertThat(second).isEqualTo(first + 1); + } + + private long greetingId() throws Exception { + String json = mockMvc.perform(get("/")) + .andExpect(status().isOk()) + .andReturn() + .getResponse() + .getContentAsString(); + return JsonPath.parse(json).read("$.id", Long.class); + } +} diff --git a/src/test/java/hello/controller/HelloControllerWebTest.java b/src/test/java/hello/controller/HelloControllerWebTest.java new file mode 100644 index 0000000..e99f741 --- /dev/null +++ b/src/test/java/hello/controller/HelloControllerWebTest.java @@ -0,0 +1,63 @@ +package hello.controller; + +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.context.SpringBootTest; +import org.springframework.test.web.servlet.MockMvc; + +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.matchesRegex; +import static org.hamcrest.Matchers.not; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * Covers the plain-text endpoints. {@code /topic/file/operation} walks the process working directory + * and reads {@code temp.txt} from it, so its exact output changes whenever a file is added to or + * removed from the repository; only the stable parts of the response are asserted. + */ +@SpringBootTest +@AutoConfigureMockMvc +class HelloControllerWebTest { + + @Autowired + private MockMvc mockMvc; + + @Test + void datetimeEndpointRendersTheJavaTimeShowcase() throws Exception { + mockMvc.perform(get("/datetime")) + .andExpect(status().isOk()) + .andExpect(content().string(containsString("Greetings from Spring Boot!"))) + .andExpect(content().string(containsString("Datetime now is "))) + .andExpect(content().string(containsString("Is this a leap year ?"))) + .andExpect(content().string(containsString("Default system zone id"))) + .andExpect(content().string(containsString("Time in California: "))) + // "Datetime now is " + .andExpect(content().string(matchesRegex("(?s).*Datetime now is \\d{4}-\\d{2}-\\d{2}T[\\d:.]+.*"))); + } + + @Test + void stringOperationEndpointRendersTheStreamShowcase() throws Exception { + mockMvc.perform(get("/topic/string/operation")) + .andExpect(status().isOk()) + .andExpect(content().string(containsString("Joining All String ID's with JOIN method: "))) + // The distinct-and-sorted characters and the ":"-split are both sorted, so they are + // stable even if another test has re-ordered the singleton's topic list. + .andExpect(content().string(containsString(":acgijnprstv"))) + .andExpect(content().string(containsString("java:javascript"))) + .andExpect(content().string(containsString("[spring]"))); + } + + @Test + void fileOperationEndpointRendersTheNioShowcase() throws Exception { + mockMvc.perform(get("/topic/file/operation")) + .andExpect(status().isOk()) + .andExpect(content().string(containsString("Find all files in path and sort:"))) + .andExpect(content().string(containsString("pom.xml"))) + .andExpect(content().string(containsString("Read \"temp.txt\" file with stream functions"))) + .andExpect(content().string(not(containsString("Error in IO")))) + .andExpect(content().string(not(containsString("IO exception")))); + } +} diff --git a/src/test/java/hello/controller/TopicControllerWebTest.java b/src/test/java/hello/controller/TopicControllerWebTest.java new file mode 100644 index 0000000..05147be --- /dev/null +++ b/src/test/java/hello/controller/TopicControllerWebTest.java @@ -0,0 +1,125 @@ +package hello.controller; + +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.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.web.servlet.MockMvc; + +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.not; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * End-to-end coverage of the JSON contract of the topic endpoints. + * + *

{@code TopicService} is a singleton holding a mutable list, so anything that writes to it leaks + * into the next test. Rather than depending on test order, the two tests that mutate the list + * ({@code /topic} writes and the in-place sort performed by {@code /topic/sort}) drop the context + * afterwards with {@link DirtiesContext}; every other test can then assume the seeded state. + * + *

Assertions go through {@code jsonPath} rather than through model getters on purpose: the JSON + * field names are the actual contract and they survive the ongoing conversion of the models to records. + */ +@SpringBootTest +@AutoConfigureMockMvc +class TopicControllerWebTest { + + @Autowired + private MockMvc mockMvc; + + @Test + void getAllTopicsReturnsTheSeededTopics() throws Exception { + mockMvc.perform(get("/topic")) + .andExpect(status().isOk()) + .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) + .andExpect(jsonPath("$", hasSize(3))) + .andExpect(jsonPath("$[*].id", containsInAnyOrder("spring", "java", "javascript"))) + .andExpect(jsonPath("$[?(@.id=='spring')].subjectName", contains("Spring Framework"))) + .andExpect(jsonPath("$[?(@.id=='spring')].subjectDescription", contains("Spring Framework Description"))); + } + + @Test + void aTopicSerialisesWithExactlyIdSubjectNameAndSubjectDescription() throws Exception { + mockMvc.perform(get("/topic/java")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.*", hasSize(3))) + .andExpect(jsonPath("$.id").value("java")) + .andExpect(jsonPath("$.subjectName").value("Core Java")) + .andExpect(jsonPath("$.subjectDescription").value("Java Description")); + } + + @Test + @DirtiesContext(methodMode = DirtiesContext.MethodMode.AFTER_METHOD) + void supportsTheFullCreateReadUpdateDeleteLifecycle() throws Exception { + mockMvc.perform(post("/topic") + .contentType(MediaType.APPLICATION_JSON) + .content(""" + {"id":"kotlin","subjectName":"Kotlin","subjectDescription":"Kotlin Description"}""")) + .andExpect(status().isOk()); + + mockMvc.perform(get("/topic")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", hasSize(4))) + .andExpect(jsonPath("$[*].id", containsInAnyOrder("spring", "java", "javascript", "kotlin"))); + + mockMvc.perform(get("/topic/kotlin")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.subjectName").value("Kotlin")) + .andExpect(jsonPath("$.subjectDescription").value("Kotlin Description")); + + mockMvc.perform(put("/topic/kotlin") + .contentType(MediaType.APPLICATION_JSON) + .content(""" + {"id":"kotlin","subjectName":"Kotlin Updated","subjectDescription":"Updated Description"}""")) + .andExpect(status().isOk()); + + mockMvc.perform(get("/topic/kotlin")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.subjectName").value("Kotlin Updated")) + .andExpect(jsonPath("$.subjectDescription").value("Updated Description")); + + mockMvc.perform(delete("/topic/kotlin")) + .andExpect(status().isOk()); + + mockMvc.perform(get("/topic")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", hasSize(3))) + .andExpect(jsonPath("$[*].id", not(hasItem("kotlin")))); + } + + @Test + @DirtiesContext(methodMode = DirtiesContext.MethodMode.AFTER_METHOD) + void sortEndpointReturnsTopicsOrderedById() throws Exception { + mockMvc.perform(get("/topic/sort")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", hasSize(3))) + .andExpect(jsonPath("$[*].id", contains("java", "javascript", "spring"))); + } + + @Test + void minimumLengthEndpointFiltersOnIdLength() throws Exception { + mockMvc.perform(get("/topic/minimum/length/4")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[*].id", containsInAnyOrder("spring", "javascript"))); + + mockMvc.perform(get("/topic/minimum/length/6")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[*].id", contains("javascript"))); + + mockMvc.perform(get("/topic/minimum/length/20")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", hasSize(0))); + } +} diff --git a/src/test/java/hello/controller/TopicNotFoundStatusTest.java b/src/test/java/hello/controller/TopicNotFoundStatusTest.java new file mode 100644 index 0000000..398aed6 --- /dev/null +++ b/src/test/java/hello/controller/TopicNotFoundStatusTest.java @@ -0,0 +1,54 @@ +package hello.controller; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Requesting an unknown topic id is the one place where the HTTP status carries real information, and + * MockMvc rethrows unhandled exceptions instead of running the error dispatch, so this one case is + * driven over a real connection. + * + *

{@code TopicService.getTopicWithId} calls {@code Optional.get()} on a miss, which throws + * {@link java.util.NoSuchElementException} and surfaces as HTTP 500. That is asserted here as the + * current behaviour; the disabled test below is the replacement for when a parallel change + * turns the miss into a proper 404. + */ +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +class TopicNotFoundStatusTest { + + @Autowired + private TestRestTemplate restTemplate; + + @Test + void unknownTopicIdCurrentlyReturnsInternalServerError() { + ResponseEntity response = restTemplate.getForEntity("/topic/does-not-exist", String.class); + + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR); + } + + @Test + @Disabled("Enable, and delete unknownTopicIdCurrentlyReturnsInternalServerError, once an unknown id is a 404") + void unknownTopicIdShouldReturnNotFound() { + ResponseEntity response = restTemplate.getForEntity("/topic/does-not-exist", String.class); + + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND); + } + + @Test + void knownTopicIdReturnsOkWithTheUnchangedJsonShape() { + ResponseEntity response = restTemplate.getForEntity("/topic/spring", String.class); + + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(response.getBody()) + .contains("\"id\":\"spring\"") + .contains("\"subjectName\":\"Spring Framework\"") + .contains("\"subjectDescription\":\"Spring Framework Description\""); + } +} diff --git a/src/test/java/hello/declaration/TimeClientTest.java b/src/test/java/hello/declaration/TimeClientTest.java new file mode 100644 index 0000000..3778f26 --- /dev/null +++ b/src/test/java/hello/declaration/TimeClientTest.java @@ -0,0 +1,80 @@ +package hello.declaration; + +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; + +import org.junit.jupiter.api.Test; + +import hello.model.SimpleTimeClient; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Covers the {@code static} and {@code default} methods on the interface and the + * {@link SimpleTimeClient} implementation of them. + */ +class TimeClientTest { + + @Test + void getZoneIdResolvesAKnownZone() { + assertThat(TimeClient.getZoneId("Canada/Central")).isEqualTo(ZoneId.of("Canada/Central")); + } + + @Test + void getZoneIdFallsBackToTheSystemZoneForAnInvalidZone() { + assertThat(TimeClient.getZoneId("Not/A/Zone")).isEqualTo(ZoneId.systemDefault()); + assertThat(TimeClient.getZoneId("")).isEqualTo(ZoneId.systemDefault()); + } + + @Test + void getZonedDateTimeCombinesTheLocalDateTimeWithTheRequestedZone() { + SimpleTimeClient client = new SimpleTimeClient(); + client.setDateAndTime(2020, 5, 17, 13, 45, 30); + + ZonedDateTime zoned = client.getZonedDateTime("Canada/Central"); + + assertThat(zoned.toLocalDateTime()).isEqualTo(LocalDateTime.of(2020, 5, 17, 13, 45, 30)); + assertThat(zoned.getZone()).isEqualTo(ZoneId.of("Canada/Central")); + } + + @Test + void getZonedDateTimeUsesTheSystemZoneWhenTheZoneIsInvalid() { + SimpleTimeClient client = new SimpleTimeClient(); + + assertThat(client.getZonedDateTime("Middle/Earth").getZone()).isEqualTo(ZoneId.systemDefault()); + } + + @Test + void newClientIsInitialisedWithTheCurrentDateTime() { + LocalDateTime before = LocalDateTime.now().minusMinutes(1); + + SimpleTimeClient client = new SimpleTimeClient(); + + assertThat(client.getLocalDateTime()).isAfter(before); + assertThat(client.toString()).isEqualTo(client.getLocalDateTime().toString()); + } + + @Test + void setTimeKeepsTheDateAndReplacesTheTime() { + SimpleTimeClient client = new SimpleTimeClient(); + client.setDateAndTime(2020, 5, 17, 1, 2, 3); + + client.setTime(23, 59, 58); + + assertThat(client.getLocalDateTime()).isEqualTo(LocalDateTime.of(2020, 5, 17, 23, 59, 58)); + } + + @Test + void setDateKeepsTheTimeAndReplacesTheDate() { + SimpleTimeClient client = new SimpleTimeClient(); + client.setDateAndTime(2020, 5, 17, 8, 30, 0); + + // setDate/setDateAndTime declare their parameters as (day, month, year) but delegate to + // LocalDate.of(..) positionally, so the first argument is really the year. Asserted as + // implemented rather than as named. + client.setDate(2021, 12, 25); + + assertThat(client.getLocalDateTime()).isEqualTo(LocalDateTime.of(2021, 12, 25, 8, 30, 0)); + } +} diff --git a/src/test/java/hello/service/TopicServiceTest.java b/src/test/java/hello/service/TopicServiceTest.java new file mode 100644 index 0000000..ed97e35 --- /dev/null +++ b/src/test/java/hello/service/TopicServiceTest.java @@ -0,0 +1,191 @@ +package hello.service; + +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.stream.Collectors; + +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import hello.model.Topic; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +/** + * {@link TopicService} keeps its topics in a mutable instance field, so as a Spring singleton its + * state leaks between tests. These unit tests therefore build a brand new service in {@link BeforeEach} + * instead of injecting the bean: every test starts from the three seeded topics and nothing has to be + * undone afterwards. + */ +class TopicServiceTest { + + private TopicService topicService; + + @BeforeEach + void createFreshService() { + topicService = new TopicService(); + } + + /** + * Single place where a {@link Topic} accessor is used, so the parallel conversion of the models to + * records only has to touch one line in this class. + */ + private static List idsOf(List topics) { + return topics.stream().map(Topic::getId).collect(Collectors.toList()); + } + + @Test + void seedsThreeTopics() { + assertThat(idsOf(topicService.getAllTopics())) + .containsExactly("spring", "java", "javascript"); + } + + @Test + void getTopicWithIdReturnsTheMatchingTopic() { + Topic topic = topicService.getTopicWithId("java"); + + assertThat(idsOf(List.of(topic))).containsExactly("java"); + assertThat(topic.getSubjectName()).isEqualTo("Core Java"); + } + + @Test + void getTopicWithIdThrowsForAnUnknownId() { + // Current behaviour: Optional.get() on an empty Optional. Over HTTP this surfaces as a 500. + assertThatThrownBy(() -> topicService.getTopicWithId("does-not-exist")) + .isInstanceOf(NoSuchElementException.class); + } + + @Test + @Disabled("Enable together with the parallel change that makes an unknown id a proper 404") + void getTopicWithIdShouldReportAMissingTopicWithoutThrowing() { + // Replacement for getTopicWithIdThrowsForAnUnknownId once the service returns an empty + // Optional (or the controller translates the miss into HTTP 404). + assertThatCode(() -> topicService.getTopicWithId("does-not-exist")) + .doesNotThrowAnyException(); + } + + @Test + void addTopicAppendsToTheList() { + topicService.addTopic(new Topic("kotlin", "Kotlin", "Kotlin Description")); + + assertThat(idsOf(topicService.getAllTopics())).containsExactly("spring", "java", "javascript", "kotlin"); + } + + @Test + void updateTopicReplacesTheTopicInPlace() { + topicService.updateTopic("java", new Topic("java", "Updated Java", "Updated Description")); + + List topics = topicService.getAllTopics(); + assertThat(idsOf(topics)).containsExactly("spring", "java", "javascript"); + assertThat(topics.get(1).getSubjectName()).isEqualTo("Updated Java"); + } + + @Test + void updateTopicIsANoOpForAnUnknownId() { + topicService.updateTopic("kotlin", new Topic("kotlin", "Kotlin", "Kotlin Description")); + + assertThat(idsOf(topicService.getAllTopics())).containsExactly("spring", "java", "javascript"); + } + + @Test + void deleteTopicRemovesOnlyTheMatchingTopic() { + topicService.deleteTopic("java"); + + assertThat(idsOf(topicService.getAllTopics())).containsExactly("spring", "javascript"); + } + + @Test + void deleteTopicIsANoOpForAnUnknownId() { + topicService.deleteTopic("kotlin"); + + assertThat(idsOf(topicService.getAllTopics())).hasSize(3); + } + + @Test + void filterMinimumLengthForIdKeepsIdsStrictlyLongerThanTheGivenLength() { + assertThat(idsOf(topicService.filterMinimumLengthForId(4))) + .containsExactly("spring", "javascript"); + assertThat(idsOf(topicService.filterMinimumLengthForId(6))) + .containsExactly("javascript"); + assertThat(topicService.filterMinimumLengthForId(20)).isEmpty(); + } + + @Test + void sortTopicsWithIDSortsTheUnderlyingListById() { + assertThat(idsOf(topicService.sortTopicsWithID())) + .containsExactly("java", "javascript", "spring"); + + // The sort mutates the service's own list, which is exactly why these tests use a fresh instance. + assertThat(idsOf(topicService.getAllTopics())) + .containsExactly("java", "javascript", "spring"); + } + + @Test + void returnAllTopicIDWithStringSlicingJoinsIdsWithAColon() { + assertThat(topicService.returnAllTopicIDWithStringSlicing()).isEqualTo("spring:java:javascript"); + } + + @Test + void makeDistinctAndSortCharactersReturnsSortedDistinctCharacters() { + assertThat(topicService.makeDistinctAndSortCharacters("spring:java:javascript")) + .isEqualTo(":acgijnprstv"); + assertThat(topicService.makeDistinctAndSortCharacters("")).isEmpty(); + } + + @Test + void splitAllIdWithColonSelectIDWithJavaKeywordThenSortThenJoinKeepsOnlyJavaIds() { + assertThat(topicService.splitAllIdWithColonSelectIDWithJavaKeywordThenSortThenJoin("spring:java:javascript")) + .isEqualTo("java:javascript"); + assertThat(topicService.splitAllIdWithColonSelectIDWithJavaKeywordThenSortThenJoin("spring:kotlin")) + .isEmpty(); + } + + @Test + void findIdHavingCharacterMatchesIdsContainingG() { + assertThat(topicService.findIdHavingCharacter()).isEqualTo("[spring]"); + } + + // The file operations below walk the process working directory (the module base directory when run + // by Surefire) and read temp.txt from it. Their exact output changes whenever a file is added or + // removed from the repository, so they are asserted loosely on purpose. + + @Test + void findAllFilesInPathAndSortListsVisibleFilesInTheWorkingDirectory() { + String listed = topicService.findAllFilesInPathAndSort(); + + assertThat(listed).isNotNull().isNotEqualTo(" Error in IO"); + assertThat(listed).contains("pom.xml"); + assertThat(listed).doesNotContain(".git;"); + } + + @Test + void findParticularFileInPathAndSortReturnsAStringWithoutFailing() { + assertThat(topicService.findParticularFileInPathAndSort()) + .isNotNull() + .isNotEqualTo(" IO exception "); + } + + @Test + void findParticularFileInPathAndSortWithWalkFunctionReturnsAStringWithoutFailing() { + assertThat(topicService.findParticularFileInPathAndSortWithWalkFunction()) + .isNotNull() + .isNotEqualTo(" IO exception "); + } + + @Test + void readFileWithStreamFunctionReturnsTheLinesStartingWithPrint() { + Assumptions.assumeTrue(Files.exists(Paths.get("temp.txt")), "temp.txt is read relative to the working directory"); + + String read = topicService.readFileWithStreamFunction(); + + assertThat(read).isNotNull().isNotEqualTo(" IO exception "); + assertThat(read).contains(" Hello"); + assertThat(read).doesNotContain("print"); + } +} From 8e50a08f06fd7e3953b96edf7a89b46e5e9a2462 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Thu, 6 Aug 2026 16:36:35 +0000 Subject: [PATCH 7/8] feature: reconcile tests with the records, 404 and RestClient changes The test suite was written in parallel against the pre-modernization API: - Topic accessors are record components now (getId -> id) - getTopicWithId returns Optional and an unknown id is a 404, not a 500, so the placeholder assertions and their @Disabled twins collapse into one - the RestTemplate bean is a RestClient bean Co-Authored-By: alex.vyshetsky --- .../hello/ApplicationContextLoadTest.java | 4 ++-- .../controller/TopicNotFoundStatusTest.java | 17 +++---------- .../java/hello/service/TopicServiceTest.java | 24 ++++++------------- 3 files changed, 12 insertions(+), 33 deletions(-) diff --git a/src/test/java/hello/ApplicationContextLoadTest.java b/src/test/java/hello/ApplicationContextLoadTest.java index e92dbb7..d52b7dd 100644 --- a/src/test/java/hello/ApplicationContextLoadTest.java +++ b/src/test/java/hello/ApplicationContextLoadTest.java @@ -5,7 +5,7 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.ApplicationContext; import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.client.RestClient; import hello.controller.GreetingController; import hello.controller.HelloController; @@ -36,7 +36,7 @@ void exposesTheExpectedBeans() { assertThat(context.getBean(TopicController.class)).isNotNull(); assertThat(context.getBean(HelloController.class)).isNotNull(); assertThat(context.getBean(GreetingController.class)).isNotNull(); - assertThat(context.getBean(RestTemplate.class)).isNotNull(); + assertThat(context.getBean(RestClient.class)).isNotNull(); assertThat(context.getBean(JdbcTemplate.class)).isNotNull(); } diff --git a/src/test/java/hello/controller/TopicNotFoundStatusTest.java b/src/test/java/hello/controller/TopicNotFoundStatusTest.java index 398aed6..86e888b 100644 --- a/src/test/java/hello/controller/TopicNotFoundStatusTest.java +++ b/src/test/java/hello/controller/TopicNotFoundStatusTest.java @@ -1,6 +1,5 @@ package hello.controller; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @@ -15,10 +14,8 @@ * MockMvc rethrows unhandled exceptions instead of running the error dispatch, so this one case is * driven over a real connection. * - *

{@code TopicService.getTopicWithId} calls {@code Optional.get()} on a miss, which throws - * {@link java.util.NoSuchElementException} and surfaces as HTTP 500. That is asserted here as the - * current behaviour; the disabled test below is the replacement for when a parallel change - * turns the miss into a proper 404. + *

{@code TopicService.getTopicWithId} returns an empty {@link java.util.Optional} on a miss, which + * the controller translates into a 404. */ @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) class TopicNotFoundStatusTest { @@ -27,15 +24,7 @@ class TopicNotFoundStatusTest { private TestRestTemplate restTemplate; @Test - void unknownTopicIdCurrentlyReturnsInternalServerError() { - ResponseEntity response = restTemplate.getForEntity("/topic/does-not-exist", String.class); - - assertThat(response.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR); - } - - @Test - @Disabled("Enable, and delete unknownTopicIdCurrentlyReturnsInternalServerError, once an unknown id is a 404") - void unknownTopicIdShouldReturnNotFound() { + void unknownTopicIdReturnsNotFound() { ResponseEntity response = restTemplate.getForEntity("/topic/does-not-exist", String.class); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND); diff --git a/src/test/java/hello/service/TopicServiceTest.java b/src/test/java/hello/service/TopicServiceTest.java index ed97e35..3bae0f7 100644 --- a/src/test/java/hello/service/TopicServiceTest.java +++ b/src/test/java/hello/service/TopicServiceTest.java @@ -37,7 +37,7 @@ void createFreshService() { * records only has to touch one line in this class. */ private static List idsOf(List topics) { - return topics.stream().map(Topic::getId).collect(Collectors.toList()); + return topics.stream().map(Topic::id).collect(Collectors.toList()); } @Test @@ -48,26 +48,16 @@ void seedsThreeTopics() { @Test void getTopicWithIdReturnsTheMatchingTopic() { - Topic topic = topicService.getTopicWithId("java"); + Topic topic = topicService.getTopicWithId("java").orElseThrow(); assertThat(idsOf(List.of(topic))).containsExactly("java"); - assertThat(topic.getSubjectName()).isEqualTo("Core Java"); + assertThat(topic.subjectName()).isEqualTo("Core Java"); } @Test - void getTopicWithIdThrowsForAnUnknownId() { - // Current behaviour: Optional.get() on an empty Optional. Over HTTP this surfaces as a 500. - assertThatThrownBy(() -> topicService.getTopicWithId("does-not-exist")) - .isInstanceOf(NoSuchElementException.class); - } - - @Test - @Disabled("Enable together with the parallel change that makes an unknown id a proper 404") - void getTopicWithIdShouldReportAMissingTopicWithoutThrowing() { - // Replacement for getTopicWithIdThrowsForAnUnknownId once the service returns an empty - // Optional (or the controller translates the miss into HTTP 404). - assertThatCode(() -> topicService.getTopicWithId("does-not-exist")) - .doesNotThrowAnyException(); + void getTopicWithIdReportsAMissingTopicWithoutThrowing() { + assertThatCode(() -> topicService.getTopicWithId("does-not-exist")).doesNotThrowAnyException(); + assertThat(topicService.getTopicWithId("does-not-exist")).isEmpty(); } @Test @@ -83,7 +73,7 @@ void updateTopicReplacesTheTopicInPlace() { List topics = topicService.getAllTopics(); assertThat(idsOf(topics)).containsExactly("spring", "java", "javascript"); - assertThat(topics.get(1).getSubjectName()).isEqualTo("Updated Java"); + assertThat(topics.get(1).subjectName()).isEqualTo("Updated Java"); } @Test From a420508b33d2dcdb24a95d8df273089e3e01561f Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Thu, 6 Aug 2026 16:41:41 +0000 Subject: [PATCH 8/8] bug: make CI runnable without marketplace actions The runner cannot resolve actions/checkout or actions/setup-java for this repository (Service Unavailable at 'Getting action download info'), so the job failed before running anything. Checkout via git and use the JDK 21 already present on the runner image. Co-Authored-By: alex.vyshetsky --- .github/workflows/ci.yml | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0ccf481..f331610 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,17 +5,24 @@ on: branches: [master] pull_request: +# No marketplace actions are used here on purpose: runners for this repository cannot +# resolve them ("Failed to resolve action download info. Error: Service Unavailable"), +# so actions/checkout and actions/setup-java fail before the job body ever runs. +# Checkout is done with git directly, and the runner image already ships JDK 21. jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - name: Checkout + run: | + git init -q . + git remote add origin "https://x-access-token:${{ github.token }}@github.com/${{ github.repository }}.git" + git fetch -q --depth 1 origin "$GITHUB_SHA" + git checkout -q FETCH_HEAD - - uses: actions/setup-java@v4 - with: - java-version: '21' - distribution: temurin - cache: maven - - - name: Build and test - run: ./mvnw -B clean verify + - name: Build and test on JDK 21 + run: | + export JAVA_HOME="$JAVA_HOME_21_X64" + export PATH="$JAVA_HOME/bin:$PATH" + java -version + ./mvnw -B clean verify