diff --git a/kamco-make-dataset-generation/.gradle/8.14.3/checksums/checksums.lock b/kamco-make-dataset-generation/.gradle/8.14.3/checksums/checksums.lock
new file mode 100644
index 0000000..84f69a3
Binary files /dev/null and b/kamco-make-dataset-generation/.gradle/8.14.3/checksums/checksums.lock differ
diff --git a/kamco-make-dataset-generation/.gradle/8.14.3/checksums/md5-checksums.bin b/kamco-make-dataset-generation/.gradle/8.14.3/checksums/md5-checksums.bin
new file mode 100644
index 0000000..2fa0678
Binary files /dev/null and b/kamco-make-dataset-generation/.gradle/8.14.3/checksums/md5-checksums.bin differ
diff --git a/kamco-make-dataset-generation/.gradle/8.14.3/checksums/sha1-checksums.bin b/kamco-make-dataset-generation/.gradle/8.14.3/checksums/sha1-checksums.bin
new file mode 100644
index 0000000..5c44705
Binary files /dev/null and b/kamco-make-dataset-generation/.gradle/8.14.3/checksums/sha1-checksums.bin differ
diff --git a/kamco-make-dataset-generation/.gradle/8.14.3/executionHistory/executionHistory.bin b/kamco-make-dataset-generation/.gradle/8.14.3/executionHistory/executionHistory.bin
new file mode 100644
index 0000000..38f9904
Binary files /dev/null and b/kamco-make-dataset-generation/.gradle/8.14.3/executionHistory/executionHistory.bin differ
diff --git a/kamco-make-dataset-generation/.gradle/8.14.3/executionHistory/executionHistory.lock b/kamco-make-dataset-generation/.gradle/8.14.3/executionHistory/executionHistory.lock
new file mode 100644
index 0000000..90ab786
Binary files /dev/null and b/kamco-make-dataset-generation/.gradle/8.14.3/executionHistory/executionHistory.lock differ
diff --git a/kamco-make-dataset-generation/.gradle/8.14.3/fileChanges/last-build.bin b/kamco-make-dataset-generation/.gradle/8.14.3/fileChanges/last-build.bin
new file mode 100644
index 0000000..f76dd23
Binary files /dev/null and b/kamco-make-dataset-generation/.gradle/8.14.3/fileChanges/last-build.bin differ
diff --git a/kamco-make-dataset-generation/.gradle/8.14.3/fileHashes/fileHashes.bin b/kamco-make-dataset-generation/.gradle/8.14.3/fileHashes/fileHashes.bin
new file mode 100644
index 0000000..24a6148
Binary files /dev/null and b/kamco-make-dataset-generation/.gradle/8.14.3/fileHashes/fileHashes.bin differ
diff --git a/kamco-make-dataset-generation/.gradle/8.14.3/fileHashes/fileHashes.lock b/kamco-make-dataset-generation/.gradle/8.14.3/fileHashes/fileHashes.lock
new file mode 100644
index 0000000..91b1371
Binary files /dev/null and b/kamco-make-dataset-generation/.gradle/8.14.3/fileHashes/fileHashes.lock differ
diff --git a/kamco-make-dataset-generation/.gradle/8.14.3/fileHashes/resourceHashesCache.bin b/kamco-make-dataset-generation/.gradle/8.14.3/fileHashes/resourceHashesCache.bin
new file mode 100644
index 0000000..f954524
Binary files /dev/null and b/kamco-make-dataset-generation/.gradle/8.14.3/fileHashes/resourceHashesCache.bin differ
diff --git a/kamco-make-dataset-generation/.gradle/8.14.3/gc.properties b/kamco-make-dataset-generation/.gradle/8.14.3/gc.properties
new file mode 100644
index 0000000..e69de29
diff --git a/kamco-make-dataset-generation/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/kamco-make-dataset-generation/.gradle/buildOutputCleanup/buildOutputCleanup.lock
new file mode 100644
index 0000000..9e3e5d7
Binary files /dev/null and b/kamco-make-dataset-generation/.gradle/buildOutputCleanup/buildOutputCleanup.lock differ
diff --git a/kamco-make-dataset-generation/.gradle/buildOutputCleanup/cache.properties b/kamco-make-dataset-generation/.gradle/buildOutputCleanup/cache.properties
new file mode 100644
index 0000000..1fd9686
--- /dev/null
+++ b/kamco-make-dataset-generation/.gradle/buildOutputCleanup/cache.properties
@@ -0,0 +1,2 @@
+#Sun Feb 08 18:46:40 KST 2026
+gradle.version=8.14.3
diff --git a/kamco-make-dataset-generation/.gradle/buildOutputCleanup/outputFiles.bin b/kamco-make-dataset-generation/.gradle/buildOutputCleanup/outputFiles.bin
new file mode 100644
index 0000000..f4a1970
Binary files /dev/null and b/kamco-make-dataset-generation/.gradle/buildOutputCleanup/outputFiles.bin differ
diff --git a/kamco-make-dataset-generation/.gradle/file-system.probe b/kamco-make-dataset-generation/.gradle/file-system.probe
new file mode 100644
index 0000000..90b3e73
Binary files /dev/null and b/kamco-make-dataset-generation/.gradle/file-system.probe differ
diff --git a/kamco-make-dataset-generation/.gradle/vcs-1/gc.properties b/kamco-make-dataset-generation/.gradle/vcs-1/gc.properties
new file mode 100644
index 0000000..e69de29
diff --git a/kamco-make-dataset-generation/.idea/.gitignore b/kamco-make-dataset-generation/.idea/.gitignore
new file mode 100644
index 0000000..13566b8
--- /dev/null
+++ b/kamco-make-dataset-generation/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/kamco-make-dataset-generation/.idea/compiler.xml b/kamco-make-dataset-generation/.idea/compiler.xml
new file mode 100644
index 0000000..40c9d5a
--- /dev/null
+++ b/kamco-make-dataset-generation/.idea/compiler.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/kamco-make-dataset-generation/.idea/gradle.xml b/kamco-make-dataset-generation/.idea/gradle.xml
new file mode 100644
index 0000000..c6d035a
--- /dev/null
+++ b/kamco-make-dataset-generation/.idea/gradle.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/kamco-make-dataset-generation/.idea/misc.xml b/kamco-make-dataset-generation/.idea/misc.xml
new file mode 100644
index 0000000..596538b
--- /dev/null
+++ b/kamco-make-dataset-generation/.idea/misc.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/kamco-make-dataset-generation/build.gradle b/kamco-make-dataset-generation/build.gradle
new file mode 100644
index 0000000..7947e95
--- /dev/null
+++ b/kamco-make-dataset-generation/build.gradle
@@ -0,0 +1,45 @@
+plugins {
+ id 'java'
+ id 'org.springframework.boot' version '3.5.7'
+ id 'io.spring.dependency-management' version '1.1.7'
+}
+
+group = 'com.kamco.cd'
+version = '0.0.1-SNAPSHOT'
+
+java {
+ toolchain {
+ languageVersion = JavaLanguageVersion.of(21)
+ }
+}
+
+configurations {
+ compileOnly {
+ extendsFrom annotationProcessor
+ }
+}
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ implementation 'org.springframework.boot:spring-boot-starter-batch'
+ implementation 'org.springframework.boot:spring-boot-starter-jdbc'
+ compileOnly 'org.projectlombok:lombok'
+ runtimeOnly 'org.postgresql:postgresql'
+ annotationProcessor 'org.projectlombok:lombok'
+ testImplementation 'org.springframework.boot:spring-boot-starter-test'
+ testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
+
+ // JSON
+ implementation 'com.fasterxml.jackson.core:jackson-databind'
+}
+
+tasks.named('test') {
+ useJUnitPlatform()
+}
+
+bootJar {
+ archiveFileName = 'generator-dataset-for-training.jar'
+}
\ No newline at end of file
diff --git a/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/GeoJsonSchedulerApplication.class b/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/GeoJsonSchedulerApplication.class
new file mode 100644
index 0000000..177b31c
Binary files /dev/null and b/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/GeoJsonSchedulerApplication.class differ
diff --git a/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/batch/ExportGeoJsonJobConfig.class b/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/batch/ExportGeoJsonJobConfig.class
new file mode 100644
index 0000000..35064af
Binary files /dev/null and b/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/batch/ExportGeoJsonJobConfig.class differ
diff --git a/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/batch/ExportGeoJsonTasklet.class b/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/batch/ExportGeoJsonTasklet.class
new file mode 100644
index 0000000..5ac8d2f
Binary files /dev/null and b/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/batch/ExportGeoJsonTasklet.class differ
diff --git a/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/config/DockerProperties.class b/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/config/DockerProperties.class
new file mode 100644
index 0000000..ee2453a
Binary files /dev/null and b/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/config/DockerProperties.class differ
diff --git a/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$AnalCntInfo.class b/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$AnalCntInfo.class
new file mode 100644
index 0000000..19e26d0
Binary files /dev/null and b/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$AnalCntInfo.class differ
diff --git a/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$AnalMapSheetList$AnalMapSheetListBuilder.class b/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$AnalMapSheetList$AnalMapSheetListBuilder.class
new file mode 100644
index 0000000..344c86c
Binary files /dev/null and b/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$AnalMapSheetList$AnalMapSheetListBuilder.class differ
diff --git a/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$AnalMapSheetList.class b/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$AnalMapSheetList.class
new file mode 100644
index 0000000..ae8c356
Binary files /dev/null and b/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$AnalMapSheetList.class differ
diff --git a/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$CompleteLabelData$GeoJsonFeature.class b/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$CompleteLabelData$GeoJsonFeature.class
new file mode 100644
index 0000000..d012de1
Binary files /dev/null and b/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$CompleteLabelData$GeoJsonFeature.class differ
diff --git a/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$CompleteLabelData$Properties.class b/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$CompleteLabelData$Properties.class
new file mode 100644
index 0000000..96a321c
Binary files /dev/null and b/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$CompleteLabelData$Properties.class differ
diff --git a/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$CompleteLabelData.class b/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$CompleteLabelData.class
new file mode 100644
index 0000000..2a14cda
Binary files /dev/null and b/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$CompleteLabelData.class differ
diff --git a/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$FeatureCollection.class b/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$FeatureCollection.class
new file mode 100644
index 0000000..7be65c6
Binary files /dev/null and b/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$FeatureCollection.class differ
diff --git a/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto.class b/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto.class
new file mode 100644
index 0000000..5efc3b4
Binary files /dev/null and b/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto.class differ
diff --git a/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/enums/InspectState.class b/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/enums/InspectState.class
new file mode 100644
index 0000000..09ec616
Binary files /dev/null and b/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/enums/InspectState.class differ
diff --git a/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/enums/LabelMngState.class b/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/enums/LabelMngState.class
new file mode 100644
index 0000000..d12e2f1
Binary files /dev/null and b/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/enums/LabelMngState.class differ
diff --git a/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/repository/TrainingDataReviewJobRepository.class b/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/repository/TrainingDataReviewJobRepository.class
new file mode 100644
index 0000000..868b8b8
Binary files /dev/null and b/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/repository/TrainingDataReviewJobRepository.class differ
diff --git a/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/service/DockerRunnerService.class b/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/service/DockerRunnerService.class
new file mode 100644
index 0000000..ecbf1cd
Binary files /dev/null and b/kamco-make-dataset-generation/build/classes/java/main/com/kamco/cd/geojsonscheduler/service/DockerRunnerService.class differ
diff --git a/kamco-make-dataset-generation/build/libs/generator-dataset-for-training.jar b/kamco-make-dataset-generation/build/libs/generator-dataset-for-training.jar
new file mode 100644
index 0000000..d3e5c94
Binary files /dev/null and b/kamco-make-dataset-generation/build/libs/generator-dataset-for-training.jar differ
diff --git a/kamco-make-dataset-generation/build/libs/kamco-geojson-scheduler-0.0.1-SNAPSHOT-plain.jar b/kamco-make-dataset-generation/build/libs/kamco-geojson-scheduler-0.0.1-SNAPSHOT-plain.jar
new file mode 100644
index 0000000..4337d94
Binary files /dev/null and b/kamco-make-dataset-generation/build/libs/kamco-geojson-scheduler-0.0.1-SNAPSHOT-plain.jar differ
diff --git a/kamco-make-dataset-generation/build/resolvedMainClassName b/kamco-make-dataset-generation/build/resolvedMainClassName
new file mode 100644
index 0000000..1fe26ac
--- /dev/null
+++ b/kamco-make-dataset-generation/build/resolvedMainClassName
@@ -0,0 +1 @@
+com.kamco.cd.geojsonscheduler.GeoJsonSchedulerApplication
\ No newline at end of file
diff --git a/kamco-make-dataset-generation/build/resources/main/application-dev.yml b/kamco-make-dataset-generation/build/resources/main/application-dev.yml
new file mode 100644
index 0000000..9f7f5ea
--- /dev/null
+++ b/kamco-make-dataset-generation/build/resources/main/application-dev.yml
@@ -0,0 +1,11 @@
+spring:
+ datasource:
+ url: jdbc:postgresql://192.168.2.127:15432/kamco_cds
+ username: kamco_cds
+ password: kamco_cds_Q!W@E#R$
+ hikari:
+ minimum-idle: 2
+ maximum-pool-size: 5
+
+training-data:
+ geojson-dir: /kamco-nfs/dataset
diff --git a/kamco-make-dataset-generation/build/resources/main/application-local.yml b/kamco-make-dataset-generation/build/resources/main/application-local.yml
new file mode 100644
index 0000000..7cc0acf
--- /dev/null
+++ b/kamco-make-dataset-generation/build/resources/main/application-local.yml
@@ -0,0 +1,8 @@
+spring:
+ datasource:
+ url: jdbc:postgresql://localhost:5432/kamco_cds
+ username: kamco_cds
+ password: kamco_cds
+
+training-data:
+ geojson-dir: /tmp/geojson
diff --git a/kamco-make-dataset-generation/build/resources/main/application-prod.yml b/kamco-make-dataset-generation/build/resources/main/application-prod.yml
new file mode 100644
index 0000000..707a18c
--- /dev/null
+++ b/kamco-make-dataset-generation/build/resources/main/application-prod.yml
@@ -0,0 +1,11 @@
+spring:
+ datasource:
+ url: jdbc:postgresql://127.0.0.1:15432/kamco_cds
+ username: kamco_cds
+ password: kamco_cds_Q!W@E#R$
+ hikari:
+ minimum-idle: 2
+ maximum-pool-size: 5
+
+training-data:
+ geojson-dir: /kamco-nfs/dataset
diff --git a/kamco-make-dataset-generation/build/resources/main/application.yml b/kamco-make-dataset-generation/build/resources/main/application.yml
new file mode 100644
index 0000000..c1f830a
--- /dev/null
+++ b/kamco-make-dataset-generation/build/resources/main/application.yml
@@ -0,0 +1,33 @@
+spring:
+ application:
+ name: kamco-geojson-scheduler
+ profiles:
+ active: local
+ datasource:
+ driver-class-name: org.postgresql.Driver
+ hikari:
+ minimum-idle: 2
+ maximum-pool-size: 2
+ connection-timeout: 20000
+ idle-timeout: 300000
+ max-lifetime: 1800000
+ batch:
+ job:
+ enabled: true
+ initialize-schema: never
+
+training-data:
+ docker:
+ image: kamco-cd-dataset:latest
+ user: "1000:1000"
+ dataset-volume: /kamco-nfs/dataset:/dataset
+ images-volume: /kamco-nfs/images:/kamco-nfs:ro
+ input-root: /dataset
+ output-root: /dataset
+ patch-size: 512
+ overlap-pct: 50
+ train-val-test-ratio:
+ - "0.7"
+ - "0.2"
+ - "0.1"
+ keep-empty-ratio: 0.1
\ No newline at end of file
diff --git a/kamco-make-dataset-generation/build/tmp/bootJar/MANIFEST.MF b/kamco-make-dataset-generation/build/tmp/bootJar/MANIFEST.MF
new file mode 100644
index 0000000..58630c0
--- /dev/null
+++ b/kamco-make-dataset-generation/build/tmp/bootJar/MANIFEST.MF
@@ -0,0 +1,2 @@
+Manifest-Version: 1.0
+
diff --git a/kamco-make-dataset-generation/build/tmp/compileJava/compileTransaction/stash-dir/ExportGeoJsonJobConfig.class.uniqueId8 b/kamco-make-dataset-generation/build/tmp/compileJava/compileTransaction/stash-dir/ExportGeoJsonJobConfig.class.uniqueId8
new file mode 100644
index 0000000..35064af
Binary files /dev/null and b/kamco-make-dataset-generation/build/tmp/compileJava/compileTransaction/stash-dir/ExportGeoJsonJobConfig.class.uniqueId8 differ
diff --git a/kamco-make-dataset-generation/build/tmp/compileJava/compileTransaction/stash-dir/ExportGeoJsonTasklet.class.uniqueId0 b/kamco-make-dataset-generation/build/tmp/compileJava/compileTransaction/stash-dir/ExportGeoJsonTasklet.class.uniqueId0
new file mode 100644
index 0000000..eef1139
Binary files /dev/null and b/kamco-make-dataset-generation/build/tmp/compileJava/compileTransaction/stash-dir/ExportGeoJsonTasklet.class.uniqueId0 differ
diff --git a/kamco-make-dataset-generation/build/tmp/compileJava/compileTransaction/stash-dir/GeoJsonSchedulerApplication.class.uniqueId6 b/kamco-make-dataset-generation/build/tmp/compileJava/compileTransaction/stash-dir/GeoJsonSchedulerApplication.class.uniqueId6
new file mode 100644
index 0000000..831247e
Binary files /dev/null and b/kamco-make-dataset-generation/build/tmp/compileJava/compileTransaction/stash-dir/GeoJsonSchedulerApplication.class.uniqueId6 differ
diff --git a/kamco-make-dataset-generation/build/tmp/compileJava/compileTransaction/stash-dir/TrainingDataReviewJobDto$AnalCntInfo.class.uniqueId2 b/kamco-make-dataset-generation/build/tmp/compileJava/compileTransaction/stash-dir/TrainingDataReviewJobDto$AnalCntInfo.class.uniqueId2
new file mode 100644
index 0000000..04b6fd8
Binary files /dev/null and b/kamco-make-dataset-generation/build/tmp/compileJava/compileTransaction/stash-dir/TrainingDataReviewJobDto$AnalCntInfo.class.uniqueId2 differ
diff --git a/kamco-make-dataset-generation/build/tmp/compileJava/compileTransaction/stash-dir/TrainingDataReviewJobDto$AnalMapSheetList.class.uniqueId3 b/kamco-make-dataset-generation/build/tmp/compileJava/compileTransaction/stash-dir/TrainingDataReviewJobDto$AnalMapSheetList.class.uniqueId3
new file mode 100644
index 0000000..7c91436
Binary files /dev/null and b/kamco-make-dataset-generation/build/tmp/compileJava/compileTransaction/stash-dir/TrainingDataReviewJobDto$AnalMapSheetList.class.uniqueId3 differ
diff --git a/kamco-make-dataset-generation/build/tmp/compileJava/compileTransaction/stash-dir/TrainingDataReviewJobDto$CompleteLabelData$GeoJsonFeature.class.uniqueId4 b/kamco-make-dataset-generation/build/tmp/compileJava/compileTransaction/stash-dir/TrainingDataReviewJobDto$CompleteLabelData$GeoJsonFeature.class.uniqueId4
new file mode 100644
index 0000000..0ec9caf
Binary files /dev/null and b/kamco-make-dataset-generation/build/tmp/compileJava/compileTransaction/stash-dir/TrainingDataReviewJobDto$CompleteLabelData$GeoJsonFeature.class.uniqueId4 differ
diff --git a/kamco-make-dataset-generation/build/tmp/compileJava/compileTransaction/stash-dir/TrainingDataReviewJobDto$CompleteLabelData$Properties.class.uniqueId10 b/kamco-make-dataset-generation/build/tmp/compileJava/compileTransaction/stash-dir/TrainingDataReviewJobDto$CompleteLabelData$Properties.class.uniqueId10
new file mode 100644
index 0000000..6717ab8
Binary files /dev/null and b/kamco-make-dataset-generation/build/tmp/compileJava/compileTransaction/stash-dir/TrainingDataReviewJobDto$CompleteLabelData$Properties.class.uniqueId10 differ
diff --git a/kamco-make-dataset-generation/build/tmp/compileJava/compileTransaction/stash-dir/TrainingDataReviewJobDto$CompleteLabelData.class.uniqueId5 b/kamco-make-dataset-generation/build/tmp/compileJava/compileTransaction/stash-dir/TrainingDataReviewJobDto$CompleteLabelData.class.uniqueId5
new file mode 100644
index 0000000..120f727
Binary files /dev/null and b/kamco-make-dataset-generation/build/tmp/compileJava/compileTransaction/stash-dir/TrainingDataReviewJobDto$CompleteLabelData.class.uniqueId5 differ
diff --git a/kamco-make-dataset-generation/build/tmp/compileJava/compileTransaction/stash-dir/TrainingDataReviewJobDto$FeatureCollection.class.uniqueId1 b/kamco-make-dataset-generation/build/tmp/compileJava/compileTransaction/stash-dir/TrainingDataReviewJobDto$FeatureCollection.class.uniqueId1
new file mode 100644
index 0000000..31799e2
Binary files /dev/null and b/kamco-make-dataset-generation/build/tmp/compileJava/compileTransaction/stash-dir/TrainingDataReviewJobDto$FeatureCollection.class.uniqueId1 differ
diff --git a/kamco-make-dataset-generation/build/tmp/compileJava/compileTransaction/stash-dir/TrainingDataReviewJobDto.class.uniqueId9 b/kamco-make-dataset-generation/build/tmp/compileJava/compileTransaction/stash-dir/TrainingDataReviewJobDto.class.uniqueId9
new file mode 100644
index 0000000..951e39a
Binary files /dev/null and b/kamco-make-dataset-generation/build/tmp/compileJava/compileTransaction/stash-dir/TrainingDataReviewJobDto.class.uniqueId9 differ
diff --git a/kamco-make-dataset-generation/build/tmp/compileJava/compileTransaction/stash-dir/TrainingDataReviewJobRepository.class.uniqueId7 b/kamco-make-dataset-generation/build/tmp/compileJava/compileTransaction/stash-dir/TrainingDataReviewJobRepository.class.uniqueId7
new file mode 100644
index 0000000..fc11cbb
Binary files /dev/null and b/kamco-make-dataset-generation/build/tmp/compileJava/compileTransaction/stash-dir/TrainingDataReviewJobRepository.class.uniqueId7 differ
diff --git a/kamco-make-dataset-generation/build/tmp/compileJava/previous-compilation-data.bin b/kamco-make-dataset-generation/build/tmp/compileJava/previous-compilation-data.bin
new file mode 100644
index 0000000..4f0245c
Binary files /dev/null and b/kamco-make-dataset-generation/build/tmp/compileJava/previous-compilation-data.bin differ
diff --git a/kamco-make-dataset-generation/build/tmp/jar/MANIFEST.MF b/kamco-make-dataset-generation/build/tmp/jar/MANIFEST.MF
new file mode 100644
index 0000000..58630c0
--- /dev/null
+++ b/kamco-make-dataset-generation/build/tmp/jar/MANIFEST.MF
@@ -0,0 +1,2 @@
+Manifest-Version: 1.0
+
diff --git a/kamco-make-dataset-generation/gradle/linux/pack_offline_bundle_airgap.sh b/kamco-make-dataset-generation/gradle/linux/pack_offline_bundle_airgap.sh
new file mode 100644
index 0000000..9cc9fc5
--- /dev/null
+++ b/kamco-make-dataset-generation/gradle/linux/pack_offline_bundle_airgap.sh
@@ -0,0 +1,550 @@
+#!/bin/bash
+# pack_offline_bundle_airgap.sh
+# ============================================================================
+# Gradle Offline Bundle Packer
+# ============================================================================
+# Version: 4.0
+#
+# WORKFLOW:
+# 1. [ONLINE] Build project (./gradlew bootJar) - downloads all deps
+# 2. [ONLINE] Test run (./gradlew bootRun) - verify app works
+# 3. [OFFLINE TEST] Verify offline build works
+# 4. Create bundle with all cached dependencies
+#
+# REQUIREMENTS:
+# - Internet connection (for initial build)
+# - Project with gradlew
+# ============================================================================
+
+set -e
+
+# ============================================================================
+# Configuration
+# ============================================================================
+WRAPPER_SEED_PATH="wrapper_jar_seed"
+OFFLINE_HOME_NAME="_offline_gradle_home"
+BOOTRUN_TIMEOUT_SECONDS=60
+
+# Color codes
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+CYAN='\033[0;36m'
+GRAY='\033[0;90m'
+WHITE='\033[1;37m'
+NC='\033[0m' # No Color
+
+echo ""
+echo -e "${CYAN}============================================================${NC}"
+echo -e "${CYAN} Gradle Offline Bundle Packer v4.0${NC}"
+echo -e "${CYAN}============================================================${NC}"
+echo ""
+echo -e "${WHITE} This script will:${NC}"
+echo -e "${GRAY} 1. Build project with internet (download dependencies)${NC}"
+echo -e "${GRAY} 2. Test run application (verify it works)${NC}"
+echo -e "${GRAY} 3. Test offline build (verify cache is complete)${NC}"
+echo -e "${GRAY} 4. Create offline bundle for air-gapped environment${NC}"
+echo ""
+echo -e "${CYAN}============================================================${NC}"
+echo ""
+
+# ============================================================================
+# [1/20] Check Current Directory
+# ============================================================================
+echo -e "${YELLOW}==[1/20] Check Current Directory ==${NC}"
+ROOT="$(pwd)"
+echo "ROOT_DIR: $ROOT"
+echo ""
+
+# ============================================================================
+# [2/20] Check Required Files
+# ============================================================================
+echo -e "${YELLOW}==[2/20] Check Required Files ==${NC}"
+
+if [ ! -f "./gradlew" ]; then
+ echo -e "${RED}ERROR: gradlew not found. Run from project root.${NC}"
+ exit 1
+fi
+chmod +x ./gradlew
+echo -e "${GREEN}[OK] gradlew${NC}"
+
+BUILD_FILE=""
+if [ -f "./build.gradle" ]; then
+ BUILD_FILE="build.gradle"
+elif [ -f "./build.gradle.kts" ]; then
+ BUILD_FILE="build.gradle.kts"
+else
+ echo -e "${RED}ERROR: build.gradle(.kts) not found.${NC}"
+ exit 1
+fi
+echo -e "${GREEN}[OK] $BUILD_FILE${NC}"
+
+SETTINGS_FILE=""
+if [ -f "./settings.gradle" ]; then
+ SETTINGS_FILE="settings.gradle"
+ echo -e "${GREEN}[OK] $SETTINGS_FILE${NC}"
+elif [ -f "./settings.gradle.kts" ]; then
+ SETTINGS_FILE="settings.gradle.kts"
+ echo -e "${GREEN}[OK] $SETTINGS_FILE${NC}"
+fi
+echo ""
+
+# ============================================================================
+# [3/20] Check Gradle Wrapper
+# ============================================================================
+echo -e "${YELLOW}==[3/20] Check Gradle Wrapper ==${NC}"
+
+WRAPPER_DIR="$ROOT/gradle/wrapper"
+WRAPPER_JAR="$WRAPPER_DIR/gradle-wrapper.jar"
+WRAPPER_PROP="$WRAPPER_DIR/gradle-wrapper.properties"
+
+mkdir -p "$WRAPPER_DIR"
+
+if [ ! -f "$WRAPPER_PROP" ]; then
+ echo -e "${RED}ERROR: gradle-wrapper.properties not found.${NC}"
+ exit 1
+fi
+
+if [ ! -f "$WRAPPER_JAR" ]; then
+ SEED_JAR="$ROOT/$WRAPPER_SEED_PATH/gradle-wrapper.jar"
+ if [ -f "$SEED_JAR" ]; then
+ cp "$SEED_JAR" "$WRAPPER_JAR"
+ echo -e "${GREEN}[OK] Wrapper jar injected from seed${NC}"
+ else
+ echo -e "${RED}ERROR: gradle-wrapper.jar missing${NC}"
+ exit 1
+ fi
+else
+ echo -e "${GREEN}[OK] gradle-wrapper.jar exists${NC}"
+fi
+
+# Create seed backup
+SEED_DIR="$ROOT/$WRAPPER_SEED_PATH"
+if [ ! -d "$SEED_DIR" ]; then
+ mkdir -p "$SEED_DIR"
+ cp "$WRAPPER_JAR" "$SEED_DIR/gradle-wrapper.jar"
+fi
+echo ""
+
+# ============================================================================
+# [4/20] Set GRADLE_USER_HOME (Project Local)
+# ============================================================================
+echo -e "${YELLOW}==[4/20] Set GRADLE_USER_HOME ==${NC}"
+
+OFFLINE_HOME="$ROOT/$OFFLINE_HOME_NAME"
+mkdir -p "$OFFLINE_HOME"
+export GRADLE_USER_HOME="$OFFLINE_HOME"
+
+echo -e "${CYAN}GRADLE_USER_HOME = $GRADLE_USER_HOME${NC}"
+echo -e "${GRAY}[INFO] All dependencies will be cached in project folder${NC}"
+echo ""
+
+# ============================================================================
+# [5/20] Check Internet Connection
+# ============================================================================
+echo -e "${YELLOW}==[5/20] Check Internet Connection ==${NC}"
+
+HAS_INTERNET=false
+TEST_HOSTS=("plugins.gradle.org" "repo.maven.apache.org" "repo1.maven.org")
+
+for TEST_HOST in "${TEST_HOSTS[@]}"; do
+ if ping -c 1 -W 3 "$TEST_HOST" &>/dev/null; then
+ HAS_INTERNET=true
+ echo -e "${GREEN}[OK] Connected to $TEST_HOST${NC}"
+ break
+ fi
+done
+
+if [ "$HAS_INTERNET" = false ]; then
+ # Try DNS resolution as fallback
+ if nslookup google.com &>/dev/null || host google.com &>/dev/null; then
+ HAS_INTERNET=true
+ echo -e "${GREEN}[OK] Internet available (DNS)${NC}"
+ fi
+fi
+
+if [ "$HAS_INTERNET" = false ]; then
+ echo ""
+ echo -e "${RED}============================================================${NC}"
+ echo -e "${RED} ERROR: No Internet Connection!${NC}"
+ echo -e "${RED}============================================================${NC}"
+ echo ""
+ echo -e "${YELLOW}This script requires internet for initial build.${NC}"
+ echo -e "${YELLOW}Please connect to internet and run again.${NC}"
+ echo ""
+ exit 1
+fi
+echo ""
+
+# ============================================================================
+# [6/20] Initial Gradle Setup
+# ============================================================================
+echo -e "${YELLOW}==[6/20] Initial Gradle Setup ==${NC}"
+echo -e "${GRAY}[INFO] Downloading Gradle distribution...${NC}"
+
+if ./gradlew --version &>/dev/null; then
+ GRADLE_VERSION=$(./gradlew --version 2>&1 | grep "^Gradle" | awk '{print $2}')
+ echo -e "${GREEN}[OK] Gradle $GRADLE_VERSION${NC}"
+else
+ echo -e "${RED}[ERROR] Gradle setup failed${NC}"
+ exit 1
+fi
+echo ""
+
+# ============================================================================
+# [7/20] ONLINE BUILD - bootJar (Download All Dependencies)
+# ============================================================================
+echo -e "${YELLOW}==[7/20] ONLINE BUILD - bootJar ==${NC}"
+echo ""
+echo -e "${CYAN}============================================================${NC}"
+echo -e "${CYAN} ONLINE BUILD (with Internet)${NC}"
+echo -e "${CYAN} Downloading all dependencies to local cache${NC}"
+echo -e "${CYAN}============================================================${NC}"
+echo ""
+
+BUILD_SUCCESS=false
+
+./gradlew clean bootJar --no-daemon
+if [ $? -eq 0 ]; then
+ BUILD_SUCCESS=true
+ echo ""
+ echo -e "${GREEN}============================================================${NC}"
+ echo -e "${GREEN} ONLINE BUILD SUCCESS!${NC}"
+ echo -e "${GREEN}============================================================${NC}"
+ echo ""
+
+ if [ -d "./build/libs" ]; then
+ echo -e "${CYAN}JAR files:${NC}"
+ ls -lh ./build/libs/*.jar 2>/dev/null | awk '{print " " $9 " (" $5 ")"}'
+ fi
+else
+ echo ""
+ echo -e "${RED}============================================================${NC}"
+ echo -e "${RED} BUILD FAILED!${NC}"
+ echo -e "${RED}============================================================${NC}"
+ echo ""
+ echo -e "${YELLOW}Build failed. Cannot continue.${NC}"
+ exit 1
+fi
+echo ""
+
+# ============================================================================
+# [8/20] Stop Daemons
+# ============================================================================
+echo -e "${YELLOW}==[8/20] Stop Daemons ==${NC}"
+
+./gradlew --stop &>/dev/null || true
+sleep 2
+echo -e "${GREEN}[OK] Daemons stopped${NC}"
+echo ""
+
+# ============================================================================
+# [9/20] ONLINE TEST - bootRun (Verify Application Works)
+# ============================================================================
+echo -e "${YELLOW}==[9/20] ONLINE TEST - bootRun ==${NC}"
+echo ""
+echo -e "${CYAN}============================================================${NC}"
+echo -e "${CYAN} Testing application startup (timeout: ${BOOTRUN_TIMEOUT_SECONDS}s)${NC}"
+echo -e "${CYAN} Will automatically stop after successful startup${NC}"
+echo -e "${CYAN}============================================================${NC}"
+echo ""
+
+BOOTRUN_SUCCESS=false
+
+timeout ${BOOTRUN_TIMEOUT_SECONDS}s ./gradlew bootRun --no-daemon &
+BOOTRUN_PID=$!
+
+sleep 10
+
+if ps -p $BOOTRUN_PID &>/dev/null; then
+ BOOTRUN_SUCCESS=true
+ echo ""
+ echo -e "${GREEN}[OK] Application started successfully${NC}"
+ kill $BOOTRUN_PID &>/dev/null || true
+ sleep 2
+else
+ echo ""
+ echo -e "${YELLOW}[WARN] Application may not have started properly${NC}"
+fi
+
+# Cleanup
+pkill -f "gradle.*bootRun" &>/dev/null || true
+sleep 2
+echo ""
+
+# ============================================================================
+# [10/20] Stop Daemons Again
+# ============================================================================
+echo -e "${YELLOW}==[10/20] Stop Daemons Again ==${NC}"
+
+./gradlew --stop &>/dev/null || true
+sleep 2
+echo -e "${GREEN}[OK] Daemons stopped${NC}"
+echo ""
+
+# ============================================================================
+# [11/20] OFFLINE BUILD TEST (Verify Cache Completeness)
+# ============================================================================
+echo -e "${YELLOW}==[11/20] OFFLINE BUILD TEST ==${NC}"
+echo ""
+echo -e "${CYAN}============================================================${NC}"
+echo -e "${CYAN} OFFLINE BUILD TEST (--offline flag)${NC}"
+echo -e "${CYAN} Verifying all dependencies are cached${NC}"
+echo -e "${CYAN}============================================================${NC}"
+echo ""
+
+OFFLINE_SUCCESS=false
+
+./gradlew clean bootJar --offline --no-daemon
+if [ $? -eq 0 ]; then
+ OFFLINE_SUCCESS=true
+ echo ""
+ echo -e "${GREEN}============================================================${NC}"
+ echo -e "${GREEN} OFFLINE BUILD TEST PASSED!${NC}"
+ echo -e "${GREEN}============================================================${NC}"
+ echo ""
+ echo -e "${GREEN}[OK] All dependencies are cached${NC}"
+else
+ echo ""
+ echo -e "${RED}============================================================${NC}"
+ echo -e "${RED} OFFLINE BUILD TEST FAILED!${NC}"
+ echo -e "${RED}============================================================${NC}"
+ echo ""
+ echo -e "${YELLOW}Some dependencies may be missing from cache.${NC}"
+ echo -e "${YELLOW}The bundle may not work in air-gapped environment.${NC}"
+ echo ""
+
+ read -p "Continue anyway? (y/N): " -n 1 -r
+ echo
+ if [[ ! $REPLY =~ ^[Yy]$ ]]; then
+ exit 1
+ fi
+fi
+echo ""
+
+# ============================================================================
+# [12/20] Stop Daemons Before Archive
+# ============================================================================
+echo -e "${YELLOW}==[12/20] Stop Daemons Before Archive ==${NC}"
+
+./gradlew --stop &>/dev/null || true
+sleep 2
+echo -e "${GREEN}[OK] Daemons stopped${NC}"
+echo ""
+
+# ============================================================================
+# [13/20] Verify settings.gradle for Offline
+# ============================================================================
+echo -e "${YELLOW}==[13/20] Verify settings.gradle ==${NC}"
+
+if [ -n "$SETTINGS_FILE" ]; then
+ if grep -q "mavenLocal()" "$SETTINGS_FILE" && grep -q "pluginManagement" "$SETTINGS_FILE"; then
+ echo -e "${GREEN}[OK] settings.gradle configured for offline${NC}"
+ else
+ echo -e "${YELLOW}[WARN] settings.gradle may need offline configuration${NC}"
+ echo -e "${GRAY}[INFO] Consider adding mavenLocal() to pluginManagement and repositories${NC}"
+ fi
+else
+ echo -e "${GRAY}[INFO] No settings.gradle found${NC}"
+fi
+echo ""
+
+# ============================================================================
+# [14/20] Create Helper Scripts
+# ============================================================================
+echo -e "${YELLOW}==[14/20] Create Helper Scripts ==${NC}"
+
+# run_offline_build.sh
+cat > "$ROOT/run_offline_build.sh" << 'EOF'
+#!/bin/bash
+# run_offline_build.sh - Build JAR offline
+export GRADLE_USER_HOME="$(pwd)/_offline_gradle_home"
+echo "GRADLE_USER_HOME = $GRADLE_USER_HOME"
+echo ""
+./gradlew --offline bootJar --no-daemon
+if [ $? -eq 0 ]; then
+ echo ""
+ echo "BUILD SUCCESS!"
+ echo ""
+ echo "JAR files:"
+ ls -lh ./build/libs/*.jar 2>/dev/null | awk '{print " " $9}'
+else
+ echo "BUILD FAILED"
+fi
+EOF
+chmod +x "$ROOT/run_offline_build.sh"
+echo -e "${GREEN}[OK] run_offline_build.sh${NC}"
+
+# run_offline_bootrun.sh
+cat > "$ROOT/run_offline_bootrun.sh" << 'EOF'
+#!/bin/bash
+# run_offline_bootrun.sh - Run application offline
+export GRADLE_USER_HOME="$(pwd)/_offline_gradle_home"
+echo "GRADLE_USER_HOME = $GRADLE_USER_HOME"
+echo ""
+echo "Starting application (Ctrl+C to stop)..."
+echo ""
+./gradlew --offline bootRun --no-daemon
+EOF
+chmod +x "$ROOT/run_offline_bootrun.sh"
+echo -e "${GREEN}[OK] run_offline_bootrun.sh${NC}"
+echo ""
+
+# ============================================================================
+# [15/20] Final Daemon Cleanup
+# ============================================================================
+echo -e "${YELLOW}==[15/20] Final Daemon Cleanup ==${NC}"
+
+./gradlew --stop &>/dev/null || true
+sleep 2
+echo -e "${GREEN}[OK] Daemons stopped${NC}"
+echo ""
+
+# ============================================================================
+# [16/20] Clean Lock Files
+# ============================================================================
+echo -e "${YELLOW}==[16/20] Clean Lock Files ==${NC}"
+
+DAEMON_DIR="$OFFLINE_HOME/daemon"
+if [ -d "$DAEMON_DIR" ]; then
+ rm -rf "$DAEMON_DIR" 2>/dev/null || true
+fi
+
+find "$OFFLINE_HOME" -type f \( -name "*.lock" -o -name "*.log" -o -name "*.tmp" \) -delete 2>/dev/null || true
+
+echo -e "${GREEN}[OK] Lock files cleaned${NC}"
+echo ""
+
+# ============================================================================
+# [17/20] Calculate Cache Size
+# ============================================================================
+echo -e "${YELLOW}==[17/20] Cache Summary ==${NC}"
+
+CACHES_DIR="$OFFLINE_HOME/caches"
+WRAPPER_DISTS="$OFFLINE_HOME/wrapper/dists"
+
+TOTAL_SIZE=0
+
+if [ -d "$CACHES_DIR" ]; then
+ SIZE=$(du -sb "$CACHES_DIR" 2>/dev/null | cut -f1)
+ TOTAL_SIZE=$((TOTAL_SIZE + SIZE))
+ SIZE_MB=$(echo "scale=2; $SIZE / 1048576" | bc)
+ echo -e "${CYAN}[INFO] Dependencies: ${SIZE_MB} MB${NC}"
+fi
+
+if [ -d "$WRAPPER_DISTS" ]; then
+ SIZE=$(du -sb "$WRAPPER_DISTS" 2>/dev/null | cut -f1)
+ TOTAL_SIZE=$((TOTAL_SIZE + SIZE))
+ SIZE_MB=$(echo "scale=2; $SIZE / 1048576" | bc)
+ echo -e "${CYAN}[INFO] Gradle dist: ${SIZE_MB} MB${NC}"
+fi
+
+TOTAL_MB=$(echo "scale=2; $TOTAL_SIZE / 1048576" | bc)
+echo -e "${CYAN}[INFO] Total cache: ${TOTAL_MB} MB${NC}"
+echo ""
+
+# ============================================================================
+# [18/20] Create Archive
+# ============================================================================
+echo -e "${YELLOW}==[18/20] Create Archive ==${NC}"
+
+BASE_NAME=$(basename "$ROOT")
+TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
+PARENT=$(dirname "$ROOT")
+ARCHIVE_PATH="${PARENT}/${BASE_NAME}_offline_bundle_${TIMESTAMP}.tar.gz"
+
+echo "Archive: $ARCHIVE_PATH"
+echo -e "${GRAY}[INFO] Creating archive (this may take several minutes)...${NC}"
+
+tar -czf "$ARCHIVE_PATH" \
+ --exclude=".git" \
+ --exclude=".idea" \
+ --exclude=".DS_Store" \
+ --exclude="*.log" \
+ --exclude="*.lock" \
+ --exclude="_offline_gradle_home/daemon" \
+ --exclude="_offline_gradle_home/native" \
+ --exclude="_offline_gradle_home/jdks" \
+ --exclude="build" \
+ --exclude="out" \
+ --exclude=".gradle" \
+ -C "$ROOT" .
+
+if [ $? -ne 0 ]; then
+ echo -e "${RED}ERROR: tar failed${NC}"
+ exit 1
+fi
+
+ARCHIVE_SIZE=$(stat -f%z "$ARCHIVE_PATH" 2>/dev/null || stat -c%s "$ARCHIVE_PATH" 2>/dev/null)
+ARCHIVE_SIZE_MB=$(echo "scale=2; $ARCHIVE_SIZE / 1048576" | bc)
+echo -e "${GREEN}[OK] Archive created: ${ARCHIVE_SIZE_MB} MB${NC}"
+echo ""
+
+# ============================================================================
+# [19/20] Verify Archive
+# ============================================================================
+echo -e "${YELLOW}==[19/20] Verify Archive ==${NC}"
+
+CHECKS=(
+ "gradle/wrapper/gradle-wrapper.jar"
+ "gradlew"
+ "_offline_gradle_home/caches"
+ "run_offline_build.sh"
+)
+
+for CHECK in "${CHECKS[@]}"; do
+ if tar -tzf "$ARCHIVE_PATH" | grep -q "$CHECK"; then
+ echo -e " ${GREEN}[OK] $CHECK${NC}"
+ else
+ echo -e " ${YELLOW}[WARN] $CHECK${NC}"
+ fi
+done
+echo ""
+
+# ============================================================================
+# [20/20] Complete
+# ============================================================================
+echo -e "${GREEN}============================================================${NC}"
+echo -e "${GREEN} BUNDLE CREATION COMPLETE!${NC}"
+echo -e "${GREEN}============================================================${NC}"
+echo ""
+echo -e "${CYAN}Archive: $ARCHIVE_PATH${NC}"
+echo -e "${CYAN}Size: ${ARCHIVE_SIZE_MB} MB${NC}"
+echo ""
+
+echo -e "${CYAN}============================================================${NC}"
+echo -e "${CYAN} Test Results${NC}"
+echo -e "${CYAN}============================================================${NC}"
+if [ "$BUILD_SUCCESS" = true ]; then
+ echo -e " Online build (bootJar): ${GREEN}PASSED${NC}"
+else
+ echo -e " Online build (bootJar): ${RED}FAILED${NC}"
+fi
+if [ "$BOOTRUN_SUCCESS" = true ]; then
+ echo -e " Online test (bootRun): ${GREEN}PASSED${NC}"
+else
+ echo -e " Online test (bootRun): ${YELLOW}SKIPPED${NC}"
+fi
+if [ "$OFFLINE_SUCCESS" = true ]; then
+ echo -e " Offline build test: ${GREEN}PASSED${NC}"
+else
+ echo -e " Offline build test: ${RED}FAILED${NC}"
+fi
+echo ""
+
+echo -e "${YELLOW}============================================================${NC}"
+echo -e "${YELLOW} Usage in Air-gapped Environment${NC}"
+echo -e "${YELLOW}============================================================${NC}"
+echo ""
+echo -e "${WHITE}Option 1: Use unpack script${NC}"
+echo -e "${GRAY} ./unpack_and_offline_build_airgap.sh${NC}"
+echo ""
+echo -e "${WHITE}Option 2: Manual extraction${NC}"
+echo -e "${GRAY} tar -xzf .tar.gz${NC}"
+echo -e "${GRAY} cd ${NC}"
+echo -e "${GRAY} ./run_offline_build.sh${NC}"
+echo ""
+echo -e "${WHITE}Option 3: Direct commands${NC}"
+echo -e "${GRAY} export GRADLE_USER_HOME=\"./_offline_gradle_home\"${NC}"
+echo -e "${GRAY} ./gradlew --offline bootJar --no-daemon${NC}"
+echo ""
diff --git a/kamco-make-dataset-generation/gradle/linux/unpack_and_offline_build_airgap.sh b/kamco-make-dataset-generation/gradle/linux/unpack_and_offline_build_airgap.sh
new file mode 100644
index 0000000..b279202
--- /dev/null
+++ b/kamco-make-dataset-generation/gradle/linux/unpack_and_offline_build_airgap.sh
@@ -0,0 +1,347 @@
+#!/bin/bash
+# unpack_and_offline_build_airgap.sh
+# ============================================================================
+# Execution Environment: OFFLINE (Air-gapped, No Internet)
+# Purpose: Extract bundle and run offline build
+# ============================================================================
+# Linux Bash Script
+# Version: 3.1
+#
+# IMPORTANT: This script automatically:
+# 1. Extracts the archive
+# 2. Sets GRADLE_USER_HOME to project local cache
+# 3. Configures settings.gradle for offline resolution
+# 4. Runs build with --offline flag
+# ============================================================================
+
+set -e
+
+# ============================================================================
+# Configuration
+# ============================================================================
+WRAPPER_SEED_PATH="wrapper_jar_seed"
+OFFLINE_HOME_NAME="_offline_gradle_home"
+
+# Color codes
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+CYAN='\033[0;36m'
+GRAY='\033[0;90m'
+WHITE='\033[1;37m'
+NC='\033[0m' # No Color
+
+echo ""
+echo -e "${CYAN}============================================================${NC}"
+echo -e "${CYAN} Gradle Offline Build Runner${NC}"
+echo -e "${CYAN} Environment: AIR-GAPPED (No Internet)${NC}"
+echo -e "${CYAN} Mode: Fully Offline (--offline enforced)${NC}"
+echo -e "${CYAN}============================================================${NC}"
+echo ""
+
+# ============================================================================
+# [1/16] Check Current Directory
+# ============================================================================
+echo -e "${YELLOW}==[1/16] Check Current Directory ==${NC}"
+START_DIR="$(pwd)"
+echo "PWD: $START_DIR"
+echo ""
+
+# ============================================================================
+# [2/16] Select Archive
+# ============================================================================
+echo -e "${YELLOW}==[2/16] Select Archive ==${NC}"
+
+ARCHIVE=""
+if [ $# -ge 1 ]; then
+ ARCHIVE="$1"
+fi
+
+if [ -z "$ARCHIVE" ]; then
+ # Auto-detect most recent .tar.gz file
+ ARCHIVE=$(find "$START_DIR" -maxdepth 1 -type f \( -name "*.tar.gz" -o -name "*.tgz" \) -printf '%T@ %p\n' 2>/dev/null | sort -rn | head -1 | cut -d' ' -f2-)
+
+ if [ -z "$ARCHIVE" ]; then
+ echo -e "${RED}[ERROR] No archive found${NC}"
+ ls -lh "$START_DIR"
+ exit 1
+ fi
+
+ echo -e "${CYAN}[AUTO] $(basename "$ARCHIVE")${NC}"
+else
+ if [ ! -f "$ARCHIVE" ]; then
+ ARCHIVE="$START_DIR/$ARCHIVE"
+ fi
+ echo -e "${CYAN}[USER] $(basename "$ARCHIVE")${NC}"
+fi
+
+if [ ! -f "$ARCHIVE" ]; then
+ echo -e "${RED}ERROR: Archive not found: $ARCHIVE${NC}"
+ exit 1
+fi
+
+ARCHIVE_SIZE=$(stat -f%z "$ARCHIVE" 2>/dev/null || stat -c%s "$ARCHIVE" 2>/dev/null)
+ARCHIVE_SIZE_MB=$(echo "scale=2; $ARCHIVE_SIZE / 1048576" | bc)
+echo "Size: ${ARCHIVE_SIZE_MB} MB"
+echo ""
+
+# ============================================================================
+# [3/16] Check tar
+# ============================================================================
+echo -e "${YELLOW}==[3/16] Check tar ==${NC}"
+
+if ! command -v tar &>/dev/null; then
+ echo -e "${RED}ERROR: tar not found${NC}"
+ exit 1
+fi
+echo -e "${GREEN}[OK] tar found${NC}"
+echo ""
+
+# ============================================================================
+# [4/16] Extract Archive
+# ============================================================================
+echo -e "${YELLOW}==[4/16] Extract Archive ==${NC}"
+echo -e "${GRAY}[INFO] Extracting...${NC}"
+
+tar -xzf "$ARCHIVE" -C "$START_DIR"
+if [ $? -ne 0 ]; then
+ echo -e "${RED}ERROR: Extraction failed${NC}"
+ exit 1
+fi
+echo -e "${GREEN}[OK] Extracted${NC}"
+echo ""
+
+# ============================================================================
+# [5/16] Set Permissions
+# ============================================================================
+echo -e "${YELLOW}==[5/16] Set Permissions ==${NC}"
+
+chmod -R u+rw "$START_DIR" 2>/dev/null || true
+echo -e "${GREEN}[OK] Permissions set${NC}"
+echo ""
+
+# ============================================================================
+# [6/16] Find Project Root
+# ============================================================================
+echo -e "${YELLOW}==[6/16] Find Project Root ==${NC}"
+
+GRADLEW=$(find "$START_DIR" -name "gradlew" -type f 2>/dev/null | sort | head -1)
+if [ -z "$GRADLEW" ]; then
+ echo -e "${RED}ERROR: gradlew not found${NC}"
+ exit 1
+fi
+
+PROJECT_DIR=$(dirname "$GRADLEW")
+echo -e "${CYAN}Project: $PROJECT_DIR${NC}"
+cd "$PROJECT_DIR"
+echo ""
+
+# ============================================================================
+# [7/16] Fix Permissions
+# ============================================================================
+echo -e "${YELLOW}==[7/16] Fix Permissions ==${NC}"
+
+chmod +x ./gradlew
+find . -name "*.sh" -type f -exec chmod +x {} \; 2>/dev/null || true
+echo -e "${GREEN}[OK] Permissions fixed${NC}"
+echo ""
+
+# ============================================================================
+# [8/16] Verify Wrapper
+# ============================================================================
+echo -e "${YELLOW}==[8/16] Verify Wrapper ==${NC}"
+
+WRAPPER_DIR="$PROJECT_DIR/gradle/wrapper"
+WRAPPER_JAR="$WRAPPER_DIR/gradle-wrapper.jar"
+WRAPPER_PROP="$WRAPPER_DIR/gradle-wrapper.properties"
+
+if [ ! -f "$WRAPPER_PROP" ]; then
+ echo -e "${RED}ERROR: gradle-wrapper.properties missing${NC}"
+ exit 1
+fi
+
+if [ ! -f "$WRAPPER_JAR" ]; then
+ SEED_JAR="$PROJECT_DIR/$WRAPPER_SEED_PATH/gradle-wrapper.jar"
+ if [ -f "$SEED_JAR" ]; then
+ mkdir -p "$WRAPPER_DIR"
+ cp "$SEED_JAR" "$WRAPPER_JAR"
+ echo -e "${GREEN}[OK] Injected from seed${NC}"
+ else
+ echo -e "${RED}ERROR: wrapper jar missing${NC}"
+ exit 1
+ fi
+else
+ echo -e "${GREEN}[OK] Wrapper verified${NC}"
+fi
+echo ""
+
+# ============================================================================
+# [9/16] Set GRADLE_USER_HOME
+# ============================================================================
+echo -e "${YELLOW}==[9/16] Set GRADLE_USER_HOME ==${NC}"
+
+OFFLINE_HOME="$PROJECT_DIR/$OFFLINE_HOME_NAME"
+if [ ! -d "$OFFLINE_HOME" ]; then
+ echo -e "${RED}ERROR: _offline_gradle_home not found in archive${NC}"
+ exit 1
+fi
+
+export GRADLE_USER_HOME="$OFFLINE_HOME"
+echo -e "${CYAN}GRADLE_USER_HOME = $GRADLE_USER_HOME${NC}"
+
+# Check cache
+CACHES_DIR="$OFFLINE_HOME/caches"
+if [ -d "$CACHES_DIR" ]; then
+ CACHE_SIZE=$(du -sb "$CACHES_DIR" 2>/dev/null | cut -f1)
+ CACHE_SIZE_MB=$(echo "scale=2; $CACHE_SIZE / 1048576" | bc)
+ echo -e "${CYAN}[INFO] Cache size: ${CACHE_SIZE_MB} MB${NC}"
+else
+ echo -e "${YELLOW}[WARN] No cache folder found${NC}"
+fi
+echo ""
+
+# ============================================================================
+# [10/16] Verify settings.gradle
+# ============================================================================
+echo -e "${YELLOW}==[10/16] Verify settings.gradle ==${NC}"
+
+SETTINGS_FILE=""
+if [ -f "./settings.gradle" ]; then
+ SETTINGS_FILE="settings.gradle"
+elif [ -f "./settings.gradle.kts" ]; then
+ SETTINGS_FILE="settings.gradle.kts"
+fi
+
+if [ -n "$SETTINGS_FILE" ]; then
+ if grep -q "mavenLocal()" "$SETTINGS_FILE" && grep -q "pluginManagement" "$SETTINGS_FILE"; then
+ echo -e "${GREEN}[OK] settings.gradle configured for offline${NC}"
+ else
+ echo -e "${YELLOW}[WARN] settings.gradle may not be configured for offline${NC}"
+ echo -e "${GRAY}[INFO] Build may fail if plugins not cached${NC}"
+ fi
+fi
+echo ""
+
+# ============================================================================
+# [11/16] Test Gradle
+# ============================================================================
+echo -e "${YELLOW}==[11/16] Test Gradle ==${NC}"
+
+GRADLE_WORKS=false
+if ./gradlew --offline --version &>/dev/null; then
+ GRADLE_WORKS=true
+ echo -e "${GREEN}[OK] Gradle working in offline mode${NC}"
+else
+ echo -e "${YELLOW}[WARN] Gradle --version failed${NC}"
+fi
+echo ""
+
+# ============================================================================
+# [12/16] Stop Daemon
+# ============================================================================
+echo -e "${YELLOW}==[12/16] Stop Daemon ==${NC}"
+
+./gradlew --stop &>/dev/null || true
+sleep 2
+echo -e "${GREEN}[OK] Daemon stopped${NC}"
+echo ""
+
+# ============================================================================
+# [13/16] Run Offline Build
+# ============================================================================
+echo -e "${YELLOW}==[13/16] Run Offline Build ==${NC}"
+echo ""
+echo -e "${CYAN}============================================================${NC}"
+echo -e "${CYAN} Building with --offline flag${NC}"
+echo -e "${CYAN} All dependencies from local cache${NC}"
+echo -e "${CYAN}============================================================${NC}"
+echo ""
+
+BUILD_SUCCESS=false
+BUILD_TASK=""
+
+# Try bootJar
+echo -e "${GRAY}[TRY] --offline bootJar...${NC}"
+if ./gradlew --offline clean bootJar --no-daemon; then
+ BUILD_SUCCESS=true
+ BUILD_TASK="bootJar"
+fi
+
+# Try jar
+if [ "$BUILD_SUCCESS" = false ]; then
+ echo -e "${GRAY}[TRY] --offline jar...${NC}"
+ if ./gradlew --offline clean jar --no-daemon; then
+ BUILD_SUCCESS=true
+ BUILD_TASK="jar"
+ fi
+fi
+
+# Try build
+if [ "$BUILD_SUCCESS" = false ]; then
+ echo -e "${GRAY}[TRY] --offline build...${NC}"
+ if ./gradlew --offline build --no-daemon; then
+ BUILD_SUCCESS=true
+ BUILD_TASK="build"
+ fi
+fi
+
+echo ""
+if [ "$BUILD_SUCCESS" = true ]; then
+ echo -e "${GREEN}============================================================${NC}"
+ echo -e "${GREEN} BUILD SUCCESS! (task: $BUILD_TASK)${NC}"
+ echo -e "${GREEN}============================================================${NC}"
+else
+ echo -e "${RED}============================================================${NC}"
+ echo -e "${RED} BUILD FAILED!${NC}"
+ echo -e "${RED}============================================================${NC}"
+ echo ""
+ echo -e "${YELLOW}Possible causes:${NC}"
+ echo -e "${WHITE} - Dependencies not in cache${NC}"
+ echo -e "${WHITE} - Plugin resolution failed${NC}"
+ echo -e "${WHITE} - Need complete build in online env first${NC}"
+ exit 1
+fi
+echo ""
+
+# ============================================================================
+# [14/16] Show Build Output
+# ============================================================================
+echo -e "${YELLOW}==[14/16] Build Output ==${NC}"
+
+LIBS_DIR="$PROJECT_DIR/build/libs"
+if [ -d "$LIBS_DIR" ]; then
+ echo -e "${CYAN}build/libs contents:${NC}"
+ ls -lh "$LIBS_DIR"/*.jar 2>/dev/null | awk '{printf " %-40s %10s\n", $9, $5}'
+
+ MAIN_JAR=$(find "$LIBS_DIR" -name "*.jar" -type f ! -name "*-plain.jar" ! -name "*-sources.jar" ! -name "*-javadoc.jar" 2>/dev/null | head -1)
+else
+ echo -e "${YELLOW}[WARN] build/libs not found${NC}"
+fi
+echo ""
+
+# ============================================================================
+# [15/16] Run Instructions
+# ============================================================================
+echo -e "${YELLOW}==[15/16] Run Instructions ==${NC}"
+echo ""
+
+if [ -n "$MAIN_JAR" ]; then
+ echo -e "${CYAN}To run the application:${NC}"
+ echo -e "${WHITE} java -jar $(basename "$MAIN_JAR")${NC}"
+ echo ""
+fi
+
+echo -e "${CYAN}To rebuild:${NC}"
+echo -e "${WHITE} export GRADLE_USER_HOME=\"./_offline_gradle_home\"${NC}"
+echo -e "${WHITE} ./gradlew --offline bootJar --no-daemon${NC}"
+echo ""
+
+# ============================================================================
+# [16/16] Complete
+# ============================================================================
+echo -e "${GREEN}============================================================${NC}"
+echo -e "${GREEN} Offline Build Complete!${NC}"
+echo -e "${GREEN}============================================================${NC}"
+echo ""
+echo -e "${CYAN}Project: $PROJECT_DIR${NC}"
+echo ""
diff --git a/kamco-make-dataset-generation/gradle/mac/pack_offline_bundle_airgap_macos.sh b/kamco-make-dataset-generation/gradle/mac/pack_offline_bundle_airgap_macos.sh
new file mode 100755
index 0000000..1a34086
--- /dev/null
+++ b/kamco-make-dataset-generation/gradle/mac/pack_offline_bundle_airgap_macos.sh
@@ -0,0 +1,571 @@
+#!/bin/bash
+# pack_offline_bundle_airgap_macos.sh
+# ============================================================================
+# Gradle Offline Bundle Packer (macOS)
+# ============================================================================
+# Version: 4.0
+#
+# WORKFLOW:
+# 1. [ONLINE] Build project (./gradlew bootJar) - downloads all deps
+# 2. [ONLINE] Test run (./gradlew bootRun) - verify app works
+# 3. [OFFLINE TEST] Verify offline build works
+# 4. Create bundle with all cached dependencies
+#
+# REQUIREMENTS:
+# - Internet connection (for initial build)
+# - Project with gradlew
+# - macOS 10.13+ (High Sierra or later)
+# ============================================================================
+
+set -e
+
+# ============================================================================
+# Configuration
+# ============================================================================
+WRAPPER_SEED_PATH="wrapper_jar_seed"
+OFFLINE_HOME_NAME="_offline_gradle_home"
+BOOTRUN_TIMEOUT_SECONDS=60
+
+# Color codes
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+CYAN='\033[0;36m'
+GRAY='\033[0;90m'
+WHITE='\033[1;37m'
+NC='\033[0m' # No Color
+
+echo ""
+echo -e "${CYAN}============================================================${NC}"
+echo -e "${CYAN} Gradle Offline Bundle Packer v4.0 (macOS)${NC}"
+echo -e "${CYAN}============================================================${NC}"
+echo ""
+echo -e "${WHITE} This script will:${NC}"
+echo -e "${GRAY} 1. Build project with internet (download dependencies)${NC}"
+echo -e "${GRAY} 2. Test run application (verify it works)${NC}"
+echo -e "${GRAY} 3. Test offline build (verify cache is complete)${NC}"
+echo -e "${GRAY} 4. Create offline bundle for air-gapped environment${NC}"
+echo ""
+echo -e "${CYAN}============================================================${NC}"
+echo ""
+
+# ============================================================================
+# [1/20] Check Current Directory
+# ============================================================================
+echo -e "${YELLOW}==[1/20] Check Current Directory ==${NC}"
+ROOT="$(pwd)"
+echo "ROOT_DIR: $ROOT"
+echo ""
+
+# ============================================================================
+# [2/20] Check Required Files
+# ============================================================================
+echo -e "${YELLOW}==[2/20] Check Required Files ==${NC}"
+
+if [ ! -f "./gradlew" ]; then
+ echo -e "${RED}ERROR: gradlew not found. Run from project root.${NC}"
+ exit 1
+fi
+chmod +x ./gradlew
+echo -e "${GREEN}[OK] gradlew${NC}"
+
+BUILD_FILE=""
+if [ -f "./build.gradle" ]; then
+ BUILD_FILE="build.gradle"
+elif [ -f "./build.gradle.kts" ]; then
+ BUILD_FILE="build.gradle.kts"
+else
+ echo -e "${RED}ERROR: build.gradle(.kts) not found.${NC}"
+ exit 1
+fi
+echo -e "${GREEN}[OK] $BUILD_FILE${NC}"
+
+SETTINGS_FILE=""
+if [ -f "./settings.gradle" ]; then
+ SETTINGS_FILE="settings.gradle"
+ echo -e "${GREEN}[OK] $SETTINGS_FILE${NC}"
+elif [ -f "./settings.gradle.kts" ]; then
+ SETTINGS_FILE="settings.gradle.kts"
+ echo -e "${GREEN}[OK] $SETTINGS_FILE${NC}"
+fi
+echo ""
+
+# ============================================================================
+# [3/20] Check Gradle Wrapper
+# ============================================================================
+echo -e "${YELLOW}==[3/20] Check Gradle Wrapper ==${NC}"
+
+WRAPPER_DIR="$ROOT/gradle/wrapper"
+WRAPPER_JAR="$WRAPPER_DIR/gradle-wrapper.jar"
+WRAPPER_PROP="$WRAPPER_DIR/gradle-wrapper.properties"
+
+mkdir -p "$WRAPPER_DIR"
+
+if [ ! -f "$WRAPPER_PROP" ]; then
+ echo -e "${RED}ERROR: gradle-wrapper.properties not found.${NC}"
+ exit 1
+fi
+
+if [ ! -f "$WRAPPER_JAR" ]; then
+ SEED_JAR="$ROOT/$WRAPPER_SEED_PATH/gradle-wrapper.jar"
+ if [ -f "$SEED_JAR" ]; then
+ cp "$SEED_JAR" "$WRAPPER_JAR"
+ echo -e "${GREEN}[OK] Wrapper jar injected from seed${NC}"
+ else
+ echo -e "${RED}ERROR: gradle-wrapper.jar missing${NC}"
+ exit 1
+ fi
+else
+ echo -e "${GREEN}[OK] gradle-wrapper.jar exists${NC}"
+fi
+
+# Create seed backup
+SEED_DIR="$ROOT/$WRAPPER_SEED_PATH"
+if [ ! -d "$SEED_DIR" ]; then
+ mkdir -p "$SEED_DIR"
+ cp "$WRAPPER_JAR" "$SEED_DIR/gradle-wrapper.jar"
+fi
+echo ""
+
+# ============================================================================
+# [4/20] Set GRADLE_USER_HOME (Project Local)
+# ============================================================================
+echo -e "${YELLOW}==[4/20] Set GRADLE_USER_HOME ==${NC}"
+
+OFFLINE_HOME="$ROOT/$OFFLINE_HOME_NAME"
+mkdir -p "$OFFLINE_HOME"
+export GRADLE_USER_HOME="$OFFLINE_HOME"
+
+echo -e "${CYAN}GRADLE_USER_HOME = $GRADLE_USER_HOME${NC}"
+echo -e "${GRAY}[INFO] All dependencies will be cached in project folder${NC}"
+echo ""
+
+# ============================================================================
+# [5/20] Check Internet Connection
+# ============================================================================
+echo -e "${YELLOW}==[5/20] Check Internet Connection ==${NC}"
+
+HAS_INTERNET=false
+TEST_HOSTS=("plugins.gradle.org" "repo.maven.apache.org" "repo1.maven.org")
+
+for TEST_HOST in "${TEST_HOSTS[@]}"; do
+ # macOS ping doesn't have -W, use -t instead
+ if ping -c 1 -t 3 "$TEST_HOST" &>/dev/null; then
+ HAS_INTERNET=true
+ echo -e "${GREEN}[OK] Connected to $TEST_HOST${NC}"
+ break
+ fi
+done
+
+if [ "$HAS_INTERNET" = false ]; then
+ # Try DNS resolution as fallback
+ if nslookup google.com &>/dev/null || host google.com &>/dev/null; then
+ HAS_INTERNET=true
+ echo -e "${GREEN}[OK] Internet available (DNS)${NC}"
+ fi
+fi
+
+if [ "$HAS_INTERNET" = false ]; then
+ echo ""
+ echo -e "${RED}============================================================${NC}"
+ echo -e "${RED} ERROR: No Internet Connection!${NC}"
+ echo -e "${RED}============================================================${NC}"
+ echo ""
+ echo -e "${YELLOW}This script requires internet for initial build.${NC}"
+ echo -e "${YELLOW}Please connect to internet and run again.${NC}"
+ echo ""
+ exit 1
+fi
+echo ""
+
+# ============================================================================
+# [6/20] Initial Gradle Setup
+# ============================================================================
+echo -e "${YELLOW}==[6/20] Initial Gradle Setup ==${NC}"
+echo -e "${GRAY}[INFO] Downloading Gradle distribution...${NC}"
+
+if ./gradlew --version &>/dev/null; then
+ GRADLE_VERSION=$(./gradlew --version 2>&1 | grep "^Gradle" | awk '{print $2}')
+ echo -e "${GREEN}[OK] Gradle $GRADLE_VERSION${NC}"
+else
+ echo -e "${RED}[ERROR] Gradle setup failed${NC}"
+ exit 1
+fi
+echo ""
+
+# ============================================================================
+# [7/20] ONLINE BUILD - bootJar (Download All Dependencies)
+# ============================================================================
+echo -e "${YELLOW}==[7/20] ONLINE BUILD - bootJar ==${NC}"
+echo ""
+echo -e "${CYAN}============================================================${NC}"
+echo -e "${CYAN} ONLINE BUILD (with Internet)${NC}"
+echo -e "${CYAN} Downloading all dependencies to local cache${NC}"
+echo -e "${CYAN}============================================================${NC}"
+echo ""
+
+BUILD_SUCCESS=false
+
+./gradlew clean bootJar --no-daemon
+if [ $? -eq 0 ]; then
+ BUILD_SUCCESS=true
+ echo ""
+ echo -e "${GREEN}============================================================${NC}"
+ echo -e "${GREEN} ONLINE BUILD SUCCESS!${NC}"
+ echo -e "${GREEN}============================================================${NC}"
+ echo ""
+
+ if [ -d "./build/libs" ]; then
+ echo -e "${CYAN}JAR files:${NC}"
+ ls -lh ./build/libs/*.jar 2>/dev/null | awk '{print " " $9 " (" $5 ")"}'
+ fi
+else
+ echo ""
+ echo -e "${RED}============================================================${NC}"
+ echo -e "${RED} BUILD FAILED!${NC}"
+ echo -e "${RED}============================================================${NC}"
+ echo ""
+ echo -e "${YELLOW}Build failed. Cannot continue.${NC}"
+ exit 1
+fi
+echo ""
+
+# ============================================================================
+# [8/20] Stop Daemons
+# ============================================================================
+echo -e "${YELLOW}==[8/20] Stop Daemons ==${NC}"
+
+./gradlew --stop &>/dev/null || true
+sleep 2
+echo -e "${GREEN}[OK] Daemons stopped${NC}"
+echo ""
+
+# ============================================================================
+# [9/20] ONLINE TEST - bootRun (Verify Application Works)
+# ============================================================================
+echo -e "${YELLOW}==[9/20] ONLINE TEST - bootRun ==${NC}"
+echo ""
+echo -e "${CYAN}============================================================${NC}"
+echo -e "${CYAN} Testing application startup (timeout: ${BOOTRUN_TIMEOUT_SECONDS}s)${NC}"
+echo -e "${CYAN} Will automatically stop after successful startup${NC}"
+echo -e "${CYAN}============================================================${NC}"
+echo ""
+
+BOOTRUN_SUCCESS=false
+
+# macOS uses gtimeout if available, otherwise perl-based timeout
+if command -v gtimeout &>/dev/null; then
+ gtimeout ${BOOTRUN_TIMEOUT_SECONDS}s ./gradlew bootRun --no-daemon &
+else
+ # Fallback: start in background and kill after timeout
+ ./gradlew bootRun --no-daemon &
+fi
+BOOTRUN_PID=$!
+
+sleep 10
+
+if ps -p $BOOTRUN_PID &>/dev/null; then
+ BOOTRUN_SUCCESS=true
+ echo ""
+ echo -e "${GREEN}[OK] Application started successfully${NC}"
+ kill $BOOTRUN_PID &>/dev/null || true
+ sleep 2
+else
+ echo ""
+ echo -e "${YELLOW}[WARN] Application may not have started properly${NC}"
+fi
+
+# Cleanup - macOS process cleanup
+pkill -f "gradle.*bootRun" &>/dev/null || true
+sleep 2
+echo ""
+
+# ============================================================================
+# [10/20] Stop Daemons Again
+# ============================================================================
+echo -e "${YELLOW}==[10/20] Stop Daemons Again ==${NC}"
+
+./gradlew --stop &>/dev/null || true
+sleep 2
+echo -e "${GREEN}[OK] Daemons stopped${NC}"
+echo ""
+
+# ============================================================================
+# [11/20] OFFLINE BUILD TEST (Verify Cache Completeness)
+# ============================================================================
+echo -e "${YELLOW}==[11/20] OFFLINE BUILD TEST ==${NC}"
+echo ""
+echo -e "${CYAN}============================================================${NC}"
+echo -e "${CYAN} OFFLINE BUILD TEST (--offline flag)${NC}"
+echo -e "${CYAN} Verifying all dependencies are cached${NC}"
+echo -e "${CYAN}============================================================${NC}"
+echo ""
+
+OFFLINE_SUCCESS=false
+
+./gradlew clean bootJar --offline --no-daemon
+if [ $? -eq 0 ]; then
+ OFFLINE_SUCCESS=true
+ echo ""
+ echo -e "${GREEN}============================================================${NC}"
+ echo -e "${GREEN} OFFLINE BUILD TEST PASSED!${NC}"
+ echo -e "${GREEN}============================================================${NC}"
+ echo ""
+ echo -e "${GREEN}[OK] All dependencies are cached${NC}"
+else
+ echo ""
+ echo -e "${RED}============================================================${NC}"
+ echo -e "${RED} OFFLINE BUILD TEST FAILED!${NC}"
+ echo -e "${RED}============================================================${NC}"
+ echo ""
+ echo -e "${YELLOW}Some dependencies may be missing from cache.${NC}"
+ echo -e "${YELLOW}The bundle may not work in air-gapped environment.${NC}"
+ echo ""
+
+ read -p "Continue anyway? (y/N): " -n 1 -r
+ echo
+ if [[ ! $REPLY =~ ^[Yy]$ ]]; then
+ exit 1
+ fi
+fi
+echo ""
+
+# ============================================================================
+# [12/20] Stop Daemons Before Archive
+# ============================================================================
+echo -e "${YELLOW}==[12/20] Stop Daemons Before Archive ==${NC}"
+
+./gradlew --stop &>/dev/null || true
+sleep 2
+echo -e "${GREEN}[OK] Daemons stopped${NC}"
+echo ""
+
+# ============================================================================
+# [13/20] Verify settings.gradle for Offline
+# ============================================================================
+echo -e "${YELLOW}==[13/20] Verify settings.gradle ==${NC}"
+
+if [ -n "$SETTINGS_FILE" ]; then
+ if grep -q "mavenLocal()" "$SETTINGS_FILE" && grep -q "pluginManagement" "$SETTINGS_FILE"; then
+ echo -e "${GREEN}[OK] settings.gradle configured for offline${NC}"
+ else
+ echo -e "${YELLOW}[WARN] settings.gradle may need offline configuration${NC}"
+ echo -e "${GRAY}[INFO] Consider adding mavenLocal() to pluginManagement and repositories${NC}"
+ fi
+else
+ echo -e "${GRAY}[INFO] No settings.gradle found${NC}"
+fi
+echo ""
+
+# ============================================================================
+# [14/20] Create Helper Scripts
+# ============================================================================
+echo -e "${YELLOW}==[14/20] Create Helper Scripts ==${NC}"
+
+# run_offline_build.sh
+cat > "$ROOT/run_offline_build.sh" << 'EOF'
+#!/bin/bash
+# run_offline_build.sh - Build JAR offline
+export GRADLE_USER_HOME="$(pwd)/_offline_gradle_home"
+echo "GRADLE_USER_HOME = $GRADLE_USER_HOME"
+echo ""
+./gradlew --offline bootJar --no-daemon
+if [ $? -eq 0 ]; then
+ echo ""
+ echo "BUILD SUCCESS!"
+ echo ""
+ echo "JAR files:"
+ ls -lh ./build/libs/*.jar 2>/dev/null | awk '{print " " $9}'
+else
+ echo "BUILD FAILED"
+fi
+EOF
+chmod +x "$ROOT/run_offline_build.sh"
+echo -e "${GREEN}[OK] run_offline_build.sh${NC}"
+
+# run_offline_bootrun.sh
+cat > "$ROOT/run_offline_bootrun.sh" << 'EOF'
+#!/bin/bash
+# run_offline_bootrun.sh - Run application offline
+export GRADLE_USER_HOME="$(pwd)/_offline_gradle_home"
+echo "GRADLE_USER_HOME = $GRADLE_USER_HOME"
+echo ""
+echo "Starting application (Ctrl+C to stop)..."
+echo ""
+./gradlew --offline bootRun --no-daemon
+EOF
+chmod +x "$ROOT/run_offline_bootrun.sh"
+echo -e "${GREEN}[OK] run_offline_bootrun.sh${NC}"
+echo ""
+
+# ============================================================================
+# [15/20] Final Daemon Cleanup
+# ============================================================================
+echo -e "${YELLOW}==[15/20] Final Daemon Cleanup ==${NC}"
+
+./gradlew --stop &>/dev/null || true
+sleep 2
+echo -e "${GREEN}[OK] Daemons stopped${NC}"
+echo ""
+
+# ============================================================================
+# [16/20] Clean Lock Files
+# ============================================================================
+echo -e "${YELLOW}==[16/20] Clean Lock Files ==${NC}"
+
+DAEMON_DIR="$OFFLINE_HOME/daemon"
+if [ -d "$DAEMON_DIR" ]; then
+ rm -rf "$DAEMON_DIR" 2>/dev/null || true
+fi
+
+find "$OFFLINE_HOME" -type f \( -name "*.lock" -o -name "*.log" -o -name "*.tmp" \) -delete 2>/dev/null || true
+
+echo -e "${GREEN}[OK] Lock files cleaned${NC}"
+echo ""
+
+# ============================================================================
+# [17/20] Calculate Cache Size
+# ============================================================================
+echo -e "${YELLOW}==[17/20] Cache Summary ==${NC}"
+
+CACHES_DIR="$OFFLINE_HOME/caches"
+WRAPPER_DISTS="$OFFLINE_HOME/wrapper/dists"
+
+TOTAL_SIZE=0
+
+if [ -d "$CACHES_DIR" ]; then
+ # macOS uses different options for du
+ if du -k "$CACHES_DIR" &>/dev/null; then
+ SIZE=$(du -sk "$CACHES_DIR" 2>/dev/null | cut -f1)
+ SIZE=$((SIZE * 1024)) # Convert to bytes
+ else
+ SIZE=0
+ fi
+ TOTAL_SIZE=$((TOTAL_SIZE + SIZE))
+ SIZE_MB=$(awk "BEGIN {printf \"%.2f\", $SIZE / 1048576}")
+ echo -e "${CYAN}[INFO] Dependencies: ${SIZE_MB} MB${NC}"
+fi
+
+if [ -d "$WRAPPER_DISTS" ]; then
+ if du -k "$WRAPPER_DISTS" &>/dev/null; then
+ SIZE=$(du -sk "$WRAPPER_DISTS" 2>/dev/null | cut -f1)
+ SIZE=$((SIZE * 1024))
+ else
+ SIZE=0
+ fi
+ TOTAL_SIZE=$((TOTAL_SIZE + SIZE))
+ SIZE_MB=$(awk "BEGIN {printf \"%.2f\", $SIZE / 1048576}")
+ echo -e "${CYAN}[INFO] Gradle dist: ${SIZE_MB} MB${NC}"
+fi
+
+TOTAL_MB=$(awk "BEGIN {printf \"%.2f\", $TOTAL_SIZE / 1048576}")
+echo -e "${CYAN}[INFO] Total cache: ${TOTAL_MB} MB${NC}"
+echo ""
+
+# ============================================================================
+# [18/20] Create Archive
+# ============================================================================
+echo -e "${YELLOW}==[18/20] Create Archive ==${NC}"
+
+BASE_NAME=$(basename "$ROOT")
+TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
+PARENT=$(dirname "$ROOT")
+ARCHIVE_PATH="${PARENT}/${BASE_NAME}_offline_bundle_${TIMESTAMP}.tar.gz"
+
+echo "Archive: $ARCHIVE_PATH"
+echo -e "${GRAY}[INFO] Creating archive (this may take several minutes)...${NC}"
+
+# macOS tar with BSD options
+tar -czf "$ARCHIVE_PATH" \
+ --exclude=".git" \
+ --exclude=".idea" \
+ --exclude=".DS_Store" \
+ --exclude="*.log" \
+ --exclude="*.lock" \
+ --exclude="_offline_gradle_home/daemon" \
+ --exclude="_offline_gradle_home/native" \
+ --exclude="_offline_gradle_home/jdks" \
+ --exclude="build" \
+ --exclude="out" \
+ --exclude=".gradle" \
+ -C "$ROOT" .
+
+if [ $? -ne 0 ]; then
+ echo -e "${RED}ERROR: tar failed${NC}"
+ exit 1
+fi
+
+# macOS stat command
+ARCHIVE_SIZE=$(stat -f%z "$ARCHIVE_PATH" 2>/dev/null)
+ARCHIVE_SIZE_MB=$(awk "BEGIN {printf \"%.2f\", $ARCHIVE_SIZE / 1048576}")
+echo -e "${GREEN}[OK] Archive created: ${ARCHIVE_SIZE_MB} MB${NC}"
+echo ""
+
+# ============================================================================
+# [19/20] Verify Archive
+# ============================================================================
+echo -e "${YELLOW}==[19/20] Verify Archive ==${NC}"
+
+CHECKS=(
+ "gradle/wrapper/gradle-wrapper.jar"
+ "gradlew"
+ "_offline_gradle_home/caches"
+ "run_offline_build.sh"
+)
+
+for CHECK in "${CHECKS[@]}"; do
+ if tar -tzf "$ARCHIVE_PATH" | grep -q "$CHECK"; then
+ echo -e " ${GREEN}[OK] $CHECK${NC}"
+ else
+ echo -e " ${YELLOW}[WARN] $CHECK${NC}"
+ fi
+done
+echo ""
+
+# ============================================================================
+# [20/20] Complete
+# ============================================================================
+echo -e "${GREEN}============================================================${NC}"
+echo -e "${GREEN} BUNDLE CREATION COMPLETE!${NC}"
+echo -e "${GREEN}============================================================${NC}"
+echo ""
+echo -e "${CYAN}Archive: $ARCHIVE_PATH${NC}"
+echo -e "${CYAN}Size: ${ARCHIVE_SIZE_MB} MB${NC}"
+echo ""
+
+echo -e "${CYAN}============================================================${NC}"
+echo -e "${CYAN} Test Results${NC}"
+echo -e "${CYAN}============================================================${NC}"
+if [ "$BUILD_SUCCESS" = true ]; then
+ echo -e " Online build (bootJar): ${GREEN}PASSED${NC}"
+else
+ echo -e " Online build (bootJar): ${RED}FAILED${NC}"
+fi
+if [ "$BOOTRUN_SUCCESS" = true ]; then
+ echo -e " Online test (bootRun): ${GREEN}PASSED${NC}"
+else
+ echo -e " Online test (bootRun): ${YELLOW}SKIPPED${NC}"
+fi
+if [ "$OFFLINE_SUCCESS" = true ]; then
+ echo -e " Offline build test: ${GREEN}PASSED${NC}"
+else
+ echo -e " Offline build test: ${RED}FAILED${NC}"
+fi
+echo ""
+
+echo -e "${YELLOW}============================================================${NC}"
+echo -e "${YELLOW} Usage in Air-gapped Environment${NC}"
+echo -e "${YELLOW}============================================================${NC}"
+echo ""
+echo -e "${WHITE}Option 1: Use unpack script${NC}"
+echo -e "${GRAY} ./unpack_and_offline_build_airgap.sh${NC}"
+echo ""
+echo -e "${WHITE}Option 2: Manual extraction${NC}"
+echo -e "${GRAY} tar -xzf .tar.gz${NC}"
+echo -e "${GRAY} cd ${NC}"
+echo -e "${GRAY} ./run_offline_build.sh${NC}"
+echo ""
+echo -e "${WHITE}Option 3: Direct commands${NC}"
+echo -e "${GRAY} export GRADLE_USER_HOME=\"./_offline_gradle_home\"${NC}"
+echo -e "${GRAY} ./gradlew --offline bootJar --no-daemon${NC}"
+echo ""
diff --git a/kamco-make-dataset-generation/gradle/mac/unpack_and_offline_build_airgap_macos.sh b/kamco-make-dataset-generation/gradle/mac/unpack_and_offline_build_airgap_macos.sh
new file mode 100755
index 0000000..4ab128e
--- /dev/null
+++ b/kamco-make-dataset-generation/gradle/mac/unpack_and_offline_build_airgap_macos.sh
@@ -0,0 +1,359 @@
+#!/bin/bash
+# unpack_and_offline_build_airgap_macos.sh
+# ============================================================================
+# Execution Environment: OFFLINE (Air-gapped, No Internet)
+# Purpose: Extract bundle and run offline build
+# ============================================================================
+# macOS Bash Script
+# Version: 3.1
+#
+# IMPORTANT: This script automatically:
+# 1. Extracts the archive
+# 2. Sets GRADLE_USER_HOME to project local cache
+# 3. Configures settings.gradle for offline resolution
+# 4. Runs build with --offline flag
+# ============================================================================
+
+set -e
+
+# ============================================================================
+# Configuration
+# ============================================================================
+WRAPPER_SEED_PATH="wrapper_jar_seed"
+OFFLINE_HOME_NAME="_offline_gradle_home"
+
+# Color codes
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+CYAN='\033[0;36m'
+GRAY='\033[0;90m'
+WHITE='\033[1;37m'
+NC='\033[0m' # No Color
+
+echo ""
+echo -e "${CYAN}============================================================${NC}"
+echo -e "${CYAN} Gradle Offline Build Runner (macOS)${NC}"
+echo -e "${CYAN} Environment: AIR-GAPPED (No Internet)${NC}"
+echo -e "${CYAN} Mode: Fully Offline (--offline enforced)${NC}"
+echo -e "${CYAN}============================================================${NC}"
+echo ""
+
+# ============================================================================
+# [1/16] Check Current Directory
+# ============================================================================
+echo -e "${YELLOW}==[1/16] Check Current Directory ==${NC}"
+START_DIR="$(pwd)"
+echo "PWD: $START_DIR"
+echo ""
+
+# ============================================================================
+# [2/16] Select Archive
+# ============================================================================
+echo -e "${YELLOW}==[2/16] Select Archive ==${NC}"
+
+ARCHIVE=""
+if [ $# -ge 1 ]; then
+ ARCHIVE="$1"
+fi
+
+if [ -z "$ARCHIVE" ]; then
+ # Auto-detect most recent .tar.gz file (macOS compatible)
+ ARCHIVE=$(find "$START_DIR" -maxdepth 1 -type f \( -name "*.tar.gz" -o -name "*.tgz" \) -exec stat -f "%m %N" {} \; 2>/dev/null | sort -rn | head -1 | cut -d' ' -f2-)
+
+ if [ -z "$ARCHIVE" ]; then
+ echo -e "${RED}[ERROR] No archive found${NC}"
+ ls -lh "$START_DIR"
+ exit 1
+ fi
+
+ echo -e "${CYAN}[AUTO] $(basename "$ARCHIVE")${NC}"
+else
+ if [ ! -f "$ARCHIVE" ]; then
+ ARCHIVE="$START_DIR/$ARCHIVE"
+ fi
+ echo -e "${CYAN}[USER] $(basename "$ARCHIVE")${NC}"
+fi
+
+if [ ! -f "$ARCHIVE" ]; then
+ echo -e "${RED}ERROR: Archive not found: $ARCHIVE${NC}"
+ exit 1
+fi
+
+# macOS stat command
+ARCHIVE_SIZE=$(stat -f%z "$ARCHIVE" 2>/dev/null)
+ARCHIVE_SIZE_MB=$(awk "BEGIN {printf \"%.2f\", $ARCHIVE_SIZE / 1048576}")
+echo "Size: ${ARCHIVE_SIZE_MB} MB"
+echo ""
+
+# ============================================================================
+# [3/16] Check tar
+# ============================================================================
+echo -e "${YELLOW}==[3/16] Check tar ==${NC}"
+
+if ! command -v tar &>/dev/null; then
+ echo -e "${RED}ERROR: tar not found${NC}"
+ exit 1
+fi
+echo -e "${GREEN}[OK] tar found${NC}"
+echo ""
+
+# ============================================================================
+# [4/16] Extract Archive
+# ============================================================================
+echo -e "${YELLOW}==[4/16] Extract Archive ==${NC}"
+echo -e "${GRAY}[INFO] Extracting...${NC}"
+
+tar -xzf "$ARCHIVE" -C "$START_DIR"
+if [ $? -ne 0 ]; then
+ echo -e "${RED}ERROR: Extraction failed${NC}"
+ exit 1
+fi
+echo -e "${GREEN}[OK] Extracted${NC}"
+echo ""
+
+# ============================================================================
+# [5/16] Set Permissions
+# ============================================================================
+echo -e "${YELLOW}==[5/16] Set Permissions ==${NC}"
+
+chmod -R u+rw "$START_DIR" 2>/dev/null || true
+# Remove extended attributes that macOS may add
+xattr -cr "$START_DIR" 2>/dev/null || true
+echo -e "${GREEN}[OK] Permissions set${NC}"
+echo ""
+
+# ============================================================================
+# [6/16] Find Project Root
+# ============================================================================
+echo -e "${YELLOW}==[6/16] Find Project Root ==${NC}"
+
+GRADLEW=$(find "$START_DIR" -name "gradlew" -type f 2>/dev/null | sort | head -1)
+if [ -z "$GRADLEW" ]; then
+ echo -e "${RED}ERROR: gradlew not found${NC}"
+ exit 1
+fi
+
+PROJECT_DIR=$(dirname "$GRADLEW")
+echo -e "${CYAN}Project: $PROJECT_DIR${NC}"
+cd "$PROJECT_DIR"
+echo ""
+
+# ============================================================================
+# [7/16] Fix Permissions
+# ============================================================================
+echo -e "${YELLOW}==[7/16] Fix Permissions ==${NC}"
+
+chmod +x ./gradlew
+find . -name "*.sh" -type f -exec chmod +x {} \; 2>/dev/null || true
+# Remove quarantine attributes that macOS adds to downloaded files
+xattr -d com.apple.quarantine ./gradlew 2>/dev/null || true
+find . -name "*.jar" -exec xattr -d com.apple.quarantine {} \; 2>/dev/null || true
+echo -e "${GREEN}[OK] Permissions fixed${NC}"
+echo ""
+
+# ============================================================================
+# [8/16] Verify Wrapper
+# ============================================================================
+echo -e "${YELLOW}==[8/16] Verify Wrapper ==${NC}"
+
+WRAPPER_DIR="$PROJECT_DIR/gradle/wrapper"
+WRAPPER_JAR="$WRAPPER_DIR/gradle-wrapper.jar"
+WRAPPER_PROP="$WRAPPER_DIR/gradle-wrapper.properties"
+
+if [ ! -f "$WRAPPER_PROP" ]; then
+ echo -e "${RED}ERROR: gradle-wrapper.properties missing${NC}"
+ exit 1
+fi
+
+if [ ! -f "$WRAPPER_JAR" ]; then
+ SEED_JAR="$PROJECT_DIR/$WRAPPER_SEED_PATH/gradle-wrapper.jar"
+ if [ -f "$SEED_JAR" ]; then
+ mkdir -p "$WRAPPER_DIR"
+ cp "$SEED_JAR" "$WRAPPER_JAR"
+ echo -e "${GREEN}[OK] Injected from seed${NC}"
+ else
+ echo -e "${RED}ERROR: wrapper jar missing${NC}"
+ exit 1
+ fi
+else
+ echo -e "${GREEN}[OK] Wrapper verified${NC}"
+fi
+echo ""
+
+# ============================================================================
+# [9/16] Set GRADLE_USER_HOME
+# ============================================================================
+echo -e "${YELLOW}==[9/16] Set GRADLE_USER_HOME ==${NC}"
+
+OFFLINE_HOME="$PROJECT_DIR/$OFFLINE_HOME_NAME"
+if [ ! -d "$OFFLINE_HOME" ]; then
+ echo -e "${RED}ERROR: _offline_gradle_home not found in archive${NC}"
+ exit 1
+fi
+
+export GRADLE_USER_HOME="$OFFLINE_HOME"
+echo -e "${CYAN}GRADLE_USER_HOME = $GRADLE_USER_HOME${NC}"
+
+# Check cache
+CACHES_DIR="$OFFLINE_HOME/caches"
+if [ -d "$CACHES_DIR" ]; then
+ # macOS du command
+ if du -k "$CACHES_DIR" &>/dev/null; then
+ CACHE_SIZE=$(du -sk "$CACHES_DIR" 2>/dev/null | cut -f1)
+ CACHE_SIZE=$((CACHE_SIZE * 1024))
+ else
+ CACHE_SIZE=0
+ fi
+ CACHE_SIZE_MB=$(awk "BEGIN {printf \"%.2f\", $CACHE_SIZE / 1048576}")
+ echo -e "${CYAN}[INFO] Cache size: ${CACHE_SIZE_MB} MB${NC}"
+else
+ echo -e "${YELLOW}[WARN] No cache folder found${NC}"
+fi
+echo ""
+
+# ============================================================================
+# [10/16] Verify settings.gradle
+# ============================================================================
+echo -e "${YELLOW}==[10/16] Verify settings.gradle ==${NC}"
+
+SETTINGS_FILE=""
+if [ -f "./settings.gradle" ]; then
+ SETTINGS_FILE="settings.gradle"
+elif [ -f "./settings.gradle.kts" ]; then
+ SETTINGS_FILE="settings.gradle.kts"
+fi
+
+if [ -n "$SETTINGS_FILE" ]; then
+ if grep -q "mavenLocal()" "$SETTINGS_FILE" && grep -q "pluginManagement" "$SETTINGS_FILE"; then
+ echo -e "${GREEN}[OK] settings.gradle configured for offline${NC}"
+ else
+ echo -e "${YELLOW}[WARN] settings.gradle may not be configured for offline${NC}"
+ echo -e "${GRAY}[INFO] Build may fail if plugins not cached${NC}"
+ fi
+fi
+echo ""
+
+# ============================================================================
+# [11/16] Test Gradle
+# ============================================================================
+echo -e "${YELLOW}==[11/16] Test Gradle ==${NC}"
+
+GRADLE_WORKS=false
+if ./gradlew --offline --version &>/dev/null; then
+ GRADLE_WORKS=true
+ echo -e "${GREEN}[OK] Gradle working in offline mode${NC}"
+else
+ echo -e "${YELLOW}[WARN] Gradle --version failed${NC}"
+fi
+echo ""
+
+# ============================================================================
+# [12/16] Stop Daemon
+# ============================================================================
+echo -e "${YELLOW}==[12/16] Stop Daemon ==${NC}"
+
+./gradlew --stop &>/dev/null || true
+sleep 2
+echo -e "${GREEN}[OK] Daemon stopped${NC}"
+echo ""
+
+# ============================================================================
+# [13/16] Run Offline Build
+# ============================================================================
+echo -e "${YELLOW}==[13/16] Run Offline Build ==${NC}"
+echo ""
+echo -e "${CYAN}============================================================${NC}"
+echo -e "${CYAN} Building with --offline flag${NC}"
+echo -e "${CYAN} All dependencies from local cache${NC}"
+echo -e "${CYAN}============================================================${NC}"
+echo ""
+
+BUILD_SUCCESS=false
+BUILD_TASK=""
+
+# Try bootJar
+echo -e "${GRAY}[TRY] --offline bootJar...${NC}"
+if ./gradlew --offline clean bootJar --no-daemon; then
+ BUILD_SUCCESS=true
+ BUILD_TASK="bootJar"
+fi
+
+# Try jar
+if [ "$BUILD_SUCCESS" = false ]; then
+ echo -e "${GRAY}[TRY] --offline jar...${NC}"
+ if ./gradlew --offline clean jar --no-daemon; then
+ BUILD_SUCCESS=true
+ BUILD_TASK="jar"
+ fi
+fi
+
+# Try build
+if [ "$BUILD_SUCCESS" = false ]; then
+ echo -e "${GRAY}[TRY] --offline build...${NC}"
+ if ./gradlew --offline build --no-daemon; then
+ BUILD_SUCCESS=true
+ BUILD_TASK="build"
+ fi
+fi
+
+echo ""
+if [ "$BUILD_SUCCESS" = true ]; then
+ echo -e "${GREEN}============================================================${NC}"
+ echo -e "${GREEN} BUILD SUCCESS! (task: $BUILD_TASK)${NC}"
+ echo -e "${GREEN}============================================================${NC}"
+else
+ echo -e "${RED}============================================================${NC}"
+ echo -e "${RED} BUILD FAILED!${NC}"
+ echo -e "${RED}============================================================${NC}"
+ echo ""
+ echo -e "${YELLOW}Possible causes:${NC}"
+ echo -e "${WHITE} - Dependencies not in cache${NC}"
+ echo -e "${WHITE} - Plugin resolution failed${NC}"
+ echo -e "${WHITE} - Need complete build in online env first${NC}"
+ exit 1
+fi
+echo ""
+
+# ============================================================================
+# [14/16] Show Build Output
+# ============================================================================
+echo -e "${YELLOW}==[14/16] Build Output ==${NC}"
+
+LIBS_DIR="$PROJECT_DIR/build/libs"
+if [ -d "$LIBS_DIR" ]; then
+ echo -e "${CYAN}build/libs contents:${NC}"
+ ls -lh "$LIBS_DIR"/*.jar 2>/dev/null | awk '{printf " %-40s %10s\n", $9, $5}'
+
+ MAIN_JAR=$(find "$LIBS_DIR" -name "*.jar" -type f ! -name "*-plain.jar" ! -name "*-sources.jar" ! -name "*-javadoc.jar" 2>/dev/null | head -1)
+else
+ echo -e "${YELLOW}[WARN] build/libs not found${NC}"
+fi
+echo ""
+
+# ============================================================================
+# [15/16] Run Instructions
+# ============================================================================
+echo -e "${YELLOW}==[15/16] Run Instructions ==${NC}"
+echo ""
+
+if [ -n "$MAIN_JAR" ]; then
+ echo -e "${CYAN}To run the application:${NC}"
+ echo -e "${WHITE} java -jar $(basename "$MAIN_JAR")${NC}"
+ echo ""
+fi
+
+echo -e "${CYAN}To rebuild:${NC}"
+echo -e "${WHITE} export GRADLE_USER_HOME=\"./_offline_gradle_home\"${NC}"
+echo -e "${WHITE} ./gradlew --offline bootJar --no-daemon${NC}"
+echo ""
+
+# ============================================================================
+# [16/16] Complete
+# ============================================================================
+echo -e "${GREEN}============================================================${NC}"
+echo -e "${GREEN} Offline Build Complete!${NC}"
+echo -e "${GREEN}============================================================${NC}"
+echo ""
+echo -e "${CYAN}Project: $PROJECT_DIR${NC}"
+echo ""
diff --git a/kamco-make-dataset-generation/gradle/win/kamco-dabeeo-backoffice_gradle.tar.gz b/kamco-make-dataset-generation/gradle/win/kamco-dabeeo-backoffice_gradle.tar.gz
new file mode 100755
index 0000000..bcc4932
Binary files /dev/null and b/kamco-make-dataset-generation/gradle/win/kamco-dabeeo-backoffice_gradle.tar.gz differ
diff --git a/kamco-make-dataset-generation/gradle/win/scripts/Readme.txt b/kamco-make-dataset-generation/gradle/win/scripts/Readme.txt
new file mode 100755
index 0000000..03c24ff
--- /dev/null
+++ b/kamco-make-dataset-generation/gradle/win/scripts/Readme.txt
@@ -0,0 +1,14 @@
+How to Use
+
+[1] Move The Two scripts to a Last location
+1. pack_offline_bundle_airgap.ps1
+2. unpack_and_offline_build_airgap.ps1
+
+[2] Packing Scripts Start --Options: Internet connect Require when you packing, after then you will get all gradle File
+command on powershell: powershell -ExecutionPolicy Bypass -File .\pack_offline_bundle_airgap.ps1
+
+[3] UnPacking Scripts Start --Options: The JPA Spring boot Project All gradle, gradle cache File, Build File etc (Check using .\gradlew.bat bootRun --offline)
+command on powershell: powershell -ExecutionPolicy Bypass -File .\unpack_and_offline_build_airgap.ps1 .\kamco-dabeeo-backoffice_offline_bundle_20260121_145830.tar.gz (The tar File name have to be changed)
+
+
+PS. You can check the ALL Gradle Backup File location Users/d-pn-0071/Desktop/lala/kamco-dabeeo-backoffice/gradle/win/kamco-dabeeo-backoffice_gradle.tar.gz
\ No newline at end of file
diff --git a/kamco-make-dataset-generation/gradle/win/scripts/pack_offline_bundle_airgap.ps1 b/kamco-make-dataset-generation/gradle/win/scripts/pack_offline_bundle_airgap.ps1
new file mode 100755
index 0000000..35e2b99
--- /dev/null
+++ b/kamco-make-dataset-generation/gradle/win/scripts/pack_offline_bundle_airgap.ps1
@@ -0,0 +1,672 @@
+# pack_offline_bundle_airgap.ps1
+# ============================================================================
+# Gradle Offline Bundle Packer
+# ============================================================================
+# Version: 4.0
+#
+# WORKFLOW:
+# 1. [ONLINE] Build project (./gradlew.bat bootJar) - downloads all deps
+# 2. [ONLINE] Test run (./gradlew.bat bootRun) - verify app works
+# 3. [OFFLINE TEST] Verify offline build works
+# 4. Create bundle with all cached dependencies
+#
+# REQUIREMENTS:
+# - Internet connection (for initial build)
+# - Project with gradlew.bat
+# ============================================================================
+
+$ErrorActionPreference = "Stop"
+$ProgressPreference = "SilentlyContinue"
+
+# ============================================================================
+# Configuration
+# ============================================================================
+$WRAPPER_SEED_PATH = "wrapper_jar_seed"
+$OFFLINE_HOME_NAME = "_offline_gradle_home"
+$BOOTRUN_TIMEOUT_SECONDS = 60
+
+Write-Host ""
+Write-Host "============================================================" -ForegroundColor Cyan
+Write-Host " Gradle Offline Bundle Packer v4.0" -ForegroundColor Cyan
+Write-Host "============================================================" -ForegroundColor Cyan
+Write-Host ""
+Write-Host " This script will:" -ForegroundColor White
+Write-Host " 1. Build project with internet (download dependencies)" -ForegroundColor Gray
+Write-Host " 2. Test run application (verify it works)" -ForegroundColor Gray
+Write-Host " 3. Test offline build (verify cache is complete)" -ForegroundColor Gray
+Write-Host " 4. Create offline bundle for air-gapped environment" -ForegroundColor Gray
+Write-Host ""
+Write-Host "============================================================" -ForegroundColor Cyan
+Write-Host ""
+
+# ============================================================================
+# [1/20] Check Current Directory
+# ============================================================================
+Write-Host "==[1/20] Check Current Directory ==" -ForegroundColor Yellow
+$Root = (Get-Location).Path
+Write-Host ("ROOT_DIR: " + $Root)
+Write-Host ""
+
+# ============================================================================
+# [2/20] Check Required Files
+# ============================================================================
+Write-Host "==[2/20] Check Required Files ==" -ForegroundColor Yellow
+
+if (!(Test-Path -LiteralPath ".\gradlew.bat")) {
+ throw "ERROR: gradlew.bat not found. Run from project root."
+}
+Write-Host "[OK] gradlew.bat" -ForegroundColor Green
+
+$buildFile = $null
+if (Test-Path -LiteralPath ".\build.gradle") { $buildFile = "build.gradle" }
+elseif (Test-Path -LiteralPath ".\build.gradle.kts") { $buildFile = "build.gradle.kts" }
+else { throw "ERROR: build.gradle(.kts) not found." }
+Write-Host ("[OK] " + $buildFile) -ForegroundColor Green
+
+$settingsFile = $null
+if (Test-Path -LiteralPath ".\settings.gradle") { $settingsFile = "settings.gradle" }
+elseif (Test-Path -LiteralPath ".\settings.gradle.kts") { $settingsFile = "settings.gradle.kts" }
+if ($settingsFile) { Write-Host ("[OK] " + $settingsFile) -ForegroundColor Green }
+Write-Host ""
+
+# ============================================================================
+# [3/20] Check Gradle Wrapper
+# ============================================================================
+Write-Host "==[3/20] Check Gradle Wrapper ==" -ForegroundColor Yellow
+
+$WrapperDir = Join-Path $Root "gradle\wrapper"
+$WrapperJar = Join-Path $WrapperDir "gradle-wrapper.jar"
+$WrapperProp = Join-Path $WrapperDir "gradle-wrapper.properties"
+
+New-Item -ItemType Directory -Force -Path $WrapperDir | Out-Null
+
+if (!(Test-Path -LiteralPath $WrapperProp)) {
+ throw "ERROR: gradle-wrapper.properties not found."
+}
+
+if (!(Test-Path -LiteralPath $WrapperJar)) {
+ $SeedJar = Join-Path $Root "$WRAPPER_SEED_PATH\gradle-wrapper.jar"
+ if (Test-Path -LiteralPath $SeedJar) {
+ Copy-Item -Force -LiteralPath $SeedJar -Destination $WrapperJar
+ Write-Host "[OK] Wrapper jar injected from seed" -ForegroundColor Green
+ } else {
+ throw "ERROR: gradle-wrapper.jar missing"
+ }
+} else {
+ Write-Host "[OK] gradle-wrapper.jar exists" -ForegroundColor Green
+}
+
+# Create seed backup
+$SeedDir = Join-Path $Root $WRAPPER_SEED_PATH
+if (!(Test-Path -LiteralPath $SeedDir)) {
+ New-Item -ItemType Directory -Force -Path $SeedDir | Out-Null
+ Copy-Item -Force -LiteralPath $WrapperJar -Destination (Join-Path $SeedDir "gradle-wrapper.jar")
+}
+Write-Host ""
+
+# ============================================================================
+# [4/20] Set GRADLE_USER_HOME (Project Local)
+# ============================================================================
+Write-Host "==[4/20] Set GRADLE_USER_HOME ==" -ForegroundColor Yellow
+
+$OfflineHome = Join-Path $Root $OFFLINE_HOME_NAME
+New-Item -ItemType Directory -Force -Path $OfflineHome | Out-Null
+$env:GRADLE_USER_HOME = $OfflineHome
+
+Write-Host ("GRADLE_USER_HOME = " + $env:GRADLE_USER_HOME) -ForegroundColor Cyan
+Write-Host "[INFO] All dependencies will be cached in project folder" -ForegroundColor Gray
+Write-Host ""
+
+# ============================================================================
+# [5/20] Check Internet Connection
+# ============================================================================
+Write-Host "==[5/20] Check Internet Connection ==" -ForegroundColor Yellow
+
+$hasInternet = $false
+$testHosts = @("plugins.gradle.org", "repo.maven.apache.org", "repo1.maven.org")
+
+foreach ($testHost in $testHosts) {
+ try {
+ $result = Test-Connection -ComputerName $testHost -Count 1 -Quiet -TimeoutSeconds 3 -ErrorAction SilentlyContinue
+ if ($result) {
+ $hasInternet = $true
+ Write-Host ("[OK] Connected to " + $testHost) -ForegroundColor Green
+ break
+ }
+ } catch { }
+}
+
+if (-not $hasInternet) {
+ # Try DNS resolution as fallback
+ try {
+ [System.Net.Dns]::GetHostAddresses("google.com") | Out-Null
+ $hasInternet = $true
+ Write-Host "[OK] Internet available (DNS)" -ForegroundColor Green
+ } catch { }
+}
+
+if (-not $hasInternet) {
+ Write-Host ""
+ Write-Host "============================================================" -ForegroundColor Red
+ Write-Host " ERROR: No Internet Connection!" -ForegroundColor Red
+ Write-Host "============================================================" -ForegroundColor Red
+ Write-Host ""
+ Write-Host "This script requires internet for initial build." -ForegroundColor Yellow
+ Write-Host "Please connect to internet and run again." -ForegroundColor Yellow
+ Write-Host ""
+ throw "No internet connection"
+}
+Write-Host ""
+
+# ============================================================================
+# [6/20] Initial Gradle Setup
+# ============================================================================
+Write-Host "==[6/20] Initial Gradle Setup ==" -ForegroundColor Yellow
+Write-Host "[INFO] Downloading Gradle distribution..." -ForegroundColor Gray
+
+try {
+ $output = cmd /c ".\gradlew.bat --version 2>&1"
+ if ($LASTEXITCODE -eq 0) {
+ $gradleVersion = $output | Select-String "Gradle\s+(\d+\.\d+)" |
+ ForEach-Object { $_.Matches[0].Groups[1].Value }
+ Write-Host ("[OK] Gradle " + $gradleVersion) -ForegroundColor Green
+ } else {
+ throw "Gradle setup failed"
+ }
+} catch {
+ Write-Host "[ERROR] Gradle setup failed" -ForegroundColor Red
+ throw $_
+}
+Write-Host ""
+
+# ============================================================================
+# [7/20] ONLINE BUILD - bootJar (Download All Dependencies)
+# ============================================================================
+Write-Host "==[7/20] ONLINE BUILD - bootJar ==" -ForegroundColor Yellow
+Write-Host ""
+Write-Host "============================================================" -ForegroundColor Cyan
+Write-Host " Building project (downloading all dependencies)" -ForegroundColor Cyan
+Write-Host " This may take several minutes on first run..." -ForegroundColor Cyan
+Write-Host "============================================================" -ForegroundColor Cyan
+Write-Host ""
+
+$buildSuccess = $false
+
+try {
+ cmd /c ".\gradlew.bat clean bootJar --no-daemon"
+ if ($LASTEXITCODE -eq 0) {
+ $buildSuccess = $true
+ }
+} catch { }
+
+if (-not $buildSuccess) {
+ Write-Host ""
+ Write-Host "============================================================" -ForegroundColor Red
+ Write-Host " BUILD FAILED!" -ForegroundColor Red
+ Write-Host "============================================================" -ForegroundColor Red
+ Write-Host ""
+ Write-Host "Please fix build errors and run this script again." -ForegroundColor Yellow
+ throw "Build failed"
+}
+
+Write-Host ""
+Write-Host "[OK] bootJar build SUCCESS" -ForegroundColor Green
+Write-Host ""
+
+# ============================================================================
+# [8/20] ONLINE TEST - bootRun (Verify Application Works)
+# ============================================================================
+Write-Host "==[8/20] ONLINE TEST - bootRun ==" -ForegroundColor Yellow
+Write-Host ""
+Write-Host "============================================================" -ForegroundColor Cyan
+Write-Host " Starting application to verify it works..." -ForegroundColor Cyan
+Write-Host " Will run for $BOOTRUN_TIMEOUT_SECONDS seconds then stop" -ForegroundColor Cyan
+Write-Host "============================================================" -ForegroundColor Cyan
+Write-Host ""
+
+$bootRunSuccess = $false
+
+try {
+ # Start bootRun as background job
+ $job = Start-Job -ScriptBlock {
+ param($projectDir, $gradleHome)
+ Set-Location $projectDir
+ $env:GRADLE_USER_HOME = $gradleHome
+ cmd /c ".\gradlew.bat bootRun --no-daemon 2>&1"
+ } -ArgumentList $Root, $OfflineHome
+
+ Write-Host "[INFO] Application starting..." -ForegroundColor Gray
+
+ # Wait for startup (check for typical Spring Boot messages)
+ $startTime = Get-Date
+ $startupDetected = $false
+
+ while (((Get-Date) - $startTime).TotalSeconds -lt $BOOTRUN_TIMEOUT_SECONDS) {
+ Start-Sleep -Seconds 3
+
+ # Check if job has output
+ $jobOutput = Receive-Job -Job $job -Keep -ErrorAction SilentlyContinue
+
+ if ($jobOutput) {
+ $outputText = $jobOutput -join "`n"
+
+ # Check for Spring Boot startup success indicators
+ if ($outputText -match "Started .+ in .+ seconds" -or
+ $outputText -match "Tomcat started on port" -or
+ $outputText -match "Netty started on port" -or
+ $outputText -match "Application .+ started") {
+ $startupDetected = $true
+ Write-Host "[OK] Application started successfully!" -ForegroundColor Green
+ break
+ }
+
+ # Check for errors
+ if ($outputText -match "APPLICATION FAILED TO START" -or
+ $outputText -match "Error starting ApplicationContext") {
+ Write-Host "[ERROR] Application failed to start" -ForegroundColor Red
+ break
+ }
+ }
+
+ $elapsed = [math]::Round(((Get-Date) - $startTime).TotalSeconds)
+ Write-Host ("[INFO] Waiting... " + $elapsed + "s") -ForegroundColor Gray
+ }
+
+ # Stop the job
+ Write-Host "[INFO] Stopping application..." -ForegroundColor Gray
+ Stop-Job -Job $job -ErrorAction SilentlyContinue
+ Remove-Job -Job $job -Force -ErrorAction SilentlyContinue
+
+ # Also stop any remaining Gradle processes
+ cmd /c ".\gradlew.bat --stop 2>&1" | Out-Null
+
+ if ($startupDetected) {
+ $bootRunSuccess = $true
+ }
+
+} catch {
+ Write-Host "[WARN] bootRun test encountered error: $_" -ForegroundColor DarkYellow
+}
+
+# Cleanup any remaining processes
+try {
+ Get-Process -Name "java" -ErrorAction SilentlyContinue |
+ Where-Object { $_.CommandLine -match "bootRun|spring" } |
+ Stop-Process -Force -ErrorAction SilentlyContinue
+} catch { }
+
+Write-Host ""
+
+if ($bootRunSuccess) {
+ Write-Host "[OK] bootRun test PASSED" -ForegroundColor Green
+} else {
+ Write-Host "[WARN] bootRun test could not verify startup" -ForegroundColor DarkYellow
+ Write-Host "[INFO] Continuing anyway - bootJar succeeded" -ForegroundColor Gray
+}
+Write-Host ""
+
+# ============================================================================
+# [9/20] Stop All Gradle Daemons
+# ============================================================================
+Write-Host "==[9/20] Stop Gradle Daemons ==" -ForegroundColor Yellow
+
+cmd /c ".\gradlew.bat --stop 2>&1" | Out-Null
+Start-Sleep -Seconds 3
+Write-Host "[OK] Daemons stopped" -ForegroundColor Green
+Write-Host ""
+
+# ============================================================================
+# [10/20] OFFLINE TEST - Verify Offline Build Works
+# ============================================================================
+Write-Host "==[10/20] OFFLINE TEST - Verify Cache ==" -ForegroundColor Yellow
+Write-Host ""
+Write-Host "============================================================" -ForegroundColor Cyan
+Write-Host " Testing offline build (--offline flag)" -ForegroundColor Cyan
+Write-Host " This verifies all dependencies are cached" -ForegroundColor Cyan
+Write-Host "============================================================" -ForegroundColor Cyan
+Write-Host ""
+
+$offlineSuccess = $false
+
+try {
+ cmd /c ".\gradlew.bat --offline clean bootJar --no-daemon"
+ if ($LASTEXITCODE -eq 0) {
+ $offlineSuccess = $true
+ }
+} catch { }
+
+Write-Host ""
+
+if ($offlineSuccess) {
+ Write-Host "[OK] Offline build SUCCESS - Cache is complete!" -ForegroundColor Green
+} else {
+ Write-Host "============================================================" -ForegroundColor Red
+ Write-Host " OFFLINE BUILD FAILED!" -ForegroundColor Red
+ Write-Host "============================================================" -ForegroundColor Red
+ Write-Host ""
+ Write-Host "Some dependencies may not be cached properly." -ForegroundColor Yellow
+ Write-Host ""
+
+ $continue = Read-Host "Continue creating bundle anyway? (y/N)"
+ if ($continue -ne "y" -and $continue -ne "Y") {
+ throw "Offline verification failed"
+ }
+}
+Write-Host ""
+
+# ============================================================================
+# [11/20] Backup Original settings.gradle
+# ============================================================================
+Write-Host "==[11/20] Backup settings.gradle ==" -ForegroundColor Yellow
+
+if ($settingsFile) {
+ $settingsPath = Join-Path $Root $settingsFile
+ $settingsBackup = Join-Path $Root "${settingsFile}.original.bak"
+
+ if (!(Test-Path -LiteralPath $settingsBackup)) {
+ Copy-Item -Force -LiteralPath $settingsPath -Destination $settingsBackup
+ Write-Host "[OK] Backup: ${settingsFile}.original.bak" -ForegroundColor Green
+ } else {
+ Write-Host "[OK] Backup exists" -ForegroundColor Green
+ }
+}
+Write-Host ""
+
+# ============================================================================
+# [12/20] Modify settings.gradle for Offline
+# ============================================================================
+Write-Host "==[12/20] Configure settings.gradle for Offline ==" -ForegroundColor Yellow
+
+if ($settingsFile) {
+ $settingsPath = Join-Path $Root $settingsFile
+ $content = Get-Content -LiteralPath $settingsPath -Raw
+
+ # --- Always strip BOM if present (prevents Groovy 'Unexpected character: ')
+ $hadBom = $false
+ if ($content.Length -gt 0 -and $content[0] -eq [char]0xFEFF) {
+ $hadBom = $true
+ $content = $content -replace "^\uFEFF", ""
+ }
+
+ $isOfflineConfigured =
+ ($content -match "mavenLocal\(\)") -and
+ ($content -match "pluginManagement[\s\S]*repositories")
+
+ if ($isOfflineConfigured) {
+ # Even if already configured, re-save without BOM if needed
+ if ($hadBom) {
+ [System.IO.File]::WriteAllText(
+ $settingsPath,
+ $content,
+ (New-Object System.Text.UTF8Encoding($false))
+ )
+ Write-Host "[FIX] settings.gradle BOM removed (saved as UTF-8 without BOM)" -ForegroundColor Green
+ } else {
+ Write-Host "[OK] Already configured for offline" -ForegroundColor Green
+ }
+ } else {
+ $newHeader = @"
+// ============================================================================
+// OFFLINE BUILD CONFIGURATION (Auto-generated by pack script)
+// Original backup: ${settingsFile}.original.bak
+// ============================================================================
+pluginManagement {
+ repositories {
+ mavenLocal()
+ gradlePluginPortal()
+ }
+}
+
+"@
+
+ # Remove existing pluginManagement
+ $cleaned = $content -replace '(?s)pluginManagement\s*\{[^{}]*(\{[^{}]*\}[^{}]*)*\}\s*', ''
+ $final = $newHeader + $cleaned.Trim()
+
+ # --- Write as UTF-8 WITHOUT BOM
+ [System.IO.File]::WriteAllText(
+ $settingsPath,
+ $final,
+ (New-Object System.Text.UTF8Encoding($false))
+ )
+
+ Write-Host "[OK] settings.gradle updated for offline (UTF-8 without BOM)" -ForegroundColor Green
+ }
+}
+Write-Host ""
+
+# ============================================================================
+# [13/20] Copy Maven Local Repository
+# ============================================================================
+Write-Host "==[13/20] Copy Maven Local (.m2) ==" -ForegroundColor Yellow
+
+$m2Repo = Join-Path $env:USERPROFILE ".m2\repository"
+$localM2 = Join-Path $OfflineHome "m2_repository"
+
+if (Test-Path -LiteralPath $m2Repo) {
+ $m2Size = (Get-ChildItem -Path $m2Repo -Recurse -File -ErrorAction SilentlyContinue |
+ Measure-Object -Property Length -Sum).Sum
+
+ if ($m2Size -gt 1MB) {
+ $m2SizeMB = [math]::Round($m2Size / 1MB, 2)
+ Write-Host ("[INFO] .m2 size: " + $m2SizeMB + " MB") -ForegroundColor Cyan
+
+ # Copy important plugin directories
+ $pluginDirs = @(
+ "org\springframework\boot",
+ "io\spring",
+ "com\diffplug"
+ )
+
+ foreach ($dir in $pluginDirs) {
+ $src = Join-Path $m2Repo $dir
+ if (Test-Path -LiteralPath $src) {
+ $dst = Join-Path $localM2 $dir
+ New-Item -ItemType Directory -Force -Path (Split-Path $dst -Parent) | Out-Null
+ if (!(Test-Path -LiteralPath $dst)) {
+ Copy-Item -Recurse -Force -LiteralPath $src -Destination $dst -ErrorAction SilentlyContinue
+ Write-Host ("[OK] Copied " + $dir) -ForegroundColor Green
+ }
+ }
+ }
+ }
+} else {
+ Write-Host "[INFO] No .m2 repository found" -ForegroundColor Gray
+}
+Write-Host ""
+
+# ============================================================================
+# [14/20] Create Helper Scripts
+# ============================================================================
+Write-Host "==[14/20] Create Helper Scripts ==" -ForegroundColor Yellow
+
+# run_offline_build.ps1
+$runScript = @'
+# run_offline_build.ps1 - Quick offline build script
+$env:GRADLE_USER_HOME = Join-Path (Get-Location).Path "_offline_gradle_home"
+Write-Host "GRADLE_USER_HOME = $env:GRADLE_USER_HOME" -ForegroundColor Cyan
+Write-Host ""
+.\gradlew.bat --offline bootJar --no-daemon
+if ($LASTEXITCODE -eq 0) {
+ Write-Host ""
+ Write-Host "BUILD SUCCESS!" -ForegroundColor Green
+ Write-Host ""
+ Write-Host "JAR files:" -ForegroundColor Cyan
+ Get-ChildItem .\build\libs\*.jar | ForEach-Object { Write-Host (" " + $_.Name) }
+} else {
+ Write-Host "BUILD FAILED" -ForegroundColor Red
+}
+'@
+
+[System.IO.File]::WriteAllText((Join-Path $Root "run_offline_build.ps1"), $runScript, (New-Object System.Text.UTF8Encoding($false)))
+Write-Host "[OK] run_offline_build.ps1" -ForegroundColor Green
+
+# run_offline_bootrun.ps1
+$bootRunScript = @'
+# run_offline_bootrun.ps1 - Run application offline
+$env:GRADLE_USER_HOME = Join-Path (Get-Location).Path "_offline_gradle_home"
+Write-Host "GRADLE_USER_HOME = $env:GRADLE_USER_HOME" -ForegroundColor Cyan
+Write-Host ""
+Write-Host "Starting application (Ctrl+C to stop)..." -ForegroundColor Yellow
+Write-Host ""
+.\gradlew.bat --offline bootRun --no-daemon
+'@
+
+[System.IO.File]::WriteAllText((Join-Path $Root "run_offline_bootrun.ps1"), $bootRunScript, (New-Object System.Text.UTF8Encoding($false)))
+Write-Host "[OK] run_offline_bootrun.ps1" -ForegroundColor Green
+Write-Host ""
+
+# ============================================================================
+# [15/20] Stop Daemons Again
+# ============================================================================
+Write-Host "==[15/20] Final Daemon Cleanup ==" -ForegroundColor Yellow
+
+cmd /c ".\gradlew.bat --stop 2>&1" | Out-Null
+Start-Sleep -Seconds 2
+Write-Host "[OK] Daemons stopped" -ForegroundColor Green
+Write-Host ""
+
+# ============================================================================
+# [16/20] Clean Lock Files
+# ============================================================================
+Write-Host "==[16/20] Clean Lock Files ==" -ForegroundColor Yellow
+
+try {
+ $DaemonDir = Join-Path $OfflineHome "daemon"
+ if (Test-Path -LiteralPath $DaemonDir) {
+ Remove-Item -Recurse -Force -LiteralPath $DaemonDir -ErrorAction SilentlyContinue
+ }
+
+ Get-ChildItem -Path $OfflineHome -Recurse -Include "*.lock","*.log","*.tmp" -File -ErrorAction SilentlyContinue |
+ ForEach-Object { Remove-Item -Force -LiteralPath $_.FullName -ErrorAction SilentlyContinue }
+
+ Write-Host "[OK] Lock files cleaned" -ForegroundColor Green
+} catch {
+ Write-Host "[WARN] Some files could not be cleaned" -ForegroundColor DarkYellow
+}
+Write-Host ""
+
+# ============================================================================
+# [17/20] Calculate Cache Size
+# ============================================================================
+Write-Host "==[17/20] Cache Summary ==" -ForegroundColor Yellow
+
+$CachesDir = Join-Path $OfflineHome "caches"
+$WrapperDists = Join-Path $OfflineHome "wrapper\dists"
+
+$totalSize = 0
+
+if (Test-Path -LiteralPath $CachesDir) {
+ $size = (Get-ChildItem -Path $CachesDir -Recurse -File -ErrorAction SilentlyContinue |
+ Measure-Object -Property Length -Sum).Sum
+ $totalSize += $size
+ Write-Host ("[INFO] Dependencies: " + [math]::Round($size/1MB, 2) + " MB") -ForegroundColor Cyan
+}
+
+if (Test-Path -LiteralPath $WrapperDists) {
+ $size = (Get-ChildItem -Path $WrapperDists -Recurse -File -ErrorAction SilentlyContinue |
+ Measure-Object -Property Length -Sum).Sum
+ $totalSize += $size
+ Write-Host ("[INFO] Gradle dist: " + [math]::Round($size/1MB, 2) + " MB") -ForegroundColor Cyan
+}
+
+Write-Host ("[INFO] Total cache: " + [math]::Round($totalSize/1MB, 2) + " MB") -ForegroundColor Cyan
+Write-Host ""
+
+# ============================================================================
+# [18/20] Create Archive
+# ============================================================================
+Write-Host "==[18/20] Create Archive ==" -ForegroundColor Yellow
+
+$BaseName = Split-Path $Root -Leaf
+$Ts = Get-Date -Format "yyyyMMdd_HHmmss"
+$Parent = Split-Path $Root -Parent
+$ArchivePath = Join-Path $Parent "${BaseName}_offline_bundle_${Ts}.tar.gz"
+
+Write-Host ("Archive: " + $ArchivePath)
+
+$tar = Get-Command tar.exe -ErrorAction SilentlyContinue
+if (-not $tar) { throw "ERROR: tar.exe not found" }
+
+Write-Host "[INFO] Creating archive (this may take several minutes)..." -ForegroundColor Gray
+
+& tar.exe -czf $ArchivePath `
+ --exclude ".git" `
+ --exclude ".idea" `
+ --exclude ".DS_Store" `
+ --exclude "*.log" `
+ --exclude "*.lock" `
+ --exclude "_offline_gradle_home/daemon" `
+ --exclude "_offline_gradle_home/native" `
+ --exclude "_offline_gradle_home/jdks" `
+ --exclude "build" `
+ --exclude "out" `
+ --exclude ".gradle" `
+ -C $Root .
+
+if ($LASTEXITCODE -ne 0) { throw "ERROR: tar failed" }
+
+$archiveSize = (Get-Item -LiteralPath $ArchivePath).Length
+$archiveSizeMB = [math]::Round($archiveSize / 1MB, 2)
+Write-Host ("[OK] Archive created: " + $archiveSizeMB + " MB") -ForegroundColor Green
+Write-Host ""
+
+# ============================================================================
+# [19/20] Verify Archive
+# ============================================================================
+Write-Host "==[19/20] Verify Archive ==" -ForegroundColor Yellow
+
+$listOutput = & tar.exe -tzf $ArchivePath 2>&1
+
+$checks = @(
+ "gradle/wrapper/gradle-wrapper.jar",
+ "gradlew.bat",
+ "_offline_gradle_home/caches",
+ "run_offline_build.ps1"
+)
+
+foreach ($check in $checks) {
+ $found = $listOutput | Select-String -SimpleMatch $check
+ if ($found) {
+ Write-Host (" [OK] " + $check) -ForegroundColor Green
+ } else {
+ Write-Host (" [WARN] " + $check) -ForegroundColor DarkYellow
+ }
+}
+Write-Host ""
+
+# ============================================================================
+# [20/20] Complete
+# ============================================================================
+Write-Host "============================================================" -ForegroundColor Green
+Write-Host " BUNDLE CREATION COMPLETE!" -ForegroundColor Green
+Write-Host "============================================================" -ForegroundColor Green
+Write-Host ""
+Write-Host ("Archive: " + $ArchivePath) -ForegroundColor Cyan
+Write-Host ("Size: " + $archiveSizeMB + " MB") -ForegroundColor Cyan
+Write-Host ""
+
+Write-Host "============================================================" -ForegroundColor Cyan
+Write-Host " Test Results" -ForegroundColor Cyan
+Write-Host "============================================================" -ForegroundColor Cyan
+Write-Host (" Online build (bootJar): " + $(if($buildSuccess){"PASSED"}else{"FAILED"})) -ForegroundColor $(if($buildSuccess){"Green"}else{"Red"})
+Write-Host (" Online test (bootRun): " + $(if($bootRunSuccess){"PASSED"}else{"SKIPPED"})) -ForegroundColor $(if($bootRunSuccess){"Green"}else{"Yellow"})
+Write-Host (" Offline build test: " + $(if($offlineSuccess){"PASSED"}else{"FAILED"})) -ForegroundColor $(if($offlineSuccess){"Green"}else{"Red"})
+Write-Host ""
+
+Write-Host "============================================================" -ForegroundColor Yellow
+Write-Host " Usage in Air-gapped Environment" -ForegroundColor Yellow
+Write-Host "============================================================" -ForegroundColor Yellow
+Write-Host ""
+Write-Host "Option 1: Use unpack script" -ForegroundColor White
+Write-Host " .\unpack_and_offline_build_airgap.ps1" -ForegroundColor Gray
+Write-Host ""
+Write-Host "Option 2: Manual extraction" -ForegroundColor White
+Write-Host " tar -xzf .tar.gz" -ForegroundColor Gray
+Write-Host " cd " -ForegroundColor Gray
+Write-Host " .\run_offline_build.ps1" -ForegroundColor Gray
+Write-Host ""
+Write-Host "Option 3: Direct commands" -ForegroundColor White
+Write-Host ' $env:GRADLE_USER_HOME = ".\\_offline_gradle_home"' -ForegroundColor Gray
+Write-Host " .\gradlew.bat --offline bootJar --no-daemon" -ForegroundColor Gray
+Write-Host ""
diff --git a/kamco-make-dataset-generation/gradle/win/scripts/unpack_and_offline_build_airgap.ps1 b/kamco-make-dataset-generation/gradle/win/scripts/unpack_and_offline_build_airgap.ps1
new file mode 100755
index 0000000..9342a2f
--- /dev/null
+++ b/kamco-make-dataset-generation/gradle/win/scripts/unpack_and_offline_build_airgap.ps1
@@ -0,0 +1,355 @@
+# unpack_and_offline_build_airgap.ps1
+# ============================================================================
+# Execution Environment: OFFLINE (Air-gapped, No Internet)
+# Purpose: Extract bundle and run offline build
+# ============================================================================
+# Windows PowerShell Only
+# Version: 3.1
+#
+# IMPORTANT: This script automatically:
+# 1. Extracts the archive
+# 2. Sets GRADLE_USER_HOME to project local cache
+# 3. Configures settings.gradle for offline resolution
+# 4. Runs build with --offline flag
+# ============================================================================
+
+$ErrorActionPreference = "Stop"
+$ProgressPreference = "SilentlyContinue"
+
+# ============================================================================
+# Configuration
+# ============================================================================
+$WRAPPER_SEED_PATH = "wrapper_jar_seed"
+$OFFLINE_HOME_NAME = "_offline_gradle_home"
+
+Write-Host ""
+Write-Host "============================================================" -ForegroundColor Cyan
+Write-Host " Gradle Offline Build Runner" -ForegroundColor Cyan
+Write-Host " Environment: AIR-GAPPED (No Internet)" -ForegroundColor Cyan
+Write-Host " Mode: Fully Offline (--offline enforced)" -ForegroundColor Cyan
+Write-Host "============================================================" -ForegroundColor Cyan
+Write-Host ""
+
+# ============================================================================
+# [1/16] Check Current Directory
+# ============================================================================
+Write-Host "==[1/16] Check Current Directory ==" -ForegroundColor Yellow
+$Start = (Get-Location).Path
+Write-Host ("PWD: " + $Start)
+Write-Host ""
+
+# ============================================================================
+# [2/16] Select Archive
+# ============================================================================
+Write-Host "==[2/16] Select Archive ==" -ForegroundColor Yellow
+
+$Archive = $null
+if ($args.Count -ge 1) {
+ $Archive = $args[0].Trim().Trim('"').Trim("'")
+}
+
+if ([string]::IsNullOrWhiteSpace($Archive)) {
+ $candidates = Get-ChildItem -Path $Start -File -ErrorAction SilentlyContinue |
+ Where-Object { $_.Name -match "\.(tar\.gz|tgz)$" } |
+ Sort-Object LastWriteTime -Descending
+
+ if (-not $candidates -or $candidates.Count -eq 0) {
+ Write-Host "[ERROR] No archive found" -ForegroundColor Red
+ Get-ChildItem -Path $Start -File | Format-Table Name, Length -AutoSize
+ throw "ERROR: No .tar.gz file found"
+ }
+
+ $Archive = $candidates[0].FullName
+ Write-Host ("[AUTO] " + (Split-Path $Archive -Leaf)) -ForegroundColor Cyan
+} else {
+ if (-not [System.IO.Path]::IsPathRooted($Archive)) {
+ $Archive = Join-Path $Start $Archive
+ }
+ Write-Host ("[USER] " + (Split-Path $Archive -Leaf)) -ForegroundColor Cyan
+}
+
+if (-not (Test-Path -LiteralPath $Archive)) {
+ throw "ERROR: Archive not found: $Archive"
+}
+
+$archiveSizeMB = [math]::Round((Get-Item -LiteralPath $Archive).Length / 1MB, 2)
+Write-Host ("Size: " + $archiveSizeMB + " MB")
+Write-Host ""
+
+# ============================================================================
+# [3/16] Check tar.exe
+# ============================================================================
+Write-Host "==[3/16] Check tar.exe ==" -ForegroundColor Yellow
+
+$tar = Get-Command tar.exe -ErrorAction SilentlyContinue
+if (-not $tar) { throw "ERROR: tar.exe not found" }
+Write-Host "[OK] tar.exe found" -ForegroundColor Green
+Write-Host ""
+
+# ============================================================================
+# [4/16] Extract Archive
+# ============================================================================
+Write-Host "==[4/16] Extract Archive ==" -ForegroundColor Yellow
+Write-Host "[INFO] Extracting..." -ForegroundColor Gray
+
+& tar.exe -xzf $Archive -C $Start
+if ($LASTEXITCODE -ne 0) { throw "ERROR: Extraction failed" }
+Write-Host "[OK] Extracted" -ForegroundColor Green
+Write-Host ""
+
+# ============================================================================
+# [5/16] Unblock Files
+# ============================================================================
+Write-Host "==[5/16] Unblock Files ==" -ForegroundColor Yellow
+
+try {
+ Get-ChildItem -Path $Start -Recurse -Force -ErrorAction SilentlyContinue |
+ Unblock-File -ErrorAction SilentlyContinue
+ Write-Host "[OK] Files unblocked" -ForegroundColor Green
+} catch {
+ Write-Host "[WARN] Unblock failed" -ForegroundColor DarkYellow
+}
+Write-Host ""
+
+# ============================================================================
+# [6/16] Find Project Root
+# ============================================================================
+Write-Host "==[6/16] Find Project Root ==" -ForegroundColor Yellow
+
+$gradlewList = Get-ChildItem -Path $Start -Recurse -Filter "gradlew.bat" -File -ErrorAction SilentlyContinue
+if (-not $gradlewList) { throw "ERROR: gradlew.bat not found" }
+
+$gradlew = $gradlewList | Sort-Object { $_.FullName.Length } | Select-Object -First 1
+$ProjectDir = $gradlew.Directory.FullName
+
+Write-Host ("Project: " + $ProjectDir) -ForegroundColor Cyan
+Set-Location -LiteralPath $ProjectDir
+Write-Host ""
+
+# ============================================================================
+# [7/16] Fix Permissions
+# ============================================================================
+Write-Host "==[7/16] Fix Permissions ==" -ForegroundColor Yellow
+
+try {
+ $currentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
+ cmd /c "icacls `"$ProjectDir`" /grant `"$currentUser`:(OI)(CI)F`" /t /q" 2>&1 | Out-Null
+ Write-Host "[OK] Permissions fixed" -ForegroundColor Green
+} catch {
+ Write-Host "[WARN] icacls failed" -ForegroundColor DarkYellow
+}
+Write-Host ""
+
+# ============================================================================
+# [8/16] Verify Wrapper
+# ============================================================================
+Write-Host "==[8/16] Verify Wrapper ==" -ForegroundColor Yellow
+
+$WrapperDir = Join-Path $ProjectDir "gradle\wrapper"
+$WrapperJar = Join-Path $WrapperDir "gradle-wrapper.jar"
+$WrapperProp = Join-Path $WrapperDir "gradle-wrapper.properties"
+
+if (!(Test-Path -LiteralPath $WrapperProp)) {
+ throw "ERROR: gradle-wrapper.properties missing"
+}
+
+if (!(Test-Path -LiteralPath $WrapperJar)) {
+ $SeedJar = Join-Path $ProjectDir "$WRAPPER_SEED_PATH\gradle-wrapper.jar"
+ if (Test-Path -LiteralPath $SeedJar) {
+ New-Item -ItemType Directory -Force -Path $WrapperDir | Out-Null
+ Copy-Item -Force -LiteralPath $SeedJar -Destination $WrapperJar
+ Write-Host "[OK] Injected from seed" -ForegroundColor Green
+ } else {
+ throw "ERROR: wrapper jar missing"
+ }
+} else {
+ Write-Host "[OK] Wrapper verified" -ForegroundColor Green
+}
+Write-Host ""
+
+# ============================================================================
+# [9/16] Set GRADLE_USER_HOME
+# ============================================================================
+Write-Host "==[9/16] Set GRADLE_USER_HOME ==" -ForegroundColor Yellow
+
+$OfflineHome = Join-Path $ProjectDir $OFFLINE_HOME_NAME
+if (!(Test-Path -LiteralPath $OfflineHome)) {
+ throw "ERROR: _offline_gradle_home not found in archive"
+}
+
+$env:GRADLE_USER_HOME = $OfflineHome
+Write-Host ("GRADLE_USER_HOME = " + $env:GRADLE_USER_HOME) -ForegroundColor Cyan
+
+# Check cache
+$CachesDir = Join-Path $OfflineHome "caches"
+if (Test-Path -LiteralPath $CachesDir) {
+ $cacheSize = (Get-ChildItem -Path $CachesDir -Recurse -File -ErrorAction SilentlyContinue |
+ Measure-Object -Property Length -Sum).Sum
+ $cacheSizeMB = [math]::Round($cacheSize / 1MB, 2)
+ Write-Host ("[INFO] Cache size: " + $cacheSizeMB + " MB") -ForegroundColor Cyan
+} else {
+ Write-Host "[WARN] No cache folder found" -ForegroundColor DarkYellow
+}
+Write-Host ""
+
+# ============================================================================
+# [10/16] Verify settings.gradle
+# ============================================================================
+Write-Host "==[10/16] Verify settings.gradle ==" -ForegroundColor Yellow
+
+$settingsFile = $null
+if (Test-Path -LiteralPath ".\settings.gradle") { $settingsFile = "settings.gradle" }
+elseif (Test-Path -LiteralPath ".\settings.gradle.kts") { $settingsFile = "settings.gradle.kts" }
+
+if ($settingsFile) {
+ $content = Get-Content -LiteralPath ".\$settingsFile" -Raw
+ if ($content -match "mavenLocal\(\)" -and $content -match "pluginManagement") {
+ Write-Host "[OK] settings.gradle configured for offline" -ForegroundColor Green
+ } else {
+ Write-Host "[WARN] settings.gradle may not be configured for offline" -ForegroundColor DarkYellow
+ Write-Host "[INFO] Build may fail if plugins not cached" -ForegroundColor Gray
+ }
+}
+Write-Host ""
+
+# ============================================================================
+# [11/16] Test Gradle
+# ============================================================================
+Write-Host "==[11/16] Test Gradle ==" -ForegroundColor Yellow
+
+$gradleWorks = $false
+try {
+ $output = cmd /c ".\gradlew.bat --offline --version 2>&1"
+ if ($LASTEXITCODE -eq 0) {
+ $gradleWorks = $true
+ Write-Host "[OK] Gradle working in offline mode" -ForegroundColor Green
+ }
+} catch { }
+
+if (-not $gradleWorks) {
+ Write-Host "[WARN] Gradle --version failed" -ForegroundColor DarkYellow
+}
+Write-Host ""
+
+# ============================================================================
+# [12/16] Stop Daemon
+# ============================================================================
+Write-Host "==[12/16] Stop Daemon ==" -ForegroundColor Yellow
+
+try { cmd /c ".\gradlew.bat --stop 2>&1" | Out-Null } catch { }
+Start-Sleep -Seconds 2
+Write-Host "[OK] Daemon stopped" -ForegroundColor Green
+Write-Host ""
+
+# ============================================================================
+# [13/16] Run Offline Build
+# ============================================================================
+Write-Host "==[13/16] Run Offline Build ==" -ForegroundColor Yellow
+Write-Host ""
+Write-Host "============================================================" -ForegroundColor Cyan
+Write-Host " Building with --offline flag" -ForegroundColor Cyan
+Write-Host " All dependencies from local cache" -ForegroundColor Cyan
+Write-Host "============================================================" -ForegroundColor Cyan
+Write-Host ""
+
+$buildSuccess = $false
+$buildTask = $null
+
+# Try bootJar
+Write-Host "[TRY] --offline bootJar..." -ForegroundColor Gray
+try {
+ cmd /c ".\gradlew.bat --offline clean bootJar --no-daemon"
+ if ($LASTEXITCODE -eq 0) {
+ $buildSuccess = $true
+ $buildTask = "bootJar"
+ }
+} catch { }
+
+# Try jar
+if (-not $buildSuccess) {
+ Write-Host "[TRY] --offline jar..." -ForegroundColor Gray
+ try {
+ cmd /c ".\gradlew.bat --offline clean jar --no-daemon"
+ if ($LASTEXITCODE -eq 0) {
+ $buildSuccess = $true
+ $buildTask = "jar"
+ }
+ } catch { }
+}
+
+# Try build
+if (-not $buildSuccess) {
+ Write-Host "[TRY] --offline build..." -ForegroundColor Gray
+ try {
+ cmd /c ".\gradlew.bat --offline build --no-daemon"
+ if ($LASTEXITCODE -eq 0) {
+ $buildSuccess = $true
+ $buildTask = "build"
+ }
+ } catch { }
+}
+
+Write-Host ""
+if ($buildSuccess) {
+ Write-Host "============================================================" -ForegroundColor Green
+ Write-Host (" BUILD SUCCESS! (task: " + $buildTask + ")") -ForegroundColor Green
+ Write-Host "============================================================" -ForegroundColor Green
+} else {
+ Write-Host "============================================================" -ForegroundColor Red
+ Write-Host " BUILD FAILED!" -ForegroundColor Red
+ Write-Host "============================================================" -ForegroundColor Red
+ Write-Host ""
+ Write-Host "Possible causes:" -ForegroundColor Yellow
+ Write-Host " - Dependencies not in cache" -ForegroundColor White
+ Write-Host " - Plugin resolution failed" -ForegroundColor White
+ Write-Host " - Need complete build in online env first" -ForegroundColor White
+ throw "Build failed"
+}
+Write-Host ""
+
+# ============================================================================
+# [14/16] Show Build Output
+# ============================================================================
+Write-Host "==[14/16] Build Output ==" -ForegroundColor Yellow
+
+$libsDir = Join-Path $ProjectDir "build\libs"
+if (Test-Path -LiteralPath $libsDir) {
+ Write-Host "build/libs contents:" -ForegroundColor Cyan
+ Get-ChildItem -LiteralPath $libsDir |
+ Format-Table Name, @{L="Size(KB)";E={[math]::Round($_.Length/1KB,1)}} -AutoSize |
+ Out-Host
+
+ $mainJar = Get-ChildItem -LiteralPath $libsDir -Filter "*.jar" |
+ Where-Object { $_.Name -notmatch "plain|sources|javadoc" } |
+ Select-Object -First 1
+} else {
+ Write-Host "[WARN] build/libs not found" -ForegroundColor DarkYellow
+}
+Write-Host ""
+
+# ============================================================================
+# [15/16] Run Instructions
+# ============================================================================
+Write-Host "==[15/16] Run Instructions ==" -ForegroundColor Yellow
+Write-Host ""
+
+if ($mainJar) {
+ Write-Host "To run the application:" -ForegroundColor Cyan
+ Write-Host (" java -jar build\libs\" + $mainJar.Name) -ForegroundColor White
+ Write-Host ""
+}
+
+Write-Host "To rebuild:" -ForegroundColor Cyan
+Write-Host ' $env:GRADLE_USER_HOME = ".\\_offline_gradle_home"' -ForegroundColor White
+Write-Host " .\gradlew.bat --offline bootJar --no-daemon" -ForegroundColor White
+Write-Host ""
+
+# ============================================================================
+# [16/16] Complete
+# ============================================================================
+Write-Host "============================================================" -ForegroundColor Green
+Write-Host " Offline Build Complete!" -ForegroundColor Green
+Write-Host "============================================================" -ForegroundColor Green
+Write-Host ""
+Write-Host ("Project: " + $ProjectDir) -ForegroundColor Cyan
+Write-Host ""
diff --git a/kamco-make-dataset-generation/gradle/wrapper/gradle-wrapper.jar b/kamco-make-dataset-generation/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..1b33c55
Binary files /dev/null and b/kamco-make-dataset-generation/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/kamco-make-dataset-generation/gradle/wrapper/gradle-wrapper.properties b/kamco-make-dataset-generation/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..d4081da
--- /dev/null
+++ b/kamco-make-dataset-generation/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,7 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/kamco-make-dataset-generation/gradlew b/kamco-make-dataset-generation/gradlew
new file mode 100755
index 0000000..23d15a9
--- /dev/null
+++ b/kamco-make-dataset-generation/gradlew
@@ -0,0 +1,251 @@
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+##############################################################################
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
+done
+
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+ echo "$*"
+} >&2
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
+esac
+
+CLASSPATH="\\\"\\\""
+
+
+# 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
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
+ fi
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
+ done
+fi
+
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command:
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# and any embedded shellness will be escaped.
+# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+# treated as '${Hostname}' itself on the command line.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/kamco-make-dataset-generation/gradlew.bat b/kamco-make-dataset-generation/gradlew.bat
new file mode 100644
index 0000000..5eed7ee
--- /dev/null
+++ b/kamco-make-dataset-generation/gradlew.bat
@@ -0,0 +1,94 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
+
+@if "%DEBUG%"=="" @echo off
+@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=.
+@rem This is normally unused
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if %ERRORLEVEL% equ 0 goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/GeoJsonSchedulerApplication.class b/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/GeoJsonSchedulerApplication.class
new file mode 100644
index 0000000..831247e
Binary files /dev/null and b/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/GeoJsonSchedulerApplication.class differ
diff --git a/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/batch/ExportGeoJsonJobConfig.class b/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/batch/ExportGeoJsonJobConfig.class
new file mode 100644
index 0000000..35064af
Binary files /dev/null and b/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/batch/ExportGeoJsonJobConfig.class differ
diff --git a/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/batch/ExportGeoJsonTasklet.class b/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/batch/ExportGeoJsonTasklet.class
new file mode 100644
index 0000000..2f7d141
Binary files /dev/null and b/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/batch/ExportGeoJsonTasklet.class differ
diff --git a/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$AnalCntInfo.class b/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$AnalCntInfo.class
new file mode 100644
index 0000000..19e26d0
Binary files /dev/null and b/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$AnalCntInfo.class differ
diff --git a/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$AnalMapSheetList$AnalMapSheetListBuilder.class b/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$AnalMapSheetList$AnalMapSheetListBuilder.class
new file mode 100644
index 0000000..344c86c
Binary files /dev/null and b/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$AnalMapSheetList$AnalMapSheetListBuilder.class differ
diff --git a/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$AnalMapSheetList.class b/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$AnalMapSheetList.class
new file mode 100644
index 0000000..ae8c356
Binary files /dev/null and b/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$AnalMapSheetList.class differ
diff --git a/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$CompleteLabelData$GeoJsonFeature.class b/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$CompleteLabelData$GeoJsonFeature.class
new file mode 100644
index 0000000..d012de1
Binary files /dev/null and b/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$CompleteLabelData$GeoJsonFeature.class differ
diff --git a/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$CompleteLabelData$Properties.class b/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$CompleteLabelData$Properties.class
new file mode 100644
index 0000000..96a321c
Binary files /dev/null and b/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$CompleteLabelData$Properties.class differ
diff --git a/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$CompleteLabelData.class b/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$CompleteLabelData.class
new file mode 100644
index 0000000..2a14cda
Binary files /dev/null and b/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$CompleteLabelData.class differ
diff --git a/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$FeatureCollection.class b/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$FeatureCollection.class
new file mode 100644
index 0000000..7be65c6
Binary files /dev/null and b/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto$FeatureCollection.class differ
diff --git a/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto.class b/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto.class
new file mode 100644
index 0000000..5efc3b4
Binary files /dev/null and b/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto.class differ
diff --git a/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/enums/InspectState.class b/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/enums/InspectState.class
new file mode 100644
index 0000000..09ec616
Binary files /dev/null and b/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/enums/InspectState.class differ
diff --git a/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/enums/LabelMngState.class b/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/enums/LabelMngState.class
new file mode 100644
index 0000000..d12e2f1
Binary files /dev/null and b/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/enums/LabelMngState.class differ
diff --git a/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/repository/TrainingDataReviewJobRepository.class b/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/repository/TrainingDataReviewJobRepository.class
new file mode 100644
index 0000000..868b8b8
Binary files /dev/null and b/kamco-make-dataset-generation/out/production/classes/com/kamco/cd/geojsonscheduler/repository/TrainingDataReviewJobRepository.class differ
diff --git a/kamco-make-dataset-generation/out/production/resources/application-dev.yml b/kamco-make-dataset-generation/out/production/resources/application-dev.yml
new file mode 100644
index 0000000..544f864
--- /dev/null
+++ b/kamco-make-dataset-generation/out/production/resources/application-dev.yml
@@ -0,0 +1,11 @@
+spring:
+ datasource:
+ url: jdbc:postgresql://192.168.2.127:15432/kamco_cds
+ username: kamco_cds
+ password: kamco_cds_Q!W@E#R$
+ hikari:
+ minimum-idle: 2
+ maximum-pool-size: 5
+
+training-data:
+ geojson-dir: /kamco-nfs/model_output/labeling/
diff --git a/kamco-make-dataset-generation/out/production/resources/application-local.yml b/kamco-make-dataset-generation/out/production/resources/application-local.yml
new file mode 100644
index 0000000..7cc0acf
--- /dev/null
+++ b/kamco-make-dataset-generation/out/production/resources/application-local.yml
@@ -0,0 +1,8 @@
+spring:
+ datasource:
+ url: jdbc:postgresql://localhost:5432/kamco_cds
+ username: kamco_cds
+ password: kamco_cds
+
+training-data:
+ geojson-dir: /tmp/geojson
diff --git a/kamco-make-dataset-generation/out/production/resources/application-prod.yml b/kamco-make-dataset-generation/out/production/resources/application-prod.yml
new file mode 100644
index 0000000..d57a835
--- /dev/null
+++ b/kamco-make-dataset-generation/out/production/resources/application-prod.yml
@@ -0,0 +1,11 @@
+spring:
+ datasource:
+ url: jdbc:postgresql://10.100.0.10:25432/temp
+ username: temp
+ password: temp123!
+ hikari:
+ minimum-idle: 2
+ maximum-pool-size: 5
+
+training-data:
+ geojson-dir: /kamco-nfs/model_output/labeling/
diff --git a/kamco-make-dataset-generation/out/production/resources/application.yml b/kamco-make-dataset-generation/out/production/resources/application.yml
new file mode 100644
index 0000000..8693eba
--- /dev/null
+++ b/kamco-make-dataset-generation/out/production/resources/application.yml
@@ -0,0 +1,17 @@
+spring:
+ application:
+ name: kamco-geojson-scheduler
+ profiles:
+ active: local
+ datasource:
+ driver-class-name: org.postgresql.Driver
+ hikari:
+ minimum-idle: 2
+ maximum-pool-size: 2
+ connection-timeout: 20000
+ idle-timeout: 300000
+ max-lifetime: 1800000
+ batch:
+ job:
+ enabled: true
+ initialize-schema: always
\ No newline at end of file
diff --git a/kamco-make-dataset-generation/settings.gradle b/kamco-make-dataset-generation/settings.gradle
new file mode 100644
index 0000000..5d260cf
--- /dev/null
+++ b/kamco-make-dataset-generation/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = 'kamco-geojson-scheduler'
diff --git a/kamco-make-dataset-generation/src/main/java/com/kamco/cd/geojsonscheduler/GeoJsonSchedulerApplication.java b/kamco-make-dataset-generation/src/main/java/com/kamco/cd/geojsonscheduler/GeoJsonSchedulerApplication.java
new file mode 100644
index 0000000..3165867
--- /dev/null
+++ b/kamco-make-dataset-generation/src/main/java/com/kamco/cd/geojsonscheduler/GeoJsonSchedulerApplication.java
@@ -0,0 +1,15 @@
+package com.kamco.cd.geojsonscheduler;
+
+import com.kamco.cd.geojsonscheduler.config.DockerProperties;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+
+@SpringBootApplication
+@EnableConfigurationProperties(DockerProperties.class)
+public class GeoJsonSchedulerApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(GeoJsonSchedulerApplication.class, args);
+ }
+}
\ No newline at end of file
diff --git a/kamco-make-dataset-generation/src/main/java/com/kamco/cd/geojsonscheduler/batch/ExportGeoJsonJobConfig.java b/kamco-make-dataset-generation/src/main/java/com/kamco/cd/geojsonscheduler/batch/ExportGeoJsonJobConfig.java
new file mode 100644
index 0000000..49888f9
--- /dev/null
+++ b/kamco-make-dataset-generation/src/main/java/com/kamco/cd/geojsonscheduler/batch/ExportGeoJsonJobConfig.java
@@ -0,0 +1,32 @@
+package com.kamco.cd.geojsonscheduler.batch;
+
+import lombok.RequiredArgsConstructor;
+import org.springframework.batch.core.Job;
+import org.springframework.batch.core.Step;
+import org.springframework.batch.core.job.builder.JobBuilder;
+import org.springframework.batch.core.repository.JobRepository;
+import org.springframework.batch.core.step.builder.StepBuilder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.transaction.PlatformTransactionManager;
+
+@Configuration
+@RequiredArgsConstructor
+public class ExportGeoJsonJobConfig {
+
+ private final JobRepository jobRepository;
+ private final PlatformTransactionManager transactionManager;
+ private final ExportGeoJsonTasklet exportGeoJsonTasklet;
+
+ @Bean
+ public Job exportGeoJsonJob() {
+ return new JobBuilder("exportGeoJsonJob", jobRepository).start(exportGeoJsonStep()).build();
+ }
+
+ @Bean
+ public Step exportGeoJsonStep() {
+ return new StepBuilder("exportGeoJsonStep", jobRepository)
+ .tasklet(exportGeoJsonTasklet, transactionManager)
+ .build();
+ }
+}
\ No newline at end of file
diff --git a/kamco-make-dataset-generation/src/main/java/com/kamco/cd/geojsonscheduler/batch/ExportGeoJsonTasklet.java b/kamco-make-dataset-generation/src/main/java/com/kamco/cd/geojsonscheduler/batch/ExportGeoJsonTasklet.java
new file mode 100644
index 0000000..4976bd7
--- /dev/null
+++ b/kamco-make-dataset-generation/src/main/java/com/kamco/cd/geojsonscheduler/batch/ExportGeoJsonTasklet.java
@@ -0,0 +1,100 @@
+package com.kamco.cd.geojsonscheduler.batch;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.kamco.cd.geojsonscheduler.dto.TrainingDataReviewJobDto.AnalCntInfo;
+import com.kamco.cd.geojsonscheduler.dto.TrainingDataReviewJobDto.AnalMapSheetList;
+import com.kamco.cd.geojsonscheduler.dto.TrainingDataReviewJobDto.CompleteLabelData;
+import com.kamco.cd.geojsonscheduler.dto.TrainingDataReviewJobDto.CompleteLabelData.GeoJsonFeature;
+import com.kamco.cd.geojsonscheduler.dto.TrainingDataReviewJobDto.FeatureCollection;
+import com.kamco.cd.geojsonscheduler.repository.TrainingDataReviewJobRepository;
+import com.kamco.cd.geojsonscheduler.service.DockerRunnerService;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import java.util.Objects;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.batch.core.StepContribution;
+import org.springframework.batch.core.scope.context.ChunkContext;
+import org.springframework.batch.core.step.tasklet.Tasklet;
+import org.springframework.batch.repeat.RepeatStatus;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+@Log4j2
+@Component
+@RequiredArgsConstructor
+public class ExportGeoJsonTasklet implements Tasklet {
+
+ private final TrainingDataReviewJobRepository repository;
+ private final DockerRunnerService dockerRunnerService;
+
+ @Value("${training-data.geojson-dir}")
+ private String trainingDataDir;
+
+ @Override
+ public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) {
+
+ // 진행중인 회차 중, complete_cnt 가 존재하는 회차 목록 가져오기
+ List analList = repository.findAnalCntInfoList();
+
+ for (AnalCntInfo info : analList) {
+ if (Objects.equals(info.getAllCnt(), info.getFileCnt())) {
+ continue;
+ }
+
+ String resultUid = info.getResultUid();
+ // 어제까지 검수 완료된 총 데이터의 도엽별 목록 가져오기
+ List analMapList = repository.findCompletedAnalMapSheetList(info.getAnalUid());
+
+ //TODO 도엽이 4개이상 존재할때 만 RUN 하기
+ if (analMapList.isEmpty()) {
+ continue;
+ }
+
+ boolean anyProcessed = false;
+
+ for (AnalMapSheetList mapSheet : analMapList) {
+ //도엽별 geom 데이터 가지고 와서 geojson 만들기
+ List completeList =
+ repository.findCompletedYesterdayLabelingList(
+ info.getAnalUid(), mapSheet.getMapSheetNum());
+
+ if (!completeList.isEmpty()) {
+ List geoUids = completeList.stream().map(CompleteLabelData::getGeoUid).toList();
+
+ List features = completeList.stream().map(GeoJsonFeature::from).toList();
+
+ FeatureCollection collection = new FeatureCollection(features);
+ String filename = mapSheet.buildFilename(resultUid);
+
+ // 형식 /kamco-nfs/dataset/request/uuid/filename
+ Path outputPath = Paths.get(trainingDataDir + File.separator + "request" + File.separator + resultUid, filename);
+
+ try {
+ Files.createDirectories(outputPath.getParent());
+
+ ObjectMapper objectMapper = new ObjectMapper();
+ objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
+ objectMapper.writeValue(outputPath.toFile(), collection);
+
+ repository.updateLearnDataGeomFileCreateYn(geoUids);
+ anyProcessed = true;
+ } catch (IOException e) {
+ log.error(e.getMessage());
+ }
+ }
+ }
+
+ if (anyProcessed) {
+ dockerRunnerService.run(resultUid);
+ }
+ }
+
+ return RepeatStatus.FINISHED;
+ }
+}
diff --git a/kamco-make-dataset-generation/src/main/java/com/kamco/cd/geojsonscheduler/config/DockerProperties.java b/kamco-make-dataset-generation/src/main/java/com/kamco/cd/geojsonscheduler/config/DockerProperties.java
new file mode 100644
index 0000000..fc834c1
--- /dev/null
+++ b/kamco-make-dataset-generation/src/main/java/com/kamco/cd/geojsonscheduler/config/DockerProperties.java
@@ -0,0 +1,23 @@
+package com.kamco.cd.geojsonscheduler.config;
+
+import java.util.List;
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+@Getter
+@Setter
+@ConfigurationProperties(prefix = "training-data.docker")
+public class DockerProperties {
+
+ private String image;
+ private String user;
+ private String datasetVolume;
+ private String imagesVolume;
+ private String inputRoot;
+ private String outputRoot;
+ private int patchSize;
+ private int overlapPct;
+ private List trainValTestRatio;
+ private double keepEmptyRatio;
+}
diff --git a/kamco-make-dataset-generation/src/main/java/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto.java b/kamco-make-dataset-generation/src/main/java/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto.java
new file mode 100644
index 0000000..8d4698b
--- /dev/null
+++ b/kamco-make-dataset-generation/src/main/java/com/kamco/cd/geojsonscheduler/dto/TrainingDataReviewJobDto.java
@@ -0,0 +1,121 @@
+package com.kamco.cd.geojsonscheduler.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.kamco.cd.geojsonscheduler.dto.TrainingDataReviewJobDto.CompleteLabelData.GeoJsonFeature;
+import java.util.List;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import lombok.Setter;
+
+public class TrainingDataReviewJobDto {
+
+ @Getter
+ @Setter
+ @RequiredArgsConstructor
+ @AllArgsConstructor
+ public static class AnalCntInfo {
+
+ Long analUid;
+ String resultUid;
+ Long allCnt;
+ Long completeCnt;
+ Long fileCnt;
+ }
+
+ @Getter
+ @Builder
+ @AllArgsConstructor
+ public static class AnalMapSheetList {
+
+ private Integer compareYyyy;
+ private Integer targetYyyy;
+ private String mapSheetNum;
+
+ public String buildFilename(String resultUid) {
+ return String.format(
+ "%s_%s_%s_%s_D15.geojson",
+ resultUid.substring(0, 8),
+ compareYyyy,
+ targetYyyy,
+ mapSheetNum);
+ }
+ }
+
+ @Getter
+ @Setter
+ @JsonPropertyOrder({"type", "features"})
+ public static class FeatureCollection {
+
+ private final String type = "FeatureCollection";
+ private List features;
+
+ public FeatureCollection(List features) {
+ this.features = features;
+ }
+ }
+
+ @Getter
+ @Setter
+ @JsonPropertyOrder({"type", "geometry", "properties"})
+ public static class CompleteLabelData {
+
+ private Long geoUid;
+ private String type;
+ @JsonIgnore private String geomStr;
+ private JsonNode geometry;
+ private Properties properties;
+
+ public CompleteLabelData(Long geoUid, String type, String geomStr, Properties properties) {
+ this.geoUid = geoUid;
+ this.type = type;
+ this.geomStr = geomStr;
+ ObjectMapper mapper = new ObjectMapper();
+ JsonNode jsonNode = null;
+ try {
+ if (geomStr != null) {
+ jsonNode = mapper.readTree(this.geomStr);
+ }
+ } catch (JsonProcessingException e) {
+ throw new RuntimeException(e);
+ }
+
+ this.geometry = jsonNode;
+ if (jsonNode != null && jsonNode.isObject()) {
+ ((ObjectNode) jsonNode).remove("crs");
+ }
+
+ this.properties = properties;
+ }
+
+ @Getter
+ @Setter
+ @RequiredArgsConstructor
+ @AllArgsConstructor
+ public static class Properties {
+
+ private String modelId;
+ private String before;
+ private String after;
+ }
+
+ @Getter
+ @AllArgsConstructor
+ public static class GeoJsonFeature {
+
+ private String type;
+ private JsonNode geometry;
+ private Properties properties;
+
+ public static GeoJsonFeature from(CompleteLabelData data) {
+ return new GeoJsonFeature(data.getType(), data.getGeometry(), data.getProperties());
+ }
+ }
+ }
+}
diff --git a/kamco-make-dataset-generation/src/main/java/com/kamco/cd/geojsonscheduler/enums/InspectState.java b/kamco-make-dataset-generation/src/main/java/com/kamco/cd/geojsonscheduler/enums/InspectState.java
new file mode 100644
index 0000000..233903b
--- /dev/null
+++ b/kamco-make-dataset-generation/src/main/java/com/kamco/cd/geojsonscheduler/enums/InspectState.java
@@ -0,0 +1,18 @@
+package com.kamco.cd.geojsonscheduler.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public enum InspectState {
+ UNCONFIRM("미확인"),
+ EXCEPT("제외"),
+ COMPLETE("완료");
+
+ private final String desc;
+
+ public String getId() {
+ return name();
+ }
+}
diff --git a/kamco-make-dataset-generation/src/main/java/com/kamco/cd/geojsonscheduler/enums/LabelMngState.java b/kamco-make-dataset-generation/src/main/java/com/kamco/cd/geojsonscheduler/enums/LabelMngState.java
new file mode 100644
index 0000000..e211fcf
--- /dev/null
+++ b/kamco-make-dataset-generation/src/main/java/com/kamco/cd/geojsonscheduler/enums/LabelMngState.java
@@ -0,0 +1,19 @@
+package com.kamco.cd.geojsonscheduler.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public enum LabelMngState {
+ PENDING("작업대기"),
+ ASSIGNED("작업할당"),
+ ING("진행중"),
+ FINISH("종료");
+
+ private final String desc;
+
+ public String getId() {
+ return name();
+ }
+}
diff --git a/kamco-make-dataset-generation/src/main/java/com/kamco/cd/geojsonscheduler/repository/TrainingDataReviewJobRepository.java b/kamco-make-dataset-generation/src/main/java/com/kamco/cd/geojsonscheduler/repository/TrainingDataReviewJobRepository.java
new file mode 100644
index 0000000..bb80e86
--- /dev/null
+++ b/kamco-make-dataset-generation/src/main/java/com/kamco/cd/geojsonscheduler/repository/TrainingDataReviewJobRepository.java
@@ -0,0 +1,127 @@
+package com.kamco.cd.geojsonscheduler.repository;
+
+import com.kamco.cd.geojsonscheduler.dto.TrainingDataReviewJobDto.AnalCntInfo;
+import com.kamco.cd.geojsonscheduler.dto.TrainingDataReviewJobDto.AnalMapSheetList;
+import com.kamco.cd.geojsonscheduler.dto.TrainingDataReviewJobDto.CompleteLabelData;
+import com.kamco.cd.geojsonscheduler.dto.TrainingDataReviewJobDto.CompleteLabelData.Properties;
+import java.sql.Timestamp;
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.util.List;
+import java.util.stream.Collectors;
+import lombok.RequiredArgsConstructor;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Repository;
+
+@Repository
+@RequiredArgsConstructor
+public class TrainingDataReviewJobRepository {
+
+ private final JdbcTemplate jdbcTemplate;
+
+ public List findAnalCntInfoList() {
+ String sql =
+ """
+ SELECT
+ la.anal_uid,
+ msl.uid AS result_uid,
+ SUM(CASE WHEN la.inspect_state IN ('UNCONFIRM', 'COMPLETE') OR la.inspect_state IS NULL THEN 1 ELSE 0 END) AS all_cnt,
+ SUM(CASE WHEN la.inspect_state = 'COMPLETE' THEN 1 ELSE 0 END) AS complete_cnt,
+ SUM(CASE WHEN mslg.file_create_yn = true THEN 1 ELSE 0 END) AS file_cnt
+ FROM tb_labeling_assignment la
+ INNER JOIN tb_map_sheet_anal_inference msai ON la.anal_uid = msai.anal_uid AND msai.anal_state = 'ING'
+ LEFT JOIN tb_map_sheet_learn msl ON msai.learn_id = msl.id
+ LEFT JOIN tb_map_sheet_learn_data_geom mslg ON la.inference_geom_uid = mslg.geo_uid
+ GROUP BY la.anal_uid, msl.uid
+ HAVING SUM(CASE WHEN la.inspect_state = 'COMPLETE' THEN 1 ELSE 0 END) > 0
+ """;
+ return jdbcTemplate.query(
+ sql,
+ (rs, rowNum) ->
+ new AnalCntInfo(
+ rs.getLong("anal_uid"),
+ rs.getString("result_uid"),
+ rs.getLong("all_cnt"),
+ rs.getLong("complete_cnt"),
+ rs.getLong("file_cnt")));
+ }
+
+ public List findCompletedAnalMapSheetList(Long analUid) {
+ ZonedDateTime end =
+ LocalDate.now(ZoneId.of("Asia/Seoul")).atStartOfDay(ZoneId.of("Asia/Seoul"));
+ String sql =
+ """
+ SELECT
+ msai.compare_yyyy,
+ msai.target_yyyy,
+ la.assign_group_id
+ FROM tb_labeling_assignment la
+ INNER JOIN tb_map_sheet_anal_inference msai ON la.anal_uid = msai.anal_uid
+ WHERE la.anal_uid = ?
+ AND la.inspect_state = 'COMPLETE'
+ AND la.inspect_stat_dttm < ?
+ GROUP BY msai.compare_yyyy, msai.target_yyyy, la.assign_group_id
+ """;
+ return jdbcTemplate.query(
+ sql,
+ (rs, rowNum) ->
+ AnalMapSheetList.builder()
+ .compareYyyy(rs.getInt("compare_yyyy"))
+ .targetYyyy(rs.getInt("target_yyyy"))
+ .mapSheetNum(rs.getString("assign_group_id"))
+ .build(),
+ analUid,
+ Timestamp.from(end.toInstant()));
+ }
+
+ public List findCompletedYesterdayLabelingList(
+ Long analUid, String mapSheetNum) {
+ ZonedDateTime end =
+ LocalDate.now(ZoneId.of("Asia/Seoul")).atStartOfDay(ZoneId.of("Asia/Seoul"));
+ String sql =
+ """
+ SELECT
+ mslg.geo_uid,
+ 'Feature' AS type,
+ ST_AsGeoJSON(mslg.geom) AS geom_str,
+ CASE
+ WHEN mslg.class_after_cd IN ('building', 'container') THEN 'M1'
+ WHEN mslg.class_after_cd = 'waste' THEN 'M2'
+ ELSE 'M3'
+ END AS model_id,
+ mslg.class_before_cd,
+ mslg.class_after_cd
+ FROM tb_labeling_assignment la
+ LEFT JOIN tb_map_sheet_learn_data_geom mslg ON la.inference_geom_uid = mslg.geo_uid
+ WHERE la.anal_uid = ?
+ AND la.assign_group_id = ?
+ AND la.inspect_state = 'COMPLETE'
+ AND la.inspect_stat_dttm < ?
+ """;
+ return jdbcTemplate.query(
+ sql,
+ (rs, rowNum) ->
+ new CompleteLabelData(
+ rs.getLong("geo_uid"),
+ rs.getString("type"),
+ rs.getString("geom_str"),
+ new Properties(
+ rs.getString("model_id"),
+ rs.getString("class_before_cd"),
+ rs.getString("class_after_cd"))),
+ analUid,
+ mapSheetNum,
+ Timestamp.from(end.toInstant()));
+ }
+
+ public void updateLearnDataGeomFileCreateYn(List geoUids) {
+ String placeholders = geoUids.stream().map(id -> "?").collect(Collectors.joining(","));
+ String sql =
+ "UPDATE tb_map_sheet_learn_data_geom SET file_create_yn = true, modified_date = NOW()"
+ + " WHERE geo_uid IN ("
+ + placeholders
+ + ")";
+ jdbcTemplate.update(sql, geoUids.toArray());
+ }
+}
\ No newline at end of file
diff --git a/kamco-make-dataset-generation/src/main/java/com/kamco/cd/geojsonscheduler/service/DockerRunnerService.java b/kamco-make-dataset-generation/src/main/java/com/kamco/cd/geojsonscheduler/service/DockerRunnerService.java
new file mode 100644
index 0000000..42e6e47
--- /dev/null
+++ b/kamco-make-dataset-generation/src/main/java/com/kamco/cd/geojsonscheduler/service/DockerRunnerService.java
@@ -0,0 +1,84 @@
+package com.kamco.cd.geojsonscheduler.service;
+
+import com.kamco.cd.geojsonscheduler.config.DockerProperties;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.List;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.stereotype.Service;
+
+@Log4j2
+@Service
+@RequiredArgsConstructor
+public class DockerRunnerService {
+
+ private final DockerProperties dockerProperties;
+
+ public void run(String resultUid) {
+ List command = buildCommand(resultUid);
+ log.info("Running docker command: {}", String.join(" ", command));
+
+ try {
+ ProcessBuilder pb = new ProcessBuilder(command);
+ pb.redirectErrorStream(true);
+ Process process = pb.start();
+
+ try (BufferedReader reader =
+ new BufferedReader(new InputStreamReader(process.getInputStream()))) {
+ String line;
+ while ((line = reader.readLine()) != null) {
+ log.info("[docker] {}", line);
+ }
+ }
+
+ int exitCode = process.waitFor();
+ if (exitCode != 0) {
+ log.error("Docker process exited with code {} for resultUid: {}", exitCode, resultUid);
+ } else {
+ log.info("Docker process completed successfully for resultUid: {}", resultUid);
+ }
+ } catch (IOException e) {
+ log.error("Failed to run docker command for resultUid {}: {}", resultUid, e.getMessage());
+ } catch (InterruptedException e) {
+ log.error("Docker process interrupted for resultUid {}: {}", resultUid, e.getMessage());
+ Thread.currentThread().interrupt();
+ }
+ }
+
+ private List buildCommand(String resultUid) {
+ List cmd = new ArrayList<>();
+ cmd.add("docker");
+ cmd.add("run");
+ cmd.add("--rm");
+ cmd.add("--user");
+ cmd.add(dockerProperties.getUser());
+ cmd.add("-v");
+ cmd.add(dockerProperties.getDatasetVolume());
+ cmd.add("-v");
+ cmd.add(dockerProperties.getImagesVolume());
+ cmd.add("--entrypoint");
+ cmd.add("python");
+ cmd.add(dockerProperties.getImage());
+ cmd.add("code/kamco_full_pipeline.py");
+ cmd.add("--labelling-folder");
+ cmd.add("request/" + resultUid);
+ cmd.add("--output-folder");
+ cmd.add("response/" + resultUid);
+ cmd.add("--input_root");
+ cmd.add(dockerProperties.getInputRoot());
+ cmd.add("--output_root");
+ cmd.add(dockerProperties.getOutputRoot());
+ cmd.add("--patch_size");
+ cmd.add(String.valueOf(dockerProperties.getPatchSize()));
+ cmd.add("--overlap_pct");
+ cmd.add(String.valueOf(dockerProperties.getOverlapPct()));
+ cmd.add("--train_val_test_ratio");
+ cmd.addAll(dockerProperties.getTrainValTestRatio());
+ cmd.add("--keep_empty_ratio");
+ cmd.add(String.valueOf(dockerProperties.getKeepEmptyRatio()));
+ return cmd;
+ }
+}
diff --git a/kamco-make-dataset-generation/src/main/resources/application-dev.yml b/kamco-make-dataset-generation/src/main/resources/application-dev.yml
new file mode 100644
index 0000000..9f7f5ea
--- /dev/null
+++ b/kamco-make-dataset-generation/src/main/resources/application-dev.yml
@@ -0,0 +1,11 @@
+spring:
+ datasource:
+ url: jdbc:postgresql://192.168.2.127:15432/kamco_cds
+ username: kamco_cds
+ password: kamco_cds_Q!W@E#R$
+ hikari:
+ minimum-idle: 2
+ maximum-pool-size: 5
+
+training-data:
+ geojson-dir: /kamco-nfs/dataset
diff --git a/kamco-make-dataset-generation/src/main/resources/application-local.yml b/kamco-make-dataset-generation/src/main/resources/application-local.yml
new file mode 100644
index 0000000..7cc0acf
--- /dev/null
+++ b/kamco-make-dataset-generation/src/main/resources/application-local.yml
@@ -0,0 +1,8 @@
+spring:
+ datasource:
+ url: jdbc:postgresql://localhost:5432/kamco_cds
+ username: kamco_cds
+ password: kamco_cds
+
+training-data:
+ geojson-dir: /tmp/geojson
diff --git a/kamco-make-dataset-generation/src/main/resources/application-prod.yml b/kamco-make-dataset-generation/src/main/resources/application-prod.yml
new file mode 100644
index 0000000..707a18c
--- /dev/null
+++ b/kamco-make-dataset-generation/src/main/resources/application-prod.yml
@@ -0,0 +1,11 @@
+spring:
+ datasource:
+ url: jdbc:postgresql://127.0.0.1:15432/kamco_cds
+ username: kamco_cds
+ password: kamco_cds_Q!W@E#R$
+ hikari:
+ minimum-idle: 2
+ maximum-pool-size: 5
+
+training-data:
+ geojson-dir: /kamco-nfs/dataset
diff --git a/kamco-make-dataset-generation/src/main/resources/application.yml b/kamco-make-dataset-generation/src/main/resources/application.yml
new file mode 100644
index 0000000..c1f830a
--- /dev/null
+++ b/kamco-make-dataset-generation/src/main/resources/application.yml
@@ -0,0 +1,33 @@
+spring:
+ application:
+ name: kamco-geojson-scheduler
+ profiles:
+ active: local
+ datasource:
+ driver-class-name: org.postgresql.Driver
+ hikari:
+ minimum-idle: 2
+ maximum-pool-size: 2
+ connection-timeout: 20000
+ idle-timeout: 300000
+ max-lifetime: 1800000
+ batch:
+ job:
+ enabled: true
+ initialize-schema: never
+
+training-data:
+ docker:
+ image: kamco-cd-dataset:latest
+ user: "1000:1000"
+ dataset-volume: /kamco-nfs/dataset:/dataset
+ images-volume: /kamco-nfs/images:/kamco-nfs:ro
+ input-root: /dataset
+ output-root: /dataset
+ patch-size: 512
+ overlap-pct: 50
+ train-val-test-ratio:
+ - "0.7"
+ - "0.2"
+ - "0.1"
+ keep-empty-ratio: 0.1
\ No newline at end of file