commit b8c8ff98e221b9b7458c3fb675fa922d3ffc7d26 Author: Hellings Date: Fri Oct 16 09:05:56 2026 -0400 Hi diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..d9b92d6 --- /dev/null +++ b/.classpath @@ -0,0 +1,6 @@ + + + + + + diff --git a/.claude/skills/tessl__neumorphism b/.claude/skills/tessl__neumorphism new file mode 120000 index 0000000..55b2c18 --- /dev/null +++ b/.claude/skills/tessl__neumorphism @@ -0,0 +1 @@ +../../.tessl/plugins/bergside/awesome-design-skills/skills/neumorphism \ No newline at end of file diff --git a/.codex/config.toml b/.codex/config.toml new file mode 100644 index 0000000..4334324 --- /dev/null +++ b/.codex/config.toml @@ -0,0 +1,4 @@ +[mcp_servers.tessl] +type = "stdio" +command = "tessl" +args = [ "mcp", "start" ] diff --git a/.codex/skills/tessl__neumorphism b/.codex/skills/tessl__neumorphism new file mode 120000 index 0000000..55b2c18 --- /dev/null +++ b/.codex/skills/tessl__neumorphism @@ -0,0 +1 @@ +../../.tessl/plugins/bergside/awesome-design-skills/skills/neumorphism \ No newline at end of file diff --git a/.gemini/settings.json b/.gemini/settings.json new file mode 100644 index 0000000..c4fc42b --- /dev/null +++ b/.gemini/settings.json @@ -0,0 +1,9 @@ +{ + "mcpServers": { + "tessl": { + "type": "stdio", + "command": "tessl", + "args": ["mcp", "start"] + } + } +} diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..f91f646 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,12 @@ +# +# https://help.github.com/articles/dealing-with-line-endings/ +# +# Linux start script should use lf +/gradlew text eol=lf + +# These are Windows script files and should use crlf +*.bat text eol=crlf + +# Binary files should be left untouched +*.jar binary + diff --git a/.github/mcp.json b/.github/mcp.json new file mode 100644 index 0000000..c4fc42b --- /dev/null +++ b/.github/mcp.json @@ -0,0 +1,9 @@ +{ + "mcpServers": { + "tessl": { + "type": "stdio", + "command": "tessl", + "args": ["mcp", "start"] + } + } +} diff --git a/.github/skills/tessl__neumorphism b/.github/skills/tessl__neumorphism new file mode 120000 index 0000000..55b2c18 --- /dev/null +++ b/.github/skills/tessl__neumorphism @@ -0,0 +1 @@ +../../.tessl/plugins/bergside/awesome-design-skills/skills/neumorphism \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3e69143 --- /dev/null +++ b/.gitignore @@ -0,0 +1,67 @@ +# dependencies (bun install) +node_modules + +# output +out +dist +*.tgz + +# code coverage +coverage +*.lcov + +# logs +logs +_.log +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# caches +.eslintcache +.cache +*.tsbuildinfo + +# IntelliJ based IDEs +.idea + +# Finder (MacOS) folder config +.DS_Store + +# Ignore Gradle project-specific cache directory +.gradle +.venv-translator/ +.argos-data/ +.argos-packages/ +.argos-config/ +.argos-cache/ +.venv-krita-build/ +adbme/.dart_tool/ +adbme/build/ + +# Ignore Gradle build output directory +build + +# Ignore Kotlin plugin data +.kotlin + + +temp/ +third_party/onyx-maven/**/*.aar +third_party/nnote/*.apk + +outputs/ +inputs/ +notable/native/ocr/target + +.agents/ +skills-lock.json + +notable/models/ + +translator/__pycache__/ \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..511c76b --- /dev/null +++ b/.gitmodules @@ -0,0 +1,22 @@ +[submodule "apk_unpack"] + path = apk_unpack + url = https://github.com/puntorigen/apk_unpack + +[submodule "krita"] + path = krita + url = https://invent.kde.org/graphics/krita.git +[submodule "third_party/krita-deps-management"] + path = third_party/krita-deps-management + url = https://invent.kde.org/packaging/krita-deps-management.git +[submodule "third_party/krita-ci-utilities"] + path = third_party/krita-ci-utilities + url = https://invent.kde.org/packaging/krita-ci-utilities.git +[submodule "third_party/kde-ci-utilities"] + path = third_party/kde-ci-utilities + url = https://invent.kde.org/sysadmin/ci-utilities.git +[submodule "third_party/ci-notary-service"] + path = third_party/ci-notary-service + url = https://invent.kde.org/sysadmin/ci-notary-service.git +[submodule "third_party/enote-sdk"] + path = third_party/enote-sdk + url = https://github.com/webpad/eNote-SDK.git diff --git a/.gradle-user/.tmp/gradle-worker-classpath1338154394125014853txt b/.gradle-user/.tmp/gradle-worker-classpath1338154394125014853txt new file mode 100644 index 0000000..3711b22 --- /dev/null +++ b/.gradle-user/.tmp/gradle-worker-classpath1338154394125014853txt @@ -0,0 +1,2 @@ +-cp +/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/workerMain/gradle-worker.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/plugins/gradle-daemon-server-worker-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-ant-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/plugins/gradle-ant-impl-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-base-services-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-operations-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-process-services-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-classloaders-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-concurrent-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-core-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-core-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-domain-object-collections-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-file-collections-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-file-operations-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-file-temp-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-groovy-loader-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-hashing-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-messaging-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-model-core-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-persistent-cache-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-problems-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-process-services-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-request-handler-worker-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-scoped-persistent-cache-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-serialization-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-service-lookup-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-service-provider-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-service-registry-builder-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-snapshots-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-worker-main-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/guava-33.4.6-jre.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/javax.inject-1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jspecify-1.0.0-no-module-annotation.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/ant-1.10.17.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-ant-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-logging-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-logging-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-stdlib-java-extensions-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-ant-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/slf4j-api-2.0.17.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/commons-io-2.20.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/commons-lang3-3.20.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-base-asm-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-declarative-dsl-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-time-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jsr305-3.0.2.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/fastutil-8.5.2-min.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-io-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jctools-core-4.0.5.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/asm-9.9.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/asm-tree-9.9.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/commons-compress-1.28.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/error_prone_annotations-2.50.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-base-services-groovy-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-cache-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-cache-base-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-cache-core-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-cache-packaging-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-cache-spi-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-discovery-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-discovery-impl-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-discovery-reporting-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-init-specs-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-operations-trace-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-option-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-classpath-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-cli-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-collections-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-configuration-problems-base-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-core-flow-services-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-credentials-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-daemon-logging-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-daemon-messaging-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-enterprise-logging-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-enterprise-operations-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-execution-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-file-watching-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-files-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-functional-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-hashing-services-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-instrumentation-agent-services-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-instrumentation-reporting-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-internal-instrumentation-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-jvm-services-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-model-groovy-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-model-reflect-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-native-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-normalization-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-normalization-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-normalization-java-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-problems-rendering-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-process-memory-services-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-process-services-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-process-services-base-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-project-features-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-project-features-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-resources-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-start-parameter-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-tooling-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-versioned-cache-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-worker-process-services-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-astbuilder-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-datetime-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-dateutil-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-groovydoc-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-json-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-nio-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-xml-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/tomlj-1.0.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/kotlin-reflect-2.4.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-templates-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/kotlin-stdlib-2.4.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/kryo-2.24.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-service-registry-impl-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/failureaccess-1.0.3.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/ant-launcher-1.10.17.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-enterprise-workers-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-wrapper-shared-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gson-2.13.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jansi-2.4.2.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jcl-over-slf4j-2.0.17.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jul-to-slf4j-2.0.17.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/log4j-over-slf4j-2.0.17.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/ant-antlr-1.10.15.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/commons-codec-1.18.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-cache-local-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-init-specs-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jackson-core-2.22.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jackson-databind-2.22.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jackson-datatype-jdk8-2.22.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jackson-datatype-jsr310-2.22.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/asm-commons-9.9.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-input-tracking-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-stdlib-kotlin-extensions-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-fileevents-0.2.8.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-java-api-extractor-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jnr-constants-0.10.4-min.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-docgenerator-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/javaparser-core-3.27.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-freebsd-amd64-libcpp-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-linux-aarch64-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-linux-aarch64-ncurses5-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-linux-aarch64-ncurses6-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-linux-amd64-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-linux-amd64-ncurses5-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-linux-amd64-ncurses6-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-osx-aarch64-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-osx-amd64-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-windows-aarch64-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-windows-aarch64-min-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-windows-amd64-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-windows-amd64-min-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-windows-i386-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-windows-i386-min-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/antlr4-runtime-4.7.2.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/annotations-24.0.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/minlog-1.2.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/objenesis-2.6.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jackson-annotations-2.22.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/configuration-cache-report-jvm-1.34.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/qdox-1.12.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/plugins/gradle-java-compiler-worker-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/plugins/gradle-jvm-compiler-worker-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/plugins/gradle-base-compiler-worker-9.7.1.jar diff --git a/.gradle-user/.tmp/gradle-worker-classpath4428196616110299768txt b/.gradle-user/.tmp/gradle-worker-classpath4428196616110299768txt new file mode 100644 index 0000000..3711b22 --- /dev/null +++ b/.gradle-user/.tmp/gradle-worker-classpath4428196616110299768txt @@ -0,0 +1,2 @@ +-cp +/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/workerMain/gradle-worker.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/plugins/gradle-daemon-server-worker-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-ant-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/plugins/gradle-ant-impl-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-base-services-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-operations-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-process-services-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-classloaders-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-concurrent-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-core-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-core-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-domain-object-collections-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-file-collections-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-file-operations-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-file-temp-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-groovy-loader-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-hashing-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-messaging-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-model-core-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-persistent-cache-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-problems-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-process-services-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-request-handler-worker-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-scoped-persistent-cache-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-serialization-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-service-lookup-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-service-provider-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-service-registry-builder-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-snapshots-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-worker-main-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/guava-33.4.6-jre.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/javax.inject-1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jspecify-1.0.0-no-module-annotation.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/ant-1.10.17.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-ant-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-logging-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-logging-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-stdlib-java-extensions-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-ant-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/slf4j-api-2.0.17.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/commons-io-2.20.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/commons-lang3-3.20.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-base-asm-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-declarative-dsl-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-time-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jsr305-3.0.2.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/fastutil-8.5.2-min.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-io-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jctools-core-4.0.5.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/asm-9.9.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/asm-tree-9.9.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/commons-compress-1.28.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/error_prone_annotations-2.50.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-base-services-groovy-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-cache-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-cache-base-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-cache-core-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-cache-packaging-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-cache-spi-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-discovery-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-discovery-impl-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-discovery-reporting-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-init-specs-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-operations-trace-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-option-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-classpath-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-cli-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-collections-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-configuration-problems-base-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-core-flow-services-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-credentials-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-daemon-logging-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-daemon-messaging-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-enterprise-logging-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-enterprise-operations-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-execution-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-file-watching-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-files-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-functional-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-hashing-services-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-instrumentation-agent-services-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-instrumentation-reporting-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-internal-instrumentation-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-jvm-services-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-model-groovy-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-model-reflect-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-native-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-normalization-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-normalization-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-normalization-java-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-problems-rendering-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-process-memory-services-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-process-services-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-process-services-base-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-project-features-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-project-features-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-resources-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-start-parameter-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-tooling-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-versioned-cache-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-worker-process-services-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-astbuilder-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-datetime-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-dateutil-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-groovydoc-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-json-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-nio-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-xml-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/tomlj-1.0.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/kotlin-reflect-2.4.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-templates-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/kotlin-stdlib-2.4.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/kryo-2.24.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-service-registry-impl-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/failureaccess-1.0.3.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/ant-launcher-1.10.17.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-enterprise-workers-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-wrapper-shared-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gson-2.13.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jansi-2.4.2.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jcl-over-slf4j-2.0.17.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jul-to-slf4j-2.0.17.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/log4j-over-slf4j-2.0.17.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/ant-antlr-1.10.15.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/commons-codec-1.18.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-cache-local-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-init-specs-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jackson-core-2.22.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jackson-databind-2.22.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jackson-datatype-jdk8-2.22.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jackson-datatype-jsr310-2.22.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/asm-commons-9.9.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-input-tracking-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-stdlib-kotlin-extensions-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-fileevents-0.2.8.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-java-api-extractor-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jnr-constants-0.10.4-min.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-docgenerator-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/javaparser-core-3.27.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-freebsd-amd64-libcpp-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-linux-aarch64-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-linux-aarch64-ncurses5-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-linux-aarch64-ncurses6-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-linux-amd64-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-linux-amd64-ncurses5-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-linux-amd64-ncurses6-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-osx-aarch64-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-osx-amd64-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-windows-aarch64-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-windows-aarch64-min-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-windows-amd64-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-windows-amd64-min-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-windows-i386-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-windows-i386-min-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/antlr4-runtime-4.7.2.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/annotations-24.0.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/minlog-1.2.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/objenesis-2.6.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jackson-annotations-2.22.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/configuration-cache-report-jvm-1.34.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/qdox-1.12.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/plugins/gradle-java-compiler-worker-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/plugins/gradle-jvm-compiler-worker-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/plugins/gradle-base-compiler-worker-9.7.1.jar diff --git a/.gradle-user/.tmp/gradle-worker-classpath773319068940645557txt b/.gradle-user/.tmp/gradle-worker-classpath773319068940645557txt new file mode 100644 index 0000000..3711b22 --- /dev/null +++ b/.gradle-user/.tmp/gradle-worker-classpath773319068940645557txt @@ -0,0 +1,2 @@ +-cp +/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/workerMain/gradle-worker.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/plugins/gradle-daemon-server-worker-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-ant-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/plugins/gradle-ant-impl-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-base-services-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-operations-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-process-services-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-classloaders-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-concurrent-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-core-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-core-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-domain-object-collections-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-file-collections-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-file-operations-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-file-temp-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-groovy-loader-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-hashing-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-messaging-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-model-core-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-persistent-cache-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-problems-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-process-services-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-request-handler-worker-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-scoped-persistent-cache-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-serialization-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-service-lookup-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-service-provider-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-service-registry-builder-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-snapshots-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-worker-main-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/guava-33.4.6-jre.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/javax.inject-1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jspecify-1.0.0-no-module-annotation.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/ant-1.10.17.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-ant-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-logging-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-logging-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-stdlib-java-extensions-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-ant-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/slf4j-api-2.0.17.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/commons-io-2.20.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/commons-lang3-3.20.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-base-asm-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-declarative-dsl-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-time-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jsr305-3.0.2.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/fastutil-8.5.2-min.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-io-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jctools-core-4.0.5.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/asm-9.9.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/asm-tree-9.9.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/commons-compress-1.28.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/error_prone_annotations-2.50.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-base-services-groovy-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-cache-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-cache-base-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-cache-core-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-cache-packaging-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-cache-spi-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-discovery-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-discovery-impl-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-discovery-reporting-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-init-specs-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-operations-trace-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-option-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-classpath-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-cli-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-collections-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-configuration-problems-base-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-core-flow-services-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-credentials-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-daemon-logging-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-daemon-messaging-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-enterprise-logging-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-enterprise-operations-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-execution-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-file-watching-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-files-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-functional-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-hashing-services-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-instrumentation-agent-services-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-instrumentation-reporting-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-internal-instrumentation-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-jvm-services-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-model-groovy-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-model-reflect-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-native-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-normalization-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-normalization-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-normalization-java-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-problems-rendering-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-process-memory-services-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-process-services-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-process-services-base-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-project-features-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-project-features-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-resources-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-start-parameter-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-tooling-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-versioned-cache-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-worker-process-services-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-astbuilder-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-datetime-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-dateutil-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-groovydoc-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-json-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-nio-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-xml-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/tomlj-1.0.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/kotlin-reflect-2.4.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-templates-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/kotlin-stdlib-2.4.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/kryo-2.24.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-service-registry-impl-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/failureaccess-1.0.3.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/ant-launcher-1.10.17.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-enterprise-workers-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-wrapper-shared-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gson-2.13.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jansi-2.4.2.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jcl-over-slf4j-2.0.17.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jul-to-slf4j-2.0.17.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/log4j-over-slf4j-2.0.17.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/ant-antlr-1.10.15.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/commons-codec-1.18.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-cache-local-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-init-specs-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jackson-core-2.22.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jackson-databind-2.22.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jackson-datatype-jdk8-2.22.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jackson-datatype-jsr310-2.22.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/asm-commons-9.9.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-input-tracking-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-stdlib-kotlin-extensions-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-fileevents-0.2.8.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-java-api-extractor-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jnr-constants-0.10.4-min.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-docgenerator-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/javaparser-core-3.27.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-freebsd-amd64-libcpp-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-linux-aarch64-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-linux-aarch64-ncurses5-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-linux-aarch64-ncurses6-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-linux-amd64-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-linux-amd64-ncurses5-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-linux-amd64-ncurses6-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-osx-aarch64-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-osx-amd64-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-windows-aarch64-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-windows-aarch64-min-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-windows-amd64-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-windows-amd64-min-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-windows-i386-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-windows-i386-min-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/antlr4-runtime-4.7.2.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/annotations-24.0.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/minlog-1.2.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/objenesis-2.6.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jackson-annotations-2.22.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/configuration-cache-report-jvm-1.34.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/qdox-1.12.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/plugins/gradle-java-compiler-worker-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/plugins/gradle-jvm-compiler-worker-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/plugins/gradle-base-compiler-worker-9.7.1.jar diff --git a/.gradle-user/.tmp/gradle-worker-classpath964243666310285974txt b/.gradle-user/.tmp/gradle-worker-classpath964243666310285974txt new file mode 100644 index 0000000..3711b22 --- /dev/null +++ b/.gradle-user/.tmp/gradle-worker-classpath964243666310285974txt @@ -0,0 +1,2 @@ +-cp +/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/workerMain/gradle-worker.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/plugins/gradle-daemon-server-worker-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-ant-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/plugins/gradle-ant-impl-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-base-services-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-operations-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-process-services-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-classloaders-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-concurrent-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-core-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-core-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-domain-object-collections-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-file-collections-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-file-operations-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-file-temp-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-groovy-loader-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-hashing-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-messaging-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-model-core-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-persistent-cache-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-problems-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-process-services-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-request-handler-worker-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-scoped-persistent-cache-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-serialization-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-service-lookup-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-service-provider-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-service-registry-builder-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-snapshots-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-worker-main-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/guava-33.4.6-jre.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/javax.inject-1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jspecify-1.0.0-no-module-annotation.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/ant-1.10.17.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-ant-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-logging-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-logging-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-stdlib-java-extensions-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-ant-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/slf4j-api-2.0.17.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/commons-io-2.20.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/commons-lang3-3.20.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-base-asm-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-declarative-dsl-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-time-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jsr305-3.0.2.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/fastutil-8.5.2-min.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-io-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jctools-core-4.0.5.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/asm-9.9.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/asm-tree-9.9.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/commons-compress-1.28.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/error_prone_annotations-2.50.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-base-services-groovy-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-cache-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-cache-base-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-cache-core-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-cache-packaging-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-cache-spi-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-discovery-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-discovery-impl-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-discovery-reporting-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-init-specs-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-operations-trace-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-option-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-classpath-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-cli-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-collections-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-configuration-problems-base-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-core-flow-services-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-credentials-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-daemon-logging-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-daemon-messaging-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-enterprise-logging-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-enterprise-operations-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-execution-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-file-watching-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-files-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-functional-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-hashing-services-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-instrumentation-agent-services-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-instrumentation-reporting-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-internal-instrumentation-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-jvm-services-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-model-groovy-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-model-reflect-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-native-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-normalization-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-normalization-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-normalization-java-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-problems-rendering-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-process-memory-services-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-process-services-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-process-services-base-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-project-features-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-project-features-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-resources-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-start-parameter-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-tooling-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-versioned-cache-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-worker-process-services-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-astbuilder-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-datetime-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-dateutil-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-groovydoc-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-json-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-nio-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-xml-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/tomlj-1.0.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/kotlin-reflect-2.4.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-templates-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/kotlin-stdlib-2.4.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/kryo-2.24.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-service-registry-impl-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/failureaccess-1.0.3.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/ant-launcher-1.10.17.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-enterprise-workers-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-wrapper-shared-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gson-2.13.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jansi-2.4.2.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jcl-over-slf4j-2.0.17.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jul-to-slf4j-2.0.17.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/log4j-over-slf4j-2.0.17.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/ant-antlr-1.10.15.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/commons-codec-1.18.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-cache-local-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-build-init-specs-api-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jackson-core-2.22.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jackson-databind-2.22.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jackson-datatype-jdk8-2.22.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jackson-datatype-jsr310-2.22.0.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/asm-commons-9.9.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-input-tracking-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-stdlib-kotlin-extensions-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-fileevents-0.2.8.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/gradle-java-api-extractor-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jnr-constants-0.10.4-min.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/groovy-docgenerator-4.0.32.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/javaparser-core-3.27.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-freebsd-amd64-libcpp-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-linux-aarch64-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-linux-aarch64-ncurses5-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-linux-aarch64-ncurses6-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-linux-amd64-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-linux-amd64-ncurses5-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-linux-amd64-ncurses6-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-osx-aarch64-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-osx-amd64-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-windows-aarch64-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-windows-aarch64-min-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-windows-amd64-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-windows-amd64-min-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-windows-i386-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/native-platform-windows-i386-min-0.22-milestone-29.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/antlr4-runtime-4.7.2.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/annotations-24.0.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/minlog-1.2.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/objenesis-2.6.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/jackson-annotations-2.22.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/configuration-cache-report-jvm-1.34.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/qdox-1.12.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/plugins/gradle-java-compiler-worker-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/plugins/gradle-jvm-compiler-worker-9.7.1.jar:/var/home/hellings/.sdkman/candidates/gradle/9.7.1/lib/plugins/gradle-base-compiler-worker-9.7.1.jar diff --git a/.gradle-user/caches/9.7.1/cc-keystore/cache.properties b/.gradle-user/caches/9.7.1/cc-keystore/cache.properties new file mode 100644 index 0000000..6a7befd --- /dev/null +++ b/.gradle-user/caches/9.7.1/cc-keystore/cache.properties @@ -0,0 +1 @@ +#Fri Oct 16 08:22:42 EDT 2026 diff --git a/.gradle-user/caches/9.7.1/cc-keystore/cc-keystore.lock b/.gradle-user/caches/9.7.1/cc-keystore/cc-keystore.lock new file mode 100644 index 0000000..998f703 Binary files /dev/null and b/.gradle-user/caches/9.7.1/cc-keystore/cc-keystore.lock differ diff --git a/.gradle-user/caches/9.7.1/cc-keystore/gradle.keystore b/.gradle-user/caches/9.7.1/cc-keystore/gradle.keystore new file mode 100644 index 0000000..432ba85 Binary files /dev/null and b/.gradle-user/caches/9.7.1/cc-keystore/gradle.keystore differ diff --git a/.gradle-user/caches/9.7.1/file-changes/last-build.bin b/.gradle-user/caches/9.7.1/file-changes/last-build.bin new file mode 100644 index 0000000..f76dd23 Binary files /dev/null and b/.gradle-user/caches/9.7.1/file-changes/last-build.bin differ diff --git a/.gradle-user/caches/9.7.1/fileContent/fileContent.lock b/.gradle-user/caches/9.7.1/fileContent/fileContent.lock new file mode 100644 index 0000000..b31f6a1 Binary files /dev/null and b/.gradle-user/caches/9.7.1/fileContent/fileContent.lock differ diff --git a/.gradle-user/caches/9.7.1/fileHashes/fileHashes.bin b/.gradle-user/caches/9.7.1/fileHashes/fileHashes.bin new file mode 100644 index 0000000..4024301 Binary files /dev/null and b/.gradle-user/caches/9.7.1/fileHashes/fileHashes.bin differ diff --git a/.gradle-user/caches/9.7.1/fileHashes/fileHashes.lock b/.gradle-user/caches/9.7.1/fileHashes/fileHashes.lock new file mode 100644 index 0000000..b80ab59 Binary files /dev/null and b/.gradle-user/caches/9.7.1/fileHashes/fileHashes.lock differ diff --git a/.gradle-user/caches/9.7.1/fileHashes/resourceHashesCache.bin b/.gradle-user/caches/9.7.1/fileHashes/resourceHashesCache.bin new file mode 100644 index 0000000..7bece8a Binary files /dev/null and b/.gradle-user/caches/9.7.1/fileHashes/resourceHashesCache.bin differ diff --git a/.gradle-user/caches/9.7.1/gc.properties b/.gradle-user/caches/9.7.1/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/groovy-dsl/.internal/gc.properties b/.gradle-user/caches/9.7.1/groovy-dsl/.internal/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/groovy-dsl/.internal/locks/011199cb3cde9595aee06f887b6b624d.lock b/.gradle-user/caches/9.7.1/groovy-dsl/.internal/locks/011199cb3cde9595aee06f887b6b624d.lock new file mode 100644 index 0000000..369aa21 Binary files /dev/null and b/.gradle-user/caches/9.7.1/groovy-dsl/.internal/locks/011199cb3cde9595aee06f887b6b624d.lock differ diff --git a/.gradle-user/caches/9.7.1/groovy-dsl/.internal/locks/06c136c9096d15898da12ee97fbb028b.lock b/.gradle-user/caches/9.7.1/groovy-dsl/.internal/locks/06c136c9096d15898da12ee97fbb028b.lock new file mode 100644 index 0000000..968c155 Binary files /dev/null and b/.gradle-user/caches/9.7.1/groovy-dsl/.internal/locks/06c136c9096d15898da12ee97fbb028b.lock differ diff --git a/.gradle-user/caches/9.7.1/groovy-dsl/.internal/locks/17943c1a7f86e51a0a2e8027bcf0a784.lock b/.gradle-user/caches/9.7.1/groovy-dsl/.internal/locks/17943c1a7f86e51a0a2e8027bcf0a784.lock new file mode 100644 index 0000000..fa8d50b Binary files /dev/null and b/.gradle-user/caches/9.7.1/groovy-dsl/.internal/locks/17943c1a7f86e51a0a2e8027bcf0a784.lock differ diff --git a/.gradle-user/caches/9.7.1/groovy-dsl/.internal/locks/1ac90e4fa33ea65ccc9f5cc63a291424.lock b/.gradle-user/caches/9.7.1/groovy-dsl/.internal/locks/1ac90e4fa33ea65ccc9f5cc63a291424.lock new file mode 100644 index 0000000..d2f42c2 Binary files /dev/null and b/.gradle-user/caches/9.7.1/groovy-dsl/.internal/locks/1ac90e4fa33ea65ccc9f5cc63a291424.lock differ diff --git a/.gradle-user/caches/9.7.1/groovy-dsl/.internal/locks/4ebd3a2c2366949192e02f8cd89c2d90.lock b/.gradle-user/caches/9.7.1/groovy-dsl/.internal/locks/4ebd3a2c2366949192e02f8cd89c2d90.lock new file mode 100644 index 0000000..dc4db9b Binary files /dev/null and b/.gradle-user/caches/9.7.1/groovy-dsl/.internal/locks/4ebd3a2c2366949192e02f8cd89c2d90.lock differ diff --git a/.gradle-user/caches/9.7.1/groovy-dsl/.internal/locks/4fadb9dd55c896578097b0cbb1e10ca8.lock b/.gradle-user/caches/9.7.1/groovy-dsl/.internal/locks/4fadb9dd55c896578097b0cbb1e10ca8.lock new file mode 100644 index 0000000..8223ef8 Binary files /dev/null and b/.gradle-user/caches/9.7.1/groovy-dsl/.internal/locks/4fadb9dd55c896578097b0cbb1e10ca8.lock differ diff --git a/.gradle-user/caches/9.7.1/groovy-dsl/.internal/locks/5fd79f05b205ac24e391c54b7dca07c7.lock b/.gradle-user/caches/9.7.1/groovy-dsl/.internal/locks/5fd79f05b205ac24e391c54b7dca07c7.lock new file mode 100644 index 0000000..b15cf81 Binary files /dev/null and b/.gradle-user/caches/9.7.1/groovy-dsl/.internal/locks/5fd79f05b205ac24e391c54b7dca07c7.lock differ diff --git a/.gradle-user/caches/9.7.1/groovy-dsl/.internal/locks/ac98f121412095df4ff127a5d1a24e5b.lock b/.gradle-user/caches/9.7.1/groovy-dsl/.internal/locks/ac98f121412095df4ff127a5d1a24e5b.lock new file mode 100644 index 0000000..bc44872 Binary files /dev/null and b/.gradle-user/caches/9.7.1/groovy-dsl/.internal/locks/ac98f121412095df4ff127a5d1a24e5b.lock differ diff --git a/.gradle-user/caches/9.7.1/groovy-dsl/.internal/locks/c728f949ea6e04121b2fdb317959a107.lock b/.gradle-user/caches/9.7.1/groovy-dsl/.internal/locks/c728f949ea6e04121b2fdb317959a107.lock new file mode 100644 index 0000000..045147f Binary files /dev/null and b/.gradle-user/caches/9.7.1/groovy-dsl/.internal/locks/c728f949ea6e04121b2fdb317959a107.lock differ diff --git a/.gradle-user/caches/9.7.1/groovy-dsl/.internal/locks/ed05cbaadddcf1c5ca1432d729aa7331.lock b/.gradle-user/caches/9.7.1/groovy-dsl/.internal/locks/ed05cbaadddcf1c5ca1432d729aa7331.lock new file mode 100644 index 0000000..1123aa0 Binary files /dev/null and b/.gradle-user/caches/9.7.1/groovy-dsl/.internal/locks/ed05cbaadddcf1c5ca1432d729aa7331.lock differ diff --git a/.gradle-user/caches/9.7.1/groovy-dsl/011199cb3cde9595aee06f887b6b624d/classes/cp_proj/_BuildScript_$_run_closure1.class b/.gradle-user/caches/9.7.1/groovy-dsl/011199cb3cde9595aee06f887b6b624d/classes/cp_proj/_BuildScript_$_run_closure1.class new file mode 100644 index 0000000..14cb7b3 Binary files /dev/null and b/.gradle-user/caches/9.7.1/groovy-dsl/011199cb3cde9595aee06f887b6b624d/classes/cp_proj/_BuildScript_$_run_closure1.class differ diff --git a/.gradle-user/caches/9.7.1/groovy-dsl/011199cb3cde9595aee06f887b6b624d/classes/cp_proj/_BuildScript_.class b/.gradle-user/caches/9.7.1/groovy-dsl/011199cb3cde9595aee06f887b6b624d/classes/cp_proj/_BuildScript_.class new file mode 100644 index 0000000..78aec4a Binary files /dev/null and b/.gradle-user/caches/9.7.1/groovy-dsl/011199cb3cde9595aee06f887b6b624d/classes/cp_proj/_BuildScript_.class differ diff --git a/.gradle-user/caches/9.7.1/groovy-dsl/011199cb3cde9595aee06f887b6b624d/instrumented/cp_proj/_BuildScript_$_run_closure1.class b/.gradle-user/caches/9.7.1/groovy-dsl/011199cb3cde9595aee06f887b6b624d/instrumented/cp_proj/_BuildScript_$_run_closure1.class new file mode 100644 index 0000000..7a58b1c Binary files /dev/null and b/.gradle-user/caches/9.7.1/groovy-dsl/011199cb3cde9595aee06f887b6b624d/instrumented/cp_proj/_BuildScript_$_run_closure1.class differ diff --git a/.gradle-user/caches/9.7.1/groovy-dsl/011199cb3cde9595aee06f887b6b624d/instrumented/cp_proj/_BuildScript_.class b/.gradle-user/caches/9.7.1/groovy-dsl/011199cb3cde9595aee06f887b6b624d/instrumented/cp_proj/_BuildScript_.class new file mode 100644 index 0000000..b7d63da Binary files /dev/null and b/.gradle-user/caches/9.7.1/groovy-dsl/011199cb3cde9595aee06f887b6b624d/instrumented/cp_proj/_BuildScript_.class differ diff --git a/.gradle-user/caches/9.7.1/groovy-dsl/011199cb3cde9595aee06f887b6b624d/metadata.bin b/.gradle-user/caches/9.7.1/groovy-dsl/011199cb3cde9595aee06f887b6b624d/metadata.bin new file mode 100644 index 0000000..a9d0d51 --- /dev/null +++ b/.gradle-user/caches/9.7.1/groovy-dsl/011199cb3cde9595aee06f887b6b624d/metadata.bin @@ -0,0 +1 @@ +›wviskalnfjcajntw2rttlz5qli°øǺÔYï@ºsi­G|>“instrumentedOutput{N {A±ÉZÛÊ]‹¦•ÝŒmetadataDir�)CÇäe9=É*òs@‘ÈœpropertyUpgradeReportOutput²´ÆyàÞœ3Ÿ&þÍË;ŒÕ \ No newline at end of file diff --git a/.gradle-user/caches/9.7.1/groovy-dsl/011199cb3cde9595aee06f887b6b624d/metadata/metadata.bin b/.gradle-user/caches/9.7.1/groovy-dsl/011199cb3cde9595aee06f887b6b624d/metadata/metadata.bin new file mode 100644 index 0000000..f76dd23 Binary files /dev/null and b/.gradle-user/caches/9.7.1/groovy-dsl/011199cb3cde9595aee06f887b6b624d/metadata/metadata.bin differ diff --git a/.gradle-user/caches/9.7.1/groovy-dsl/06c136c9096d15898da12ee97fbb028b/classes/settings/_BuildScript_.class b/.gradle-user/caches/9.7.1/groovy-dsl/06c136c9096d15898da12ee97fbb028b/classes/settings/_BuildScript_.class new file mode 100644 index 0000000..e2564c6 Binary files /dev/null and b/.gradle-user/caches/9.7.1/groovy-dsl/06c136c9096d15898da12ee97fbb028b/classes/settings/_BuildScript_.class differ diff --git a/.gradle-user/caches/9.7.1/groovy-dsl/06c136c9096d15898da12ee97fbb028b/instrumented/settings/_BuildScript_.class b/.gradle-user/caches/9.7.1/groovy-dsl/06c136c9096d15898da12ee97fbb028b/instrumented/settings/_BuildScript_.class new file mode 100644 index 0000000..eee463f Binary files /dev/null and b/.gradle-user/caches/9.7.1/groovy-dsl/06c136c9096d15898da12ee97fbb028b/instrumented/settings/_BuildScript_.class differ diff --git a/.gradle-user/caches/9.7.1/groovy-dsl/06c136c9096d15898da12ee97fbb028b/metadata.bin b/.gradle-user/caches/9.7.1/groovy-dsl/06c136c9096d15898da12ee97fbb028b/metadata.bin new file mode 100644 index 0000000..7fba08a --- /dev/null +++ b/.gradle-user/caches/9.7.1/groovy-dsl/06c136c9096d15898da12ee97fbb028b/metadata.bin @@ -0,0 +1,2 @@ +›wviskalnfjcajntw2rttlz5qli¯ÔI™¦Ký¥Mþ,–…xŠ“instrumentedOutput‡­~âO_ÀÆ©Xè�outputDirectoryaÙür‚Æú{©ðéÀ†Ý7ŒresultsFile`¯õ±Á¬7�×uH…¡¹Ê \ No newline at end of file diff --git a/.gradle-user/caches/9.7.1/transforms/35d21eb65c34dd3a68e19e4a733eca73/results.bin b/.gradle-user/caches/9.7.1/transforms/35d21eb65c34dd3a68e19e4a733eca73/results.bin new file mode 100644 index 0000000..bbe19be --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/35d21eb65c34dd3a68e19e4a733eca73/results.bin @@ -0,0 +1,2 @@ +o/.gradle-instrumented-classpath.marker +o/merge/instrumentation-dependencies.bin diff --git a/.gradle-user/caches/9.7.1/transforms/35d21eb65c34dd3a68e19e4a733eca73/transformed/.gradle-instrumented-classpath.marker b/.gradle-user/caches/9.7.1/transforms/35d21eb65c34dd3a68e19e4a733eca73/transformed/.gradle-instrumented-classpath.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/35d21eb65c34dd3a68e19e4a733eca73/transformed/merge/instrumentation-dependencies.bin b/.gradle-user/caches/9.7.1/transforms/35d21eb65c34dd3a68e19e4a733eca73/transformed/merge/instrumentation-dependencies.bin new file mode 100644 index 0000000..5702661 Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/35d21eb65c34dd3a68e19e4a733eca73/transformed/merge/instrumentation-dependencies.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/37c5d1cbebe692cba083624587a3b9df/metadata.bin b/.gradle-user/caches/9.7.1/transforms/37c5d1cbebe692cba083624587a3b9df/metadata.bin new file mode 100644 index 0000000..fc9e747 Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/37c5d1cbebe692cba083624587a3b9df/metadata.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/37c5d1cbebe692cba083624587a3b9df/results.bin b/.gradle-user/caches/9.7.1/transforms/37c5d1cbebe692cba083624587a3b9df/results.bin new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/389d81dafd8b33ede287200a6806fe33/metadata.bin b/.gradle-user/caches/9.7.1/transforms/389d81dafd8b33ede287200a6806fe33/metadata.bin new file mode 100644 index 0000000..b1b389b --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/389d81dafd8b33ede287200a6806fe33/metadata.bin @@ -0,0 +1 @@ +›wviskalnfjcajntw2rttlz5qliük­:0×&Ðå·™–Ê�Àº�outputDirectory“©Ð5á"D´�ì4²¡áçŒresultsFile`¯õ±Á¬7�×uH…¡¹Ê \ No newline at end of file diff --git a/.gradle-user/caches/9.7.1/transforms/389d81dafd8b33ede287200a6806fe33/results.bin b/.gradle-user/caches/9.7.1/transforms/389d81dafd8b33ede287200a6806fe33/results.bin new file mode 100644 index 0000000..bbe19be --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/389d81dafd8b33ede287200a6806fe33/results.bin @@ -0,0 +1,2 @@ +o/.gradle-instrumented-classpath.marker +o/merge/instrumentation-dependencies.bin diff --git a/.gradle-user/caches/9.7.1/transforms/389d81dafd8b33ede287200a6806fe33/transformed/.gradle-instrumented-classpath.marker b/.gradle-user/caches/9.7.1/transforms/389d81dafd8b33ede287200a6806fe33/transformed/.gradle-instrumented-classpath.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/389d81dafd8b33ede287200a6806fe33/transformed/merge/instrumentation-dependencies.bin b/.gradle-user/caches/9.7.1/transforms/389d81dafd8b33ede287200a6806fe33/transformed/merge/instrumentation-dependencies.bin new file mode 100644 index 0000000..6bbecff Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/389d81dafd8b33ede287200a6806fe33/transformed/merge/instrumentation-dependencies.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/3d07a562b5d50d410d7fd3df8b62278d/metadata.bin b/.gradle-user/caches/9.7.1/transforms/3d07a562b5d50d410d7fd3df8b62278d/metadata.bin new file mode 100644 index 0000000..9eb5c93 Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/3d07a562b5d50d410d7fd3df8b62278d/metadata.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/3d07a562b5d50d410d7fd3df8b62278d/results.bin b/.gradle-user/caches/9.7.1/transforms/3d07a562b5d50d410d7fd3df8b62278d/results.bin new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/427cdc7523a6644cf36397973fbfc1c4/metadata.bin b/.gradle-user/caches/9.7.1/transforms/427cdc7523a6644cf36397973fbfc1c4/metadata.bin new file mode 100644 index 0000000..93eff8f Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/427cdc7523a6644cf36397973fbfc1c4/metadata.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/427cdc7523a6644cf36397973fbfc1c4/results.bin b/.gradle-user/caches/9.7.1/transforms/427cdc7523a6644cf36397973fbfc1c4/results.bin new file mode 100644 index 0000000..bbe19be --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/427cdc7523a6644cf36397973fbfc1c4/results.bin @@ -0,0 +1,2 @@ +o/.gradle-instrumented-classpath.marker +o/merge/instrumentation-dependencies.bin diff --git a/.gradle-user/caches/9.7.1/transforms/427cdc7523a6644cf36397973fbfc1c4/transformed/.gradle-instrumented-classpath.marker b/.gradle-user/caches/9.7.1/transforms/427cdc7523a6644cf36397973fbfc1c4/transformed/.gradle-instrumented-classpath.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/427cdc7523a6644cf36397973fbfc1c4/transformed/merge/instrumentation-dependencies.bin b/.gradle-user/caches/9.7.1/transforms/427cdc7523a6644cf36397973fbfc1c4/transformed/merge/instrumentation-dependencies.bin new file mode 100644 index 0000000..6624cb9 Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/427cdc7523a6644cf36397973fbfc1c4/transformed/merge/instrumentation-dependencies.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/42d0f271a52286a9f750d79f9ecae1ef/metadata.bin b/.gradle-user/caches/9.7.1/transforms/42d0f271a52286a9f750d79f9ecae1ef/metadata.bin new file mode 100644 index 0000000..6986d08 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/42d0f271a52286a9f750d79f9ecae1ef/metadata.bin @@ -0,0 +1,2 @@ +›wviskalnfjcajntw2rttlz5qli°oáiŠ%p6©¶•¼%«;Þ��outputDirectory +ÿŠÙƒS$£Œ›ZŒresultsFile–qÄÿ’8·S 7W-4¢?k \ No newline at end of file diff --git a/.gradle-user/caches/9.7.1/transforms/42d0f271a52286a9f750d79f9ecae1ef/results.bin b/.gradle-user/caches/9.7.1/transforms/42d0f271a52286a9f750d79f9ecae1ef/results.bin new file mode 100644 index 0000000..fbd4b01 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/42d0f271a52286a9f750d79f9ecae1ef/results.bin @@ -0,0 +1,4 @@ +o/.gradle-instrumented-classpath.marker +o/.gradle-agent-instrumented-external.marker +o/instrumented/instrumented-ant-1.10.15.jar +i/ diff --git a/.gradle-user/caches/9.7.1/transforms/42d0f271a52286a9f750d79f9ecae1ef/transformed/.gradle-agent-instrumented-external.marker b/.gradle-user/caches/9.7.1/transforms/42d0f271a52286a9f750d79f9ecae1ef/transformed/.gradle-agent-instrumented-external.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/42d0f271a52286a9f750d79f9ecae1ef/transformed/.gradle-instrumented-classpath.marker b/.gradle-user/caches/9.7.1/transforms/42d0f271a52286a9f750d79f9ecae1ef/transformed/.gradle-instrumented-classpath.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/42d0f271a52286a9f750d79f9ecae1ef/transformed/instrumented/instrumented-ant-1.10.15.jar b/.gradle-user/caches/9.7.1/transforms/42d0f271a52286a9f750d79f9ecae1ef/transformed/instrumented/instrumented-ant-1.10.15.jar new file mode 100644 index 0000000..a1a6f18 Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/42d0f271a52286a9f750d79f9ecae1ef/transformed/instrumented/instrumented-ant-1.10.15.jar differ diff --git a/.gradle-user/caches/9.7.1/transforms/442f8040c6cef8684857a099d5335fa4/metadata.bin b/.gradle-user/caches/9.7.1/transforms/442f8040c6cef8684857a099d5335fa4/metadata.bin new file mode 100644 index 0000000..4a061aa --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/442f8040c6cef8684857a099d5335fa4/metadata.bin @@ -0,0 +1,2 @@ +›wviskalnfjcajntw2rttlz5qli•Q†ˆjÊîùçè¥ao¾;%�outputDirectory}Û¹¡øúTEÁƒ]ë[/½ŒresultsFile_%¡H“�6 +B‘abm \ No newline at end of file diff --git a/.gradle-user/caches/9.7.1/transforms/442f8040c6cef8684857a099d5335fa4/results.bin b/.gradle-user/caches/9.7.1/transforms/442f8040c6cef8684857a099d5335fa4/results.bin new file mode 100644 index 0000000..e7d46e8 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/442f8040c6cef8684857a099d5335fa4/results.bin @@ -0,0 +1,4 @@ +o/.gradle-instrumented-classpath.marker +o/analysis/instrumentation-hierarchy.bin +o/analysis/instrumentation-dependencies.bin +i/ diff --git a/.gradle-user/caches/9.7.1/transforms/442f8040c6cef8684857a099d5335fa4/transformed/.gradle-instrumented-classpath.marker b/.gradle-user/caches/9.7.1/transforms/442f8040c6cef8684857a099d5335fa4/transformed/.gradle-instrumented-classpath.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/442f8040c6cef8684857a099d5335fa4/transformed/analysis/instrumentation-dependencies.bin b/.gradle-user/caches/9.7.1/transforms/442f8040c6cef8684857a099d5335fa4/transformed/analysis/instrumentation-dependencies.bin new file mode 100644 index 0000000..66996ef Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/442f8040c6cef8684857a099d5335fa4/transformed/analysis/instrumentation-dependencies.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/442f8040c6cef8684857a099d5335fa4/transformed/analysis/instrumentation-hierarchy.bin b/.gradle-user/caches/9.7.1/transforms/442f8040c6cef8684857a099d5335fa4/transformed/analysis/instrumentation-hierarchy.bin new file mode 100644 index 0000000..9493aff Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/442f8040c6cef8684857a099d5335fa4/transformed/analysis/instrumentation-hierarchy.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/450d47f24a4e74a8b156c4b78ecd20f2/metadata.bin b/.gradle-user/caches/9.7.1/transforms/450d47f24a4e74a8b156c4b78ecd20f2/metadata.bin new file mode 100644 index 0000000..49889d2 Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/450d47f24a4e74a8b156c4b78ecd20f2/metadata.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/450d47f24a4e74a8b156c4b78ecd20f2/results.bin b/.gradle-user/caches/9.7.1/transforms/450d47f24a4e74a8b156c4b78ecd20f2/results.bin new file mode 100644 index 0000000..3579d05 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/450d47f24a4e74a8b156c4b78ecd20f2/results.bin @@ -0,0 +1,4 @@ +o/.gradle-instrumented-classpath.marker +o/.gradle-agent-instrumented-external.marker +o/instrumented/instrumented-jdom2-2.0.6.1.jar +i/ diff --git a/.gradle-user/caches/9.7.1/transforms/450d47f24a4e74a8b156c4b78ecd20f2/transformed/.gradle-agent-instrumented-external.marker b/.gradle-user/caches/9.7.1/transforms/450d47f24a4e74a8b156c4b78ecd20f2/transformed/.gradle-agent-instrumented-external.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/450d47f24a4e74a8b156c4b78ecd20f2/transformed/.gradle-instrumented-classpath.marker b/.gradle-user/caches/9.7.1/transforms/450d47f24a4e74a8b156c4b78ecd20f2/transformed/.gradle-instrumented-classpath.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/450d47f24a4e74a8b156c4b78ecd20f2/transformed/instrumented/instrumented-jdom2-2.0.6.1.jar b/.gradle-user/caches/9.7.1/transforms/450d47f24a4e74a8b156c4b78ecd20f2/transformed/instrumented/instrumented-jdom2-2.0.6.1.jar new file mode 100644 index 0000000..c73441d Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/450d47f24a4e74a8b156c4b78ecd20f2/transformed/instrumented/instrumented-jdom2-2.0.6.1.jar differ diff --git a/.gradle-user/caches/9.7.1/transforms/45167a7d1ca07b8c77b62bef28ddc18f/metadata.bin b/.gradle-user/caches/9.7.1/transforms/45167a7d1ca07b8c77b62bef28ddc18f/metadata.bin new file mode 100644 index 0000000..1b47560 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/45167a7d1ca07b8c77b62bef28ddc18f/metadata.bin @@ -0,0 +1,2 @@ +›wviskalnfjcajntw2rttlz5qli × <¾¨7¿“¥ol±¹Cé�outputDirectorynJ +2íï/'Ç€5�TòQŒresultsFile`¯õ±Á¬7�×uH…¡¹Ê \ No newline at end of file diff --git a/.gradle-user/caches/9.7.1/transforms/45167a7d1ca07b8c77b62bef28ddc18f/results.bin b/.gradle-user/caches/9.7.1/transforms/45167a7d1ca07b8c77b62bef28ddc18f/results.bin new file mode 100644 index 0000000..bbe19be --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/45167a7d1ca07b8c77b62bef28ddc18f/results.bin @@ -0,0 +1,2 @@ +o/.gradle-instrumented-classpath.marker +o/merge/instrumentation-dependencies.bin diff --git a/.gradle-user/caches/9.7.1/transforms/45167a7d1ca07b8c77b62bef28ddc18f/transformed/.gradle-instrumented-classpath.marker b/.gradle-user/caches/9.7.1/transforms/45167a7d1ca07b8c77b62bef28ddc18f/transformed/.gradle-instrumented-classpath.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/45167a7d1ca07b8c77b62bef28ddc18f/transformed/merge/instrumentation-dependencies.bin b/.gradle-user/caches/9.7.1/transforms/45167a7d1ca07b8c77b62bef28ddc18f/transformed/merge/instrumentation-dependencies.bin new file mode 100644 index 0000000..171a02d Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/45167a7d1ca07b8c77b62bef28ddc18f/transformed/merge/instrumentation-dependencies.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/4730e3e19c1fb45814e6ecdb9f27d813/metadata.bin b/.gradle-user/caches/9.7.1/transforms/4730e3e19c1fb45814e6ecdb9f27d813/metadata.bin new file mode 100644 index 0000000..69ae42f --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/4730e3e19c1fb45814e6ecdb9f27d813/metadata.bin @@ -0,0 +1 @@ +›wviskalnfjcajntw2rttlz5qli"PÍðK©ASò‹H”á¬�outputDirectory˜UšæÉ9FI”›n¤’¹ŒresultsFile`¯õ±Á¬7�×uH…¡¹Ê \ No newline at end of file diff --git a/.gradle-user/caches/9.7.1/transforms/4730e3e19c1fb45814e6ecdb9f27d813/results.bin b/.gradle-user/caches/9.7.1/transforms/4730e3e19c1fb45814e6ecdb9f27d813/results.bin new file mode 100644 index 0000000..bbe19be --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/4730e3e19c1fb45814e6ecdb9f27d813/results.bin @@ -0,0 +1,2 @@ +o/.gradle-instrumented-classpath.marker +o/merge/instrumentation-dependencies.bin diff --git a/.gradle-user/caches/9.7.1/transforms/4730e3e19c1fb45814e6ecdb9f27d813/transformed/.gradle-instrumented-classpath.marker b/.gradle-user/caches/9.7.1/transforms/4730e3e19c1fb45814e6ecdb9f27d813/transformed/.gradle-instrumented-classpath.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/4730e3e19c1fb45814e6ecdb9f27d813/transformed/merge/instrumentation-dependencies.bin b/.gradle-user/caches/9.7.1/transforms/4730e3e19c1fb45814e6ecdb9f27d813/transformed/merge/instrumentation-dependencies.bin new file mode 100644 index 0000000..a2ef5b7 Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/4730e3e19c1fb45814e6ecdb9f27d813/transformed/merge/instrumentation-dependencies.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/4a51db4b442c62f3485266be0d087d35/metadata.bin b/.gradle-user/caches/9.7.1/transforms/4a51db4b442c62f3485266be0d087d35/metadata.bin new file mode 100644 index 0000000..bc850f3 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/4a51db4b442c62f3485266be0d087d35/metadata.bin @@ -0,0 +1 @@ +›wviskalnfjcajntw2rttlz5qli·Ø[£ó;Í0„ôåÇs�outputDirectory:rôçäí —8TK§õJµŒresultsFile‰oÌ´ÝÌ;Z*Èç'Õ:BÛ \ No newline at end of file diff --git a/.gradle-user/caches/9.7.1/transforms/4a51db4b442c62f3485266be0d087d35/results.bin b/.gradle-user/caches/9.7.1/transforms/4a51db4b442c62f3485266be0d087d35/results.bin new file mode 100644 index 0000000..783522b --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/4a51db4b442c62f3485266be0d087d35/results.bin @@ -0,0 +1,2 @@ +o/.gradle-instrumented-classpath.marker +i/ diff --git a/.gradle-user/caches/9.7.1/transforms/4a51db4b442c62f3485266be0d087d35/transformed/.gradle-instrumented-classpath.marker b/.gradle-user/caches/9.7.1/transforms/4a51db4b442c62f3485266be0d087d35/transformed/.gradle-instrumented-classpath.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/4aa24b3c95816f0db0290739beb6c8a2/metadata.bin b/.gradle-user/caches/9.7.1/transforms/4aa24b3c95816f0db0290739beb6c8a2/metadata.bin new file mode 100644 index 0000000..ae92a76 Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/4aa24b3c95816f0db0290739beb6c8a2/metadata.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/4aa24b3c95816f0db0290739beb6c8a2/results.bin b/.gradle-user/caches/9.7.1/transforms/4aa24b3c95816f0db0290739beb6c8a2/results.bin new file mode 100644 index 0000000..1ed65e0 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/4aa24b3c95816f0db0290739beb6c8a2/results.bin @@ -0,0 +1 @@ +i/ diff --git a/.gradle-user/caches/9.7.1/transforms/4bbf9e670e040873bc597acdc7d3de72/metadata.bin b/.gradle-user/caches/9.7.1/transforms/4bbf9e670e040873bc597acdc7d3de72/metadata.bin new file mode 100644 index 0000000..abc5a23 Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/4bbf9e670e040873bc597acdc7d3de72/metadata.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/4bbf9e670e040873bc597acdc7d3de72/results.bin b/.gradle-user/caches/9.7.1/transforms/4bbf9e670e040873bc597acdc7d3de72/results.bin new file mode 100644 index 0000000..bbe19be --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/4bbf9e670e040873bc597acdc7d3de72/results.bin @@ -0,0 +1,2 @@ +o/.gradle-instrumented-classpath.marker +o/merge/instrumentation-dependencies.bin diff --git a/.gradle-user/caches/9.7.1/transforms/4bbf9e670e040873bc597acdc7d3de72/transformed/.gradle-instrumented-classpath.marker b/.gradle-user/caches/9.7.1/transforms/4bbf9e670e040873bc597acdc7d3de72/transformed/.gradle-instrumented-classpath.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/4bbf9e670e040873bc597acdc7d3de72/transformed/merge/instrumentation-dependencies.bin b/.gradle-user/caches/9.7.1/transforms/4bbf9e670e040873bc597acdc7d3de72/transformed/merge/instrumentation-dependencies.bin new file mode 100644 index 0000000..6e36fd1 Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/4bbf9e670e040873bc597acdc7d3de72/transformed/merge/instrumentation-dependencies.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/4d0e5529e7786256508155be7d7a2727/metadata.bin b/.gradle-user/caches/9.7.1/transforms/4d0e5529e7786256508155be7d7a2727/metadata.bin new file mode 100644 index 0000000..02f982a --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/4d0e5529e7786256508155be7d7a2727/metadata.bin @@ -0,0 +1 @@ +›wviskalnfjcajntw2rttlz5qli©ýÿ6q‹gLêŒþ-PA“�outputDirectoryOÕ¿ÖX3“…3±5E‘�ŒresultsFileN‡gª’Tñ|2OYE`æç \ No newline at end of file diff --git a/.gradle-user/caches/9.7.1/transforms/4d0e5529e7786256508155be7d7a2727/results.bin b/.gradle-user/caches/9.7.1/transforms/4d0e5529e7786256508155be7d7a2727/results.bin new file mode 100644 index 0000000..1ed65e0 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/4d0e5529e7786256508155be7d7a2727/results.bin @@ -0,0 +1 @@ +i/ diff --git a/.gradle-user/caches/9.7.1/transforms/4e0c861a234e7535a2c5fad85f637208/metadata.bin b/.gradle-user/caches/9.7.1/transforms/4e0c861a234e7535a2c5fad85f637208/metadata.bin new file mode 100644 index 0000000..2970757 Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/4e0c861a234e7535a2c5fad85f637208/metadata.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/4e0c861a234e7535a2c5fad85f637208/results.bin b/.gradle-user/caches/9.7.1/transforms/4e0c861a234e7535a2c5fad85f637208/results.bin new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/4e5085934282649a12c10e5776ce267e/metadata.bin b/.gradle-user/caches/9.7.1/transforms/4e5085934282649a12c10e5776ce267e/metadata.bin new file mode 100644 index 0000000..7f95f9c Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/4e5085934282649a12c10e5776ce267e/metadata.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/4e5085934282649a12c10e5776ce267e/results.bin b/.gradle-user/caches/9.7.1/transforms/4e5085934282649a12c10e5776ce267e/results.bin new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/50ed2392d9853c5f88bb8c217fee232d/metadata.bin b/.gradle-user/caches/9.7.1/transforms/50ed2392d9853c5f88bb8c217fee232d/metadata.bin new file mode 100644 index 0000000..7d823be --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/50ed2392d9853c5f88bb8c217fee232d/metadata.bin @@ -0,0 +1 @@ +›wviskalnfjcajntw2rttlz5qliáÄÙ$~²êÜ0?;¼*b�outputDirectoryQìÜ€›„¬Ë«m±Å¶`ŒresultsFile‚"-é"z2ñ•¢€“ \ No newline at end of file diff --git a/.gradle-user/caches/9.7.1/transforms/50ed2392d9853c5f88bb8c217fee232d/results.bin b/.gradle-user/caches/9.7.1/transforms/50ed2392d9853c5f88bb8c217fee232d/results.bin new file mode 100644 index 0000000..6d6c9af --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/50ed2392d9853c5f88bb8c217fee232d/results.bin @@ -0,0 +1,4 @@ +o/.gradle-instrumented-classpath.marker +o/.gradle-agent-instrumented-external.marker +o/instrumented/instrumented-plexus-xml-4.0.4.jar +i/ diff --git a/.gradle-user/caches/9.7.1/transforms/50ed2392d9853c5f88bb8c217fee232d/transformed/.gradle-agent-instrumented-external.marker b/.gradle-user/caches/9.7.1/transforms/50ed2392d9853c5f88bb8c217fee232d/transformed/.gradle-agent-instrumented-external.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/50ed2392d9853c5f88bb8c217fee232d/transformed/.gradle-instrumented-classpath.marker b/.gradle-user/caches/9.7.1/transforms/50ed2392d9853c5f88bb8c217fee232d/transformed/.gradle-instrumented-classpath.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/50ed2392d9853c5f88bb8c217fee232d/transformed/instrumented/instrumented-plexus-xml-4.0.4.jar b/.gradle-user/caches/9.7.1/transforms/50ed2392d9853c5f88bb8c217fee232d/transformed/instrumented/instrumented-plexus-xml-4.0.4.jar new file mode 100644 index 0000000..8f814c9 Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/50ed2392d9853c5f88bb8c217fee232d/transformed/instrumented/instrumented-plexus-xml-4.0.4.jar differ diff --git a/.gradle-user/caches/9.7.1/transforms/52005a40fa19fbb2f56326320a555b5c/metadata.bin b/.gradle-user/caches/9.7.1/transforms/52005a40fa19fbb2f56326320a555b5c/metadata.bin new file mode 100644 index 0000000..db10037 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/52005a40fa19fbb2f56326320a555b5c/metadata.bin @@ -0,0 +1 @@ +›wviskalnfjcajntw2rttlz5qli—jn¡°“1Ïl#ÿ¨¡�outputDirectory:rôçäí —8TK§õJµŒresultsFile‰oÌ´ÝÌ;Z*Èç'Õ:BÛ \ No newline at end of file diff --git a/.gradle-user/caches/9.7.1/transforms/52005a40fa19fbb2f56326320a555b5c/results.bin b/.gradle-user/caches/9.7.1/transforms/52005a40fa19fbb2f56326320a555b5c/results.bin new file mode 100644 index 0000000..783522b --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/52005a40fa19fbb2f56326320a555b5c/results.bin @@ -0,0 +1,2 @@ +o/.gradle-instrumented-classpath.marker +i/ diff --git a/.gradle-user/caches/9.7.1/transforms/52005a40fa19fbb2f56326320a555b5c/transformed/.gradle-instrumented-classpath.marker b/.gradle-user/caches/9.7.1/transforms/52005a40fa19fbb2f56326320a555b5c/transformed/.gradle-instrumented-classpath.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/538fde37401f65eed32356da59dd2880/metadata.bin b/.gradle-user/caches/9.7.1/transforms/538fde37401f65eed32356da59dd2880/metadata.bin new file mode 100644 index 0000000..56e0be5 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/538fde37401f65eed32356da59dd2880/metadata.bin @@ -0,0 +1,2 @@ +›wviskalnfjcajntw2rttlz5qli>ÝêÎAjC9›)…¨��outputDirectorypîwmà(®Û�‚§¶ŒresultsFile_%¡H“�6 +B‘abm \ No newline at end of file diff --git a/.gradle-user/caches/9.7.1/transforms/538fde37401f65eed32356da59dd2880/results.bin b/.gradle-user/caches/9.7.1/transforms/538fde37401f65eed32356da59dd2880/results.bin new file mode 100644 index 0000000..e7d46e8 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/538fde37401f65eed32356da59dd2880/results.bin @@ -0,0 +1,4 @@ +o/.gradle-instrumented-classpath.marker +o/analysis/instrumentation-hierarchy.bin +o/analysis/instrumentation-dependencies.bin +i/ diff --git a/.gradle-user/caches/9.7.1/transforms/538fde37401f65eed32356da59dd2880/transformed/.gradle-instrumented-classpath.marker b/.gradle-user/caches/9.7.1/transforms/538fde37401f65eed32356da59dd2880/transformed/.gradle-instrumented-classpath.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/538fde37401f65eed32356da59dd2880/transformed/analysis/instrumentation-dependencies.bin b/.gradle-user/caches/9.7.1/transforms/538fde37401f65eed32356da59dd2880/transformed/analysis/instrumentation-dependencies.bin new file mode 100644 index 0000000..c0c8b34 Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/538fde37401f65eed32356da59dd2880/transformed/analysis/instrumentation-dependencies.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/538fde37401f65eed32356da59dd2880/transformed/analysis/instrumentation-hierarchy.bin b/.gradle-user/caches/9.7.1/transforms/538fde37401f65eed32356da59dd2880/transformed/analysis/instrumentation-hierarchy.bin new file mode 100644 index 0000000..e185c77 Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/538fde37401f65eed32356da59dd2880/transformed/analysis/instrumentation-hierarchy.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/58958b7c1b782fc3c663a5d73169eac3/metadata.bin b/.gradle-user/caches/9.7.1/transforms/58958b7c1b782fc3c663a5d73169eac3/metadata.bin new file mode 100644 index 0000000..4399d45 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/58958b7c1b782fc3c663a5d73169eac3/metadata.bin @@ -0,0 +1,2 @@ +›wviskalnfjcajntw2rttlz5qliWö@D¦€û¾è°ôþ2F;�outputDirectoryÁs¶r%åH²Ø%WœMyáŒresultsFile_%¡H“�6 +B‘abm \ No newline at end of file diff --git a/.gradle-user/caches/9.7.1/transforms/58958b7c1b782fc3c663a5d73169eac3/results.bin b/.gradle-user/caches/9.7.1/transforms/58958b7c1b782fc3c663a5d73169eac3/results.bin new file mode 100644 index 0000000..e7d46e8 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/58958b7c1b782fc3c663a5d73169eac3/results.bin @@ -0,0 +1,4 @@ +o/.gradle-instrumented-classpath.marker +o/analysis/instrumentation-hierarchy.bin +o/analysis/instrumentation-dependencies.bin +i/ diff --git a/.gradle-user/caches/9.7.1/transforms/58958b7c1b782fc3c663a5d73169eac3/transformed/.gradle-instrumented-classpath.marker b/.gradle-user/caches/9.7.1/transforms/58958b7c1b782fc3c663a5d73169eac3/transformed/.gradle-instrumented-classpath.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/58958b7c1b782fc3c663a5d73169eac3/transformed/analysis/instrumentation-dependencies.bin b/.gradle-user/caches/9.7.1/transforms/58958b7c1b782fc3c663a5d73169eac3/transformed/analysis/instrumentation-dependencies.bin new file mode 100644 index 0000000..7e703d8 Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/58958b7c1b782fc3c663a5d73169eac3/transformed/analysis/instrumentation-dependencies.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/58958b7c1b782fc3c663a5d73169eac3/transformed/analysis/instrumentation-hierarchy.bin b/.gradle-user/caches/9.7.1/transforms/58958b7c1b782fc3c663a5d73169eac3/transformed/analysis/instrumentation-hierarchy.bin new file mode 100644 index 0000000..724222c Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/58958b7c1b782fc3c663a5d73169eac3/transformed/analysis/instrumentation-hierarchy.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/5b9e2196d44c27c389235c09d56360ff/metadata.bin b/.gradle-user/caches/9.7.1/transforms/5b9e2196d44c27c389235c09d56360ff/metadata.bin new file mode 100644 index 0000000..5b812da --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/5b9e2196d44c27c389235c09d56360ff/metadata.bin @@ -0,0 +1 @@ +›wviskalnfjcajntw2rttlz5qliçýµ|F9²‘ ¦ãÖ1�outputDirectoryò~öÊü•f#uwÐáJç^ŒresultsFile³ŸŹ fá™Ä6Ûvic \ No newline at end of file diff --git a/.gradle-user/caches/9.7.1/transforms/5b9e2196d44c27c389235c09d56360ff/results.bin b/.gradle-user/caches/9.7.1/transforms/5b9e2196d44c27c389235c09d56360ff/results.bin new file mode 100644 index 0000000..22a749b --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/5b9e2196d44c27c389235c09d56360ff/results.bin @@ -0,0 +1,4 @@ +o/.gradle-instrumented-classpath.marker +o/.gradle-agent-instrumented-external.marker +o/instrumented/instrumented-maven-xml-impl-4.0.0-alpha-9.jar +i/ diff --git a/.gradle-user/caches/9.7.1/transforms/5b9e2196d44c27c389235c09d56360ff/transformed/.gradle-agent-instrumented-external.marker b/.gradle-user/caches/9.7.1/transforms/5b9e2196d44c27c389235c09d56360ff/transformed/.gradle-agent-instrumented-external.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/5b9e2196d44c27c389235c09d56360ff/transformed/.gradle-instrumented-classpath.marker b/.gradle-user/caches/9.7.1/transforms/5b9e2196d44c27c389235c09d56360ff/transformed/.gradle-instrumented-classpath.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/5b9e2196d44c27c389235c09d56360ff/transformed/instrumented/instrumented-maven-xml-impl-4.0.0-alpha-9.jar b/.gradle-user/caches/9.7.1/transforms/5b9e2196d44c27c389235c09d56360ff/transformed/instrumented/instrumented-maven-xml-impl-4.0.0-alpha-9.jar new file mode 100644 index 0000000..c77743e Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/5b9e2196d44c27c389235c09d56360ff/transformed/instrumented/instrumented-maven-xml-impl-4.0.0-alpha-9.jar differ diff --git a/.gradle-user/caches/9.7.1/transforms/5d4a6eb8326c2847cacd004b1a47bd89/metadata.bin b/.gradle-user/caches/9.7.1/transforms/5d4a6eb8326c2847cacd004b1a47bd89/metadata.bin new file mode 100644 index 0000000..4cfc1b8 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/5d4a6eb8326c2847cacd004b1a47bd89/metadata.bin @@ -0,0 +1,2 @@ +›wviskalnfjcajntw2rttlz5qlii]ó‰”çZœÝ–›1¶A�outputDirectoryµ Wlê«•Ù5>B‘ŒOZŒresultsFile_%¡H“�6 +B‘abm \ No newline at end of file diff --git a/.gradle-user/caches/9.7.1/transforms/5d4a6eb8326c2847cacd004b1a47bd89/results.bin b/.gradle-user/caches/9.7.1/transforms/5d4a6eb8326c2847cacd004b1a47bd89/results.bin new file mode 100644 index 0000000..e7d46e8 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/5d4a6eb8326c2847cacd004b1a47bd89/results.bin @@ -0,0 +1,4 @@ +o/.gradle-instrumented-classpath.marker +o/analysis/instrumentation-hierarchy.bin +o/analysis/instrumentation-dependencies.bin +i/ diff --git a/.gradle-user/caches/9.7.1/transforms/5d4a6eb8326c2847cacd004b1a47bd89/transformed/.gradle-instrumented-classpath.marker b/.gradle-user/caches/9.7.1/transforms/5d4a6eb8326c2847cacd004b1a47bd89/transformed/.gradle-instrumented-classpath.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/5d4a6eb8326c2847cacd004b1a47bd89/transformed/analysis/instrumentation-dependencies.bin b/.gradle-user/caches/9.7.1/transforms/5d4a6eb8326c2847cacd004b1a47bd89/transformed/analysis/instrumentation-dependencies.bin new file mode 100644 index 0000000..29b8441 Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/5d4a6eb8326c2847cacd004b1a47bd89/transformed/analysis/instrumentation-dependencies.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/5d4a6eb8326c2847cacd004b1a47bd89/transformed/analysis/instrumentation-hierarchy.bin b/.gradle-user/caches/9.7.1/transforms/5d4a6eb8326c2847cacd004b1a47bd89/transformed/analysis/instrumentation-hierarchy.bin new file mode 100644 index 0000000..42f375b Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/5d4a6eb8326c2847cacd004b1a47bd89/transformed/analysis/instrumentation-hierarchy.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/5f1ab3021d4bb39a7279d4328a2de315/metadata.bin b/.gradle-user/caches/9.7.1/transforms/5f1ab3021d4bb39a7279d4328a2de315/metadata.bin new file mode 100644 index 0000000..aa6e69c --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/5f1ab3021d4bb39a7279d4328a2de315/metadata.bin @@ -0,0 +1 @@ +›wviskalnfjcajntw2rttlz5qlin5p–t¥FôþiŸ)ªú[ÿ�outputDirectoryúHDì_iæxQTiZžÒC!ŒresultsFile¥ØÛÓ\ŽíùOÏŸ› \ No newline at end of file diff --git a/.gradle-user/caches/9.7.1/transforms/5f1ab3021d4bb39a7279d4328a2de315/results.bin b/.gradle-user/caches/9.7.1/transforms/5f1ab3021d4bb39a7279d4328a2de315/results.bin new file mode 100644 index 0000000..35a788b --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/5f1ab3021d4bb39a7279d4328a2de315/results.bin @@ -0,0 +1,4 @@ +o/.gradle-instrumented-classpath.marker +o/.gradle-agent-instrumented-external.marker +o/instrumented/instrumented-log4j-core-2.24.1.jar +i/ diff --git a/.gradle-user/caches/9.7.1/transforms/5f1ab3021d4bb39a7279d4328a2de315/transformed/.gradle-agent-instrumented-external.marker b/.gradle-user/caches/9.7.1/transforms/5f1ab3021d4bb39a7279d4328a2de315/transformed/.gradle-agent-instrumented-external.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/5f1ab3021d4bb39a7279d4328a2de315/transformed/.gradle-instrumented-classpath.marker b/.gradle-user/caches/9.7.1/transforms/5f1ab3021d4bb39a7279d4328a2de315/transformed/.gradle-instrumented-classpath.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/5f1ab3021d4bb39a7279d4328a2de315/transformed/instrumented/instrumented-log4j-core-2.24.1.jar b/.gradle-user/caches/9.7.1/transforms/5f1ab3021d4bb39a7279d4328a2de315/transformed/instrumented/instrumented-log4j-core-2.24.1.jar new file mode 100644 index 0000000..acd32c4 Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/5f1ab3021d4bb39a7279d4328a2de315/transformed/instrumented/instrumented-log4j-core-2.24.1.jar differ diff --git a/.gradle-user/caches/9.7.1/transforms/60b39b145dfa60ef76c393321b778d79/metadata.bin b/.gradle-user/caches/9.7.1/transforms/60b39b145dfa60ef76c393321b778d79/metadata.bin new file mode 100644 index 0000000..320af24 Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/60b39b145dfa60ef76c393321b778d79/metadata.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/60b39b145dfa60ef76c393321b778d79/results.bin b/.gradle-user/caches/9.7.1/transforms/60b39b145dfa60ef76c393321b778d79/results.bin new file mode 100644 index 0000000..1ed65e0 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/60b39b145dfa60ef76c393321b778d79/results.bin @@ -0,0 +1 @@ +i/ diff --git a/.gradle-user/caches/9.7.1/transforms/648e99b1fa71322f165169b96d2a293e/metadata.bin b/.gradle-user/caches/9.7.1/transforms/648e99b1fa71322f165169b96d2a293e/metadata.bin new file mode 100644 index 0000000..767f10e Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/648e99b1fa71322f165169b96d2a293e/metadata.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/648e99b1fa71322f165169b96d2a293e/results.bin b/.gradle-user/caches/9.7.1/transforms/648e99b1fa71322f165169b96d2a293e/results.bin new file mode 100644 index 0000000..783522b --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/648e99b1fa71322f165169b96d2a293e/results.bin @@ -0,0 +1,2 @@ +o/.gradle-instrumented-classpath.marker +i/ diff --git a/.gradle-user/caches/9.7.1/transforms/648e99b1fa71322f165169b96d2a293e/transformed/.gradle-instrumented-classpath.marker b/.gradle-user/caches/9.7.1/transforms/648e99b1fa71322f165169b96d2a293e/transformed/.gradle-instrumented-classpath.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/64c37c01b5dcff83575c5eb772ab4d69/metadata.bin b/.gradle-user/caches/9.7.1/transforms/64c37c01b5dcff83575c5eb772ab4d69/metadata.bin new file mode 100644 index 0000000..367a697 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/64c37c01b5dcff83575c5eb772ab4d69/metadata.bin @@ -0,0 +1 @@ +›wviskalnfjcajntw2rttlz5qli¢£¦wÉwng|¨ÔÙL�outputDirectoryOÕ¿ÖX3“…3±5E‘�ŒresultsFileN‡gª’Tñ|2OYE`æç \ No newline at end of file diff --git a/.gradle-user/caches/9.7.1/transforms/64c37c01b5dcff83575c5eb772ab4d69/results.bin b/.gradle-user/caches/9.7.1/transforms/64c37c01b5dcff83575c5eb772ab4d69/results.bin new file mode 100644 index 0000000..1ed65e0 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/64c37c01b5dcff83575c5eb772ab4d69/results.bin @@ -0,0 +1 @@ +i/ diff --git a/.gradle-user/caches/9.7.1/transforms/651ee280f53c42b28ab61bde83d65532/metadata.bin b/.gradle-user/caches/9.7.1/transforms/651ee280f53c42b28ab61bde83d65532/metadata.bin new file mode 100644 index 0000000..47c7684 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/651ee280f53c42b28ab61bde83d65532/metadata.bin @@ -0,0 +1 @@ +›wviskalnfjcajntw2rttlz5qli�¢Í ¬Œ‰¸Édp¯î¬£ü�outputDirectoryOÕ¿ÖX3“…3±5E‘�ŒresultsFileõq“;¹HW{Ÿ0vû�ÇÆ \ No newline at end of file diff --git a/.gradle-user/caches/9.7.1/transforms/651ee280f53c42b28ab61bde83d65532/results.bin b/.gradle-user/caches/9.7.1/transforms/651ee280f53c42b28ab61bde83d65532/results.bin new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/69067c3c0e25f0ef4b5f616f30879437/metadata.bin b/.gradle-user/caches/9.7.1/transforms/69067c3c0e25f0ef4b5f616f30879437/metadata.bin new file mode 100644 index 0000000..90da87b --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/69067c3c0e25f0ef4b5f616f30879437/metadata.bin @@ -0,0 +1,2 @@ +›wviskalnfjcajntw2rttlz5qlik!¡tÞ#½¨ ¸`ÂíÖ*�outputDirectory‰•˜äBÌV8„Li;X1_úŒresultsFile_%¡H“�6 +B‘abm \ No newline at end of file diff --git a/.gradle-user/caches/9.7.1/transforms/69067c3c0e25f0ef4b5f616f30879437/results.bin b/.gradle-user/caches/9.7.1/transforms/69067c3c0e25f0ef4b5f616f30879437/results.bin new file mode 100644 index 0000000..e7d46e8 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/69067c3c0e25f0ef4b5f616f30879437/results.bin @@ -0,0 +1,4 @@ +o/.gradle-instrumented-classpath.marker +o/analysis/instrumentation-hierarchy.bin +o/analysis/instrumentation-dependencies.bin +i/ diff --git a/.gradle-user/caches/9.7.1/transforms/69067c3c0e25f0ef4b5f616f30879437/transformed/.gradle-instrumented-classpath.marker b/.gradle-user/caches/9.7.1/transforms/69067c3c0e25f0ef4b5f616f30879437/transformed/.gradle-instrumented-classpath.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/69067c3c0e25f0ef4b5f616f30879437/transformed/analysis/instrumentation-dependencies.bin b/.gradle-user/caches/9.7.1/transforms/69067c3c0e25f0ef4b5f616f30879437/transformed/analysis/instrumentation-dependencies.bin new file mode 100644 index 0000000..c83dc78 Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/69067c3c0e25f0ef4b5f616f30879437/transformed/analysis/instrumentation-dependencies.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/69067c3c0e25f0ef4b5f616f30879437/transformed/analysis/instrumentation-hierarchy.bin b/.gradle-user/caches/9.7.1/transforms/69067c3c0e25f0ef4b5f616f30879437/transformed/analysis/instrumentation-hierarchy.bin new file mode 100644 index 0000000..91f7e8c Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/69067c3c0e25f0ef4b5f616f30879437/transformed/analysis/instrumentation-hierarchy.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/6e2a30c25849b81086e05d6fe7a3f08a/metadata.bin b/.gradle-user/caches/9.7.1/transforms/6e2a30c25849b81086e05d6fe7a3f08a/metadata.bin new file mode 100644 index 0000000..622e4f6 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/6e2a30c25849b81086e05d6fe7a3f08a/metadata.bin @@ -0,0 +1,2 @@ +›wviskalnfjcajntw2rttlz5qliœ}E.¡üˆVŸc‡·è¸Ò#�outputDirectoryã¯e™çÇFWûÃGw‡ +ŒresultsFile`¯õ±Á¬7�×uH…¡¹Ê \ No newline at end of file diff --git a/.gradle-user/caches/9.7.1/transforms/6e2a30c25849b81086e05d6fe7a3f08a/results.bin b/.gradle-user/caches/9.7.1/transforms/6e2a30c25849b81086e05d6fe7a3f08a/results.bin new file mode 100644 index 0000000..bbe19be --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/6e2a30c25849b81086e05d6fe7a3f08a/results.bin @@ -0,0 +1,2 @@ +o/.gradle-instrumented-classpath.marker +o/merge/instrumentation-dependencies.bin diff --git a/.gradle-user/caches/9.7.1/transforms/6e2a30c25849b81086e05d6fe7a3f08a/transformed/.gradle-instrumented-classpath.marker b/.gradle-user/caches/9.7.1/transforms/6e2a30c25849b81086e05d6fe7a3f08a/transformed/.gradle-instrumented-classpath.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/6e2a30c25849b81086e05d6fe7a3f08a/transformed/merge/instrumentation-dependencies.bin b/.gradle-user/caches/9.7.1/transforms/6e2a30c25849b81086e05d6fe7a3f08a/transformed/merge/instrumentation-dependencies.bin new file mode 100644 index 0000000..919ccc8 Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/6e2a30c25849b81086e05d6fe7a3f08a/transformed/merge/instrumentation-dependencies.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/700875b11991c00a171fe5cfb236c390/metadata.bin b/.gradle-user/caches/9.7.1/transforms/700875b11991c00a171fe5cfb236c390/metadata.bin new file mode 100644 index 0000000..c5252b7 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/700875b11991c00a171fe5cfb236c390/metadata.bin @@ -0,0 +1 @@ +›wviskalnfjcajntw2rttlz5qliD›î¿ÚÉO É]ئýÌ�outputDirectoryƒf‚C«¥§§;geÖ6PŒresultsFile`¯õ±Á¬7�×uH…¡¹Ê \ No newline at end of file diff --git a/.gradle-user/caches/9.7.1/transforms/700875b11991c00a171fe5cfb236c390/results.bin b/.gradle-user/caches/9.7.1/transforms/700875b11991c00a171fe5cfb236c390/results.bin new file mode 100644 index 0000000..bbe19be --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/700875b11991c00a171fe5cfb236c390/results.bin @@ -0,0 +1,2 @@ +o/.gradle-instrumented-classpath.marker +o/merge/instrumentation-dependencies.bin diff --git a/.gradle-user/caches/9.7.1/transforms/700875b11991c00a171fe5cfb236c390/transformed/.gradle-instrumented-classpath.marker b/.gradle-user/caches/9.7.1/transforms/700875b11991c00a171fe5cfb236c390/transformed/.gradle-instrumented-classpath.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/700875b11991c00a171fe5cfb236c390/transformed/merge/instrumentation-dependencies.bin b/.gradle-user/caches/9.7.1/transforms/700875b11991c00a171fe5cfb236c390/transformed/merge/instrumentation-dependencies.bin new file mode 100644 index 0000000..6e8c6c0 Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/700875b11991c00a171fe5cfb236c390/transformed/merge/instrumentation-dependencies.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/725f298d898a7be154b790dd3a82d202/metadata.bin b/.gradle-user/caches/9.7.1/transforms/725f298d898a7be154b790dd3a82d202/metadata.bin new file mode 100644 index 0000000..5bcfc86 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/725f298d898a7be154b790dd3a82d202/metadata.bin @@ -0,0 +1 @@ +›wviskalnfjcajntw2rttlz5qliäÂøÔû¨ëç›eQ €éh�outputDirectory,/˜R4õoƒ„šŠuì ŒresultsFile`¯õ±Á¬7�×uH…¡¹Ê \ No newline at end of file diff --git a/.gradle-user/caches/9.7.1/transforms/725f298d898a7be154b790dd3a82d202/results.bin b/.gradle-user/caches/9.7.1/transforms/725f298d898a7be154b790dd3a82d202/results.bin new file mode 100644 index 0000000..bbe19be --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/725f298d898a7be154b790dd3a82d202/results.bin @@ -0,0 +1,2 @@ +o/.gradle-instrumented-classpath.marker +o/merge/instrumentation-dependencies.bin diff --git a/.gradle-user/caches/9.7.1/transforms/725f298d898a7be154b790dd3a82d202/transformed/.gradle-instrumented-classpath.marker b/.gradle-user/caches/9.7.1/transforms/725f298d898a7be154b790dd3a82d202/transformed/.gradle-instrumented-classpath.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/725f298d898a7be154b790dd3a82d202/transformed/merge/instrumentation-dependencies.bin b/.gradle-user/caches/9.7.1/transforms/725f298d898a7be154b790dd3a82d202/transformed/merge/instrumentation-dependencies.bin new file mode 100644 index 0000000..3c4df35 Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/725f298d898a7be154b790dd3a82d202/transformed/merge/instrumentation-dependencies.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/73ed41343b48bdd627a14d5ba44e2bc7/metadata.bin b/.gradle-user/caches/9.7.1/transforms/73ed41343b48bdd627a14d5ba44e2bc7/metadata.bin new file mode 100644 index 0000000..1c43b2f Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/73ed41343b48bdd627a14d5ba44e2bc7/metadata.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/73ed41343b48bdd627a14d5ba44e2bc7/results.bin b/.gradle-user/caches/9.7.1/transforms/73ed41343b48bdd627a14d5ba44e2bc7/results.bin new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/7d3b61bf5e7076ab4d5cc86a76520b9d/metadata.bin b/.gradle-user/caches/9.7.1/transforms/7d3b61bf5e7076ab4d5cc86a76520b9d/metadata.bin new file mode 100644 index 0000000..dde3302 Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/7d3b61bf5e7076ab4d5cc86a76520b9d/metadata.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/7d3b61bf5e7076ab4d5cc86a76520b9d/results.bin b/.gradle-user/caches/9.7.1/transforms/7d3b61bf5e7076ab4d5cc86a76520b9d/results.bin new file mode 100644 index 0000000..cd3b0e5 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/7d3b61bf5e7076ab4d5cc86a76520b9d/results.bin @@ -0,0 +1,4 @@ +o/.gradle-instrumented-classpath.marker +o/.gradle-agent-instrumented-external.marker +o/instrumented/instrumented-asm-commons-9.7.1.jar +i/ diff --git a/.gradle-user/caches/9.7.1/transforms/7d3b61bf5e7076ab4d5cc86a76520b9d/transformed/.gradle-agent-instrumented-external.marker b/.gradle-user/caches/9.7.1/transforms/7d3b61bf5e7076ab4d5cc86a76520b9d/transformed/.gradle-agent-instrumented-external.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/7d3b61bf5e7076ab4d5cc86a76520b9d/transformed/.gradle-instrumented-classpath.marker b/.gradle-user/caches/9.7.1/transforms/7d3b61bf5e7076ab4d5cc86a76520b9d/transformed/.gradle-instrumented-classpath.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/7d3b61bf5e7076ab4d5cc86a76520b9d/transformed/instrumented/instrumented-asm-commons-9.7.1.jar b/.gradle-user/caches/9.7.1/transforms/7d3b61bf5e7076ab4d5cc86a76520b9d/transformed/instrumented/instrumented-asm-commons-9.7.1.jar new file mode 100644 index 0000000..db640a3 Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/7d3b61bf5e7076ab4d5cc86a76520b9d/transformed/instrumented/instrumented-asm-commons-9.7.1.jar differ diff --git a/.gradle-user/caches/9.7.1/transforms/81b29d882eb1069a25e64bcf1e1c6dc1/metadata.bin b/.gradle-user/caches/9.7.1/transforms/81b29d882eb1069a25e64bcf1e1c6dc1/metadata.bin new file mode 100644 index 0000000..4026f63 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/81b29d882eb1069a25e64bcf1e1c6dc1/metadata.bin @@ -0,0 +1 @@ +›wviskalnfjcajntw2rttlz5qliÑû°h`–Ò �X¯UŒÞ�outputDirectory:rôçäí —8TK§õJµŒresultsFile‰oÌ´ÝÌ;Z*Èç'Õ:BÛ \ No newline at end of file diff --git a/.gradle-user/caches/9.7.1/transforms/81b29d882eb1069a25e64bcf1e1c6dc1/results.bin b/.gradle-user/caches/9.7.1/transforms/81b29d882eb1069a25e64bcf1e1c6dc1/results.bin new file mode 100644 index 0000000..783522b --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/81b29d882eb1069a25e64bcf1e1c6dc1/results.bin @@ -0,0 +1,2 @@ +o/.gradle-instrumented-classpath.marker +i/ diff --git a/.gradle-user/caches/9.7.1/transforms/81b29d882eb1069a25e64bcf1e1c6dc1/transformed/.gradle-instrumented-classpath.marker b/.gradle-user/caches/9.7.1/transforms/81b29d882eb1069a25e64bcf1e1c6dc1/transformed/.gradle-instrumented-classpath.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/88886641985db28477c352f838458693/metadata.bin b/.gradle-user/caches/9.7.1/transforms/88886641985db28477c352f838458693/metadata.bin new file mode 100644 index 0000000..9c20a13 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/88886641985db28477c352f838458693/metadata.bin @@ -0,0 +1,2 @@ +›wviskalnfjcajntw2rttlz5qli +Œ˜&²² UÇ€©&{t�outputDirectoryOÕ¿ÖX3“…3±5E‘�ŒresultsFileõq“;¹HW{Ÿ0vû�ÇÆ \ No newline at end of file diff --git a/.gradle-user/caches/9.7.1/transforms/88886641985db28477c352f838458693/results.bin b/.gradle-user/caches/9.7.1/transforms/88886641985db28477c352f838458693/results.bin new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/8976578f75a5cf8f845c04328116052f/metadata.bin b/.gradle-user/caches/9.7.1/transforms/8976578f75a5cf8f845c04328116052f/metadata.bin new file mode 100644 index 0000000..808dd4c --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/8976578f75a5cf8f845c04328116052f/metadata.bin @@ -0,0 +1 @@ +›wviskalnfjcajntw2rttlz5qlixw‡;jrÑ‹ý©)Ónú?Ñ�outputDirectoryŒXß›~& ¢gx£|¾©ŒresultsFileè‡À (yãv+y÷õ39Þ \ No newline at end of file diff --git a/.gradle-user/caches/9.7.1/transforms/8976578f75a5cf8f845c04328116052f/results.bin b/.gradle-user/caches/9.7.1/transforms/8976578f75a5cf8f845c04328116052f/results.bin new file mode 100644 index 0000000..64e2287 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/8976578f75a5cf8f845c04328116052f/results.bin @@ -0,0 +1,4 @@ +o/.gradle-instrumented-classpath.marker +o/.gradle-agent-instrumented-external.marker +o/instrumented/instrumented-woodstox-core-6.5.1.jar +i/ diff --git a/.gradle-user/caches/9.7.1/transforms/8976578f75a5cf8f845c04328116052f/transformed/.gradle-agent-instrumented-external.marker b/.gradle-user/caches/9.7.1/transforms/8976578f75a5cf8f845c04328116052f/transformed/.gradle-agent-instrumented-external.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/8976578f75a5cf8f845c04328116052f/transformed/.gradle-instrumented-classpath.marker b/.gradle-user/caches/9.7.1/transforms/8976578f75a5cf8f845c04328116052f/transformed/.gradle-instrumented-classpath.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/8976578f75a5cf8f845c04328116052f/transformed/instrumented/instrumented-woodstox-core-6.5.1.jar b/.gradle-user/caches/9.7.1/transforms/8976578f75a5cf8f845c04328116052f/transformed/instrumented/instrumented-woodstox-core-6.5.1.jar new file mode 100644 index 0000000..fc8baf6 Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/8976578f75a5cf8f845c04328116052f/transformed/instrumented/instrumented-woodstox-core-6.5.1.jar differ diff --git a/.gradle-user/caches/9.7.1/transforms/8e2736b2376ce8e49203ac0d29b4b0ec/metadata.bin b/.gradle-user/caches/9.7.1/transforms/8e2736b2376ce8e49203ac0d29b4b0ec/metadata.bin new file mode 100644 index 0000000..0cb6644 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/8e2736b2376ce8e49203ac0d29b4b0ec/metadata.bin @@ -0,0 +1 @@ +›wviskalnfjcajntw2rttlz5qliÑ*r=P�3]z Üdð¼�outputDirectorySÚr) _o¶dñ«Â÷¤ùŒresultsFile`¯õ±Á¬7�×uH…¡¹Ê \ No newline at end of file diff --git a/.gradle-user/caches/9.7.1/transforms/8e2736b2376ce8e49203ac0d29b4b0ec/results.bin b/.gradle-user/caches/9.7.1/transforms/8e2736b2376ce8e49203ac0d29b4b0ec/results.bin new file mode 100644 index 0000000..bbe19be --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/8e2736b2376ce8e49203ac0d29b4b0ec/results.bin @@ -0,0 +1,2 @@ +o/.gradle-instrumented-classpath.marker +o/merge/instrumentation-dependencies.bin diff --git a/.gradle-user/caches/9.7.1/transforms/8e2736b2376ce8e49203ac0d29b4b0ec/transformed/.gradle-instrumented-classpath.marker b/.gradle-user/caches/9.7.1/transforms/8e2736b2376ce8e49203ac0d29b4b0ec/transformed/.gradle-instrumented-classpath.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/8e2736b2376ce8e49203ac0d29b4b0ec/transformed/merge/instrumentation-dependencies.bin b/.gradle-user/caches/9.7.1/transforms/8e2736b2376ce8e49203ac0d29b4b0ec/transformed/merge/instrumentation-dependencies.bin new file mode 100644 index 0000000..6381d7a Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/8e2736b2376ce8e49203ac0d29b4b0ec/transformed/merge/instrumentation-dependencies.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/8f1dd036dd442752f02afd59cd73056b/metadata.bin b/.gradle-user/caches/9.7.1/transforms/8f1dd036dd442752f02afd59cd73056b/metadata.bin new file mode 100644 index 0000000..8378109 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/8f1dd036dd442752f02afd59cd73056b/metadata.bin @@ -0,0 +1,2 @@ +›wviskalnfjcajntw2rttlz5qliœl6�³NÎÍï/!…úÖ%�outputDirectoryµ7›þ©ƒ STb\ùŒresultsFile_%¡H“�6 +B‘abm \ No newline at end of file diff --git a/.gradle-user/caches/9.7.1/transforms/8f1dd036dd442752f02afd59cd73056b/results.bin b/.gradle-user/caches/9.7.1/transforms/8f1dd036dd442752f02afd59cd73056b/results.bin new file mode 100644 index 0000000..e7d46e8 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/8f1dd036dd442752f02afd59cd73056b/results.bin @@ -0,0 +1,4 @@ +o/.gradle-instrumented-classpath.marker +o/analysis/instrumentation-hierarchy.bin +o/analysis/instrumentation-dependencies.bin +i/ diff --git a/.gradle-user/caches/9.7.1/transforms/8f1dd036dd442752f02afd59cd73056b/transformed/.gradle-instrumented-classpath.marker b/.gradle-user/caches/9.7.1/transforms/8f1dd036dd442752f02afd59cd73056b/transformed/.gradle-instrumented-classpath.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/8f1dd036dd442752f02afd59cd73056b/transformed/analysis/instrumentation-dependencies.bin b/.gradle-user/caches/9.7.1/transforms/8f1dd036dd442752f02afd59cd73056b/transformed/analysis/instrumentation-dependencies.bin new file mode 100644 index 0000000..9829e43 Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/8f1dd036dd442752f02afd59cd73056b/transformed/analysis/instrumentation-dependencies.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/8f1dd036dd442752f02afd59cd73056b/transformed/analysis/instrumentation-hierarchy.bin b/.gradle-user/caches/9.7.1/transforms/8f1dd036dd442752f02afd59cd73056b/transformed/analysis/instrumentation-hierarchy.bin new file mode 100644 index 0000000..920e61a Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/8f1dd036dd442752f02afd59cd73056b/transformed/analysis/instrumentation-hierarchy.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/8fa183922d60060c003d264a318b94dc/metadata.bin b/.gradle-user/caches/9.7.1/transforms/8fa183922d60060c003d264a318b94dc/metadata.bin new file mode 100644 index 0000000..7d7dcf4 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/8fa183922d60060c003d264a318b94dc/metadata.bin @@ -0,0 +1 @@ +›wviskalnfjcajntw2rttlz5qli‡¦ê“ ¢[ªÕVµs�+N�outputDirectoryOÕ¿ÖX3“…3±5E‘�ŒresultsFileN‡gª’Tñ|2OYE`æç \ No newline at end of file diff --git a/.gradle-user/caches/9.7.1/transforms/8fa183922d60060c003d264a318b94dc/results.bin b/.gradle-user/caches/9.7.1/transforms/8fa183922d60060c003d264a318b94dc/results.bin new file mode 100644 index 0000000..1ed65e0 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/8fa183922d60060c003d264a318b94dc/results.bin @@ -0,0 +1 @@ +i/ diff --git a/.gradle-user/caches/9.7.1/transforms/8fce9e366d7540e6c8dd287c61e43819/metadata.bin b/.gradle-user/caches/9.7.1/transforms/8fce9e366d7540e6c8dd287c61e43819/metadata.bin new file mode 100644 index 0000000..783acef Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/8fce9e366d7540e6c8dd287c61e43819/metadata.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/8fce9e366d7540e6c8dd287c61e43819/results.bin b/.gradle-user/caches/9.7.1/transforms/8fce9e366d7540e6c8dd287c61e43819/results.bin new file mode 100644 index 0000000..783522b --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/8fce9e366d7540e6c8dd287c61e43819/results.bin @@ -0,0 +1,2 @@ +o/.gradle-instrumented-classpath.marker +i/ diff --git a/.gradle-user/caches/9.7.1/transforms/8fce9e366d7540e6c8dd287c61e43819/transformed/.gradle-instrumented-classpath.marker b/.gradle-user/caches/9.7.1/transforms/8fce9e366d7540e6c8dd287c61e43819/transformed/.gradle-instrumented-classpath.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/908077100de65063d637a75d5858f3cc/metadata.bin b/.gradle-user/caches/9.7.1/transforms/908077100de65063d637a75d5858f3cc/metadata.bin new file mode 100644 index 0000000..eb22359 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/908077100de65063d637a75d5858f3cc/metadata.bin @@ -0,0 +1,2 @@ +›wviskalnfjcajntw2rttlz5qliÍ÷<*Gf>‡ÌY�þ@‚H�outputDirectory†(�[A-rmŸÁ¹IýîýŒresultsFile_%¡H“�6 +B‘abm \ No newline at end of file diff --git a/.gradle-user/caches/9.7.1/transforms/908077100de65063d637a75d5858f3cc/results.bin b/.gradle-user/caches/9.7.1/transforms/908077100de65063d637a75d5858f3cc/results.bin new file mode 100644 index 0000000..e7d46e8 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/908077100de65063d637a75d5858f3cc/results.bin @@ -0,0 +1,4 @@ +o/.gradle-instrumented-classpath.marker +o/analysis/instrumentation-hierarchy.bin +o/analysis/instrumentation-dependencies.bin +i/ diff --git a/.gradle-user/caches/9.7.1/transforms/908077100de65063d637a75d5858f3cc/transformed/.gradle-instrumented-classpath.marker b/.gradle-user/caches/9.7.1/transforms/908077100de65063d637a75d5858f3cc/transformed/.gradle-instrumented-classpath.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/908077100de65063d637a75d5858f3cc/transformed/analysis/instrumentation-dependencies.bin b/.gradle-user/caches/9.7.1/transforms/908077100de65063d637a75d5858f3cc/transformed/analysis/instrumentation-dependencies.bin new file mode 100644 index 0000000..848fb48 Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/908077100de65063d637a75d5858f3cc/transformed/analysis/instrumentation-dependencies.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/908077100de65063d637a75d5858f3cc/transformed/analysis/instrumentation-hierarchy.bin b/.gradle-user/caches/9.7.1/transforms/908077100de65063d637a75d5858f3cc/transformed/analysis/instrumentation-hierarchy.bin new file mode 100644 index 0000000..ac88f72 Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/908077100de65063d637a75d5858f3cc/transformed/analysis/instrumentation-hierarchy.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/934e4f354707a1a27b3836b8925947fc/metadata.bin b/.gradle-user/caches/9.7.1/transforms/934e4f354707a1a27b3836b8925947fc/metadata.bin new file mode 100644 index 0000000..e271331 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/934e4f354707a1a27b3836b8925947fc/metadata.bin @@ -0,0 +1 @@ +›wviskalnfjcajntw2rttlz5qli}QÒ¹–K–Y¨_üD/G�outputDirectoryOÕ¿ÖX3“…3±5E‘�ŒresultsFileN‡gª’Tñ|2OYE`æç \ No newline at end of file diff --git a/.gradle-user/caches/9.7.1/transforms/934e4f354707a1a27b3836b8925947fc/results.bin b/.gradle-user/caches/9.7.1/transforms/934e4f354707a1a27b3836b8925947fc/results.bin new file mode 100644 index 0000000..1ed65e0 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/934e4f354707a1a27b3836b8925947fc/results.bin @@ -0,0 +1 @@ +i/ diff --git a/.gradle-user/caches/9.7.1/transforms/9509699d4480248f87cb0d43138c7648/metadata.bin b/.gradle-user/caches/9.7.1/transforms/9509699d4480248f87cb0d43138c7648/metadata.bin new file mode 100644 index 0000000..1aefd60 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/9509699d4480248f87cb0d43138c7648/metadata.bin @@ -0,0 +1,2 @@ +›wviskalnfjcajntw2rttlz5qli�DzUDh¼RüÕ¥ÅÊmw�outputDirectoryþcU¾äONŽ®²¤ÇúŒresultsFile_%¡H“�6 +B‘abm \ No newline at end of file diff --git a/.gradle-user/caches/9.7.1/transforms/9509699d4480248f87cb0d43138c7648/results.bin b/.gradle-user/caches/9.7.1/transforms/9509699d4480248f87cb0d43138c7648/results.bin new file mode 100644 index 0000000..e7d46e8 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/9509699d4480248f87cb0d43138c7648/results.bin @@ -0,0 +1,4 @@ +o/.gradle-instrumented-classpath.marker +o/analysis/instrumentation-hierarchy.bin +o/analysis/instrumentation-dependencies.bin +i/ diff --git a/.gradle-user/caches/9.7.1/transforms/9509699d4480248f87cb0d43138c7648/transformed/.gradle-instrumented-classpath.marker b/.gradle-user/caches/9.7.1/transforms/9509699d4480248f87cb0d43138c7648/transformed/.gradle-instrumented-classpath.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/9509699d4480248f87cb0d43138c7648/transformed/analysis/instrumentation-dependencies.bin b/.gradle-user/caches/9.7.1/transforms/9509699d4480248f87cb0d43138c7648/transformed/analysis/instrumentation-dependencies.bin new file mode 100644 index 0000000..888d7cd Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/9509699d4480248f87cb0d43138c7648/transformed/analysis/instrumentation-dependencies.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/9509699d4480248f87cb0d43138c7648/transformed/analysis/instrumentation-hierarchy.bin b/.gradle-user/caches/9.7.1/transforms/9509699d4480248f87cb0d43138c7648/transformed/analysis/instrumentation-hierarchy.bin new file mode 100644 index 0000000..a86c4a8 Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/9509699d4480248f87cb0d43138c7648/transformed/analysis/instrumentation-hierarchy.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/955fb482d63d679cb709fd78abba1ba0/metadata.bin b/.gradle-user/caches/9.7.1/transforms/955fb482d63d679cb709fd78abba1ba0/metadata.bin new file mode 100644 index 0000000..23383d6 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/955fb482d63d679cb709fd78abba1ba0/metadata.bin @@ -0,0 +1 @@ +›wviskalnfjcajntw2rttlz5qli+4±äDN$éuV(¨ú¬ÛH�outputDirectoryOÕ¿ÖX3“…3±5E‘�ŒresultsFileõq“;¹HW{Ÿ0vû�ÇÆ \ No newline at end of file diff --git a/.gradle-user/caches/9.7.1/transforms/955fb482d63d679cb709fd78abba1ba0/results.bin b/.gradle-user/caches/9.7.1/transforms/955fb482d63d679cb709fd78abba1ba0/results.bin new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/97492d1945cbea8ee3a96d2fb87d0433/metadata.bin b/.gradle-user/caches/9.7.1/transforms/97492d1945cbea8ee3a96d2fb87d0433/metadata.bin new file mode 100644 index 0000000..23cc5dc --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/97492d1945cbea8ee3a96d2fb87d0433/metadata.bin @@ -0,0 +1,3 @@ +›wviskalnfjcajntw2rttlz5qli!4šµqùsi‹–Þ�Œ=Í… +�outputDirectory¶ºÔ9Ñ}žôÑŸÌÐoj…ŒresultsFile_%¡H“�6 +B‘abm \ No newline at end of file diff --git a/.gradle-user/caches/9.7.1/transforms/97492d1945cbea8ee3a96d2fb87d0433/results.bin b/.gradle-user/caches/9.7.1/transforms/97492d1945cbea8ee3a96d2fb87d0433/results.bin new file mode 100644 index 0000000..e7d46e8 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/97492d1945cbea8ee3a96d2fb87d0433/results.bin @@ -0,0 +1,4 @@ +o/.gradle-instrumented-classpath.marker +o/analysis/instrumentation-hierarchy.bin +o/analysis/instrumentation-dependencies.bin +i/ diff --git a/.gradle-user/caches/9.7.1/transforms/97492d1945cbea8ee3a96d2fb87d0433/transformed/.gradle-instrumented-classpath.marker b/.gradle-user/caches/9.7.1/transforms/97492d1945cbea8ee3a96d2fb87d0433/transformed/.gradle-instrumented-classpath.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/97492d1945cbea8ee3a96d2fb87d0433/transformed/analysis/instrumentation-dependencies.bin b/.gradle-user/caches/9.7.1/transforms/97492d1945cbea8ee3a96d2fb87d0433/transformed/analysis/instrumentation-dependencies.bin new file mode 100644 index 0000000..01513b7 Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/97492d1945cbea8ee3a96d2fb87d0433/transformed/analysis/instrumentation-dependencies.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/97492d1945cbea8ee3a96d2fb87d0433/transformed/analysis/instrumentation-hierarchy.bin b/.gradle-user/caches/9.7.1/transforms/97492d1945cbea8ee3a96d2fb87d0433/transformed/analysis/instrumentation-hierarchy.bin new file mode 100644 index 0000000..c4ab4f6 Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/97492d1945cbea8ee3a96d2fb87d0433/transformed/analysis/instrumentation-hierarchy.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/97c474d043d94392571682b40159023c/metadata.bin b/.gradle-user/caches/9.7.1/transforms/97c474d043d94392571682b40159023c/metadata.bin new file mode 100644 index 0000000..d71f719 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/97c474d043d94392571682b40159023c/metadata.bin @@ -0,0 +1 @@ +›wviskalnfjcajntw2rttlz5qli²| Õ12 °èÆ›!‚D�outputDirectory:rôçäí —8TK§õJµŒresultsFile‰oÌ´ÝÌ;Z*Èç'Õ:BÛ \ No newline at end of file diff --git a/.gradle-user/caches/9.7.1/transforms/97c474d043d94392571682b40159023c/results.bin b/.gradle-user/caches/9.7.1/transforms/97c474d043d94392571682b40159023c/results.bin new file mode 100644 index 0000000..783522b --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/97c474d043d94392571682b40159023c/results.bin @@ -0,0 +1,2 @@ +o/.gradle-instrumented-classpath.marker +i/ diff --git a/.gradle-user/caches/9.7.1/transforms/97c474d043d94392571682b40159023c/transformed/.gradle-instrumented-classpath.marker b/.gradle-user/caches/9.7.1/transforms/97c474d043d94392571682b40159023c/transformed/.gradle-instrumented-classpath.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/97d5318bbb9619672d579207bdfc78f8/metadata.bin b/.gradle-user/caches/9.7.1/transforms/97d5318bbb9619672d579207bdfc78f8/metadata.bin new file mode 100644 index 0000000..123a83f --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/97d5318bbb9619672d579207bdfc78f8/metadata.bin @@ -0,0 +1,2 @@ +›wviskalnfjcajntw2rttlz5qli�ÆN¾ LL¨s6Ÿ¬Ô/�outputDirectory}·[B)UnßÿFIé^d·D \ No newline at end of file diff --git a/.gradle-user/caches/9.7.1/transforms/d858bf8fb10c5bd6e27655176df30d72/results.bin b/.gradle-user/caches/9.7.1/transforms/d858bf8fb10c5bd6e27655176df30d72/results.bin new file mode 100644 index 0000000..4ac8774 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/d858bf8fb10c5bd6e27655176df30d72/results.bin @@ -0,0 +1,4 @@ +o/.gradle-instrumented-classpath.marker +o/.gradle-agent-instrumented-external.marker +o/instrumented/instrumented-maven-api-xml-4.0.0-alpha-9.jar +i/ diff --git a/.gradle-user/caches/9.7.1/transforms/d858bf8fb10c5bd6e27655176df30d72/transformed/.gradle-agent-instrumented-external.marker b/.gradle-user/caches/9.7.1/transforms/d858bf8fb10c5bd6e27655176df30d72/transformed/.gradle-agent-instrumented-external.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/d858bf8fb10c5bd6e27655176df30d72/transformed/.gradle-instrumented-classpath.marker b/.gradle-user/caches/9.7.1/transforms/d858bf8fb10c5bd6e27655176df30d72/transformed/.gradle-instrumented-classpath.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/d858bf8fb10c5bd6e27655176df30d72/transformed/instrumented/instrumented-maven-api-xml-4.0.0-alpha-9.jar b/.gradle-user/caches/9.7.1/transforms/d858bf8fb10c5bd6e27655176df30d72/transformed/instrumented/instrumented-maven-api-xml-4.0.0-alpha-9.jar new file mode 100644 index 0000000..541363a Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/d858bf8fb10c5bd6e27655176df30d72/transformed/instrumented/instrumented-maven-api-xml-4.0.0-alpha-9.jar differ diff --git a/.gradle-user/caches/9.7.1/transforms/d97a0cb97009656f98d60a358763d075/metadata.bin b/.gradle-user/caches/9.7.1/transforms/d97a0cb97009656f98d60a358763d075/metadata.bin new file mode 100644 index 0000000..7df697a --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/d97a0cb97009656f98d60a358763d075/metadata.bin @@ -0,0 +1 @@ +›wviskalnfjcajntw2rttlz5qliwµìŠ+_àL1w@°µÊÖ’�outputDirectoryêÔc”À¯~ßAƒzô¼-êŒresultsFile`¯õ±Á¬7�×uH…¡¹Ê \ No newline at end of file diff --git a/.gradle-user/caches/9.7.1/transforms/d97a0cb97009656f98d60a358763d075/results.bin b/.gradle-user/caches/9.7.1/transforms/d97a0cb97009656f98d60a358763d075/results.bin new file mode 100644 index 0000000..bbe19be --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/d97a0cb97009656f98d60a358763d075/results.bin @@ -0,0 +1,2 @@ +o/.gradle-instrumented-classpath.marker +o/merge/instrumentation-dependencies.bin diff --git a/.gradle-user/caches/9.7.1/transforms/d97a0cb97009656f98d60a358763d075/transformed/.gradle-instrumented-classpath.marker b/.gradle-user/caches/9.7.1/transforms/d97a0cb97009656f98d60a358763d075/transformed/.gradle-instrumented-classpath.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/d97a0cb97009656f98d60a358763d075/transformed/merge/instrumentation-dependencies.bin b/.gradle-user/caches/9.7.1/transforms/d97a0cb97009656f98d60a358763d075/transformed/merge/instrumentation-dependencies.bin new file mode 100644 index 0000000..b877063 Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/d97a0cb97009656f98d60a358763d075/transformed/merge/instrumentation-dependencies.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/dbc950ff72c06ef702c0dafee012a4ea/metadata.bin b/.gradle-user/caches/9.7.1/transforms/dbc950ff72c06ef702c0dafee012a4ea/metadata.bin new file mode 100644 index 0000000..ed4bcd4 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/dbc950ff72c06ef702c0dafee012a4ea/metadata.bin @@ -0,0 +1 @@ +›wviskalnfjcajntw2rttlz5qlitE;[»å‹ŸÇy5Õ�outputDirectoryOÕ¿ÖX3“…3±5E‘�ŒresultsFileN‡gª’Tñ|2OYE`æç \ No newline at end of file diff --git a/.gradle-user/caches/9.7.1/transforms/dbc950ff72c06ef702c0dafee012a4ea/results.bin b/.gradle-user/caches/9.7.1/transforms/dbc950ff72c06ef702c0dafee012a4ea/results.bin new file mode 100644 index 0000000..1ed65e0 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/dbc950ff72c06ef702c0dafee012a4ea/results.bin @@ -0,0 +1 @@ +i/ diff --git a/.gradle-user/caches/9.7.1/transforms/e12fbe79b93bafce458ce8f32532d0ca/metadata.bin b/.gradle-user/caches/9.7.1/transforms/e12fbe79b93bafce458ce8f32532d0ca/metadata.bin new file mode 100644 index 0000000..3d7446a Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/e12fbe79b93bafce458ce8f32532d0ca/metadata.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/e12fbe79b93bafce458ce8f32532d0ca/results.bin b/.gradle-user/caches/9.7.1/transforms/e12fbe79b93bafce458ce8f32532d0ca/results.bin new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/e14688b696e60cc1a66e471fbdf6f90d/metadata.bin b/.gradle-user/caches/9.7.1/transforms/e14688b696e60cc1a66e471fbdf6f90d/metadata.bin new file mode 100644 index 0000000..9c1ace5 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/e14688b696e60cc1a66e471fbdf6f90d/metadata.bin @@ -0,0 +1 @@ +›wviskalnfjcajntw2rttlz5qli¡f˜â?!1å`Ó:XqV�outputDirectory­Í0ìûzÿ¥V�; ŒresultsFile¤~†?3D“WüYDI•Féw \ No newline at end of file diff --git a/.gradle-user/caches/9.7.1/transforms/e14688b696e60cc1a66e471fbdf6f90d/results.bin b/.gradle-user/caches/9.7.1/transforms/e14688b696e60cc1a66e471fbdf6f90d/results.bin new file mode 100644 index 0000000..1a06c22 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/e14688b696e60cc1a66e471fbdf6f90d/results.bin @@ -0,0 +1,4 @@ +o/.gradle-instrumented-classpath.marker +o/.gradle-agent-instrumented-external.marker +o/instrumented/instrumented-asm-tree-9.7.1.jar +i/ diff --git a/.gradle-user/caches/9.7.1/transforms/e14688b696e60cc1a66e471fbdf6f90d/transformed/.gradle-agent-instrumented-external.marker b/.gradle-user/caches/9.7.1/transforms/e14688b696e60cc1a66e471fbdf6f90d/transformed/.gradle-agent-instrumented-external.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/e14688b696e60cc1a66e471fbdf6f90d/transformed/.gradle-instrumented-classpath.marker b/.gradle-user/caches/9.7.1/transforms/e14688b696e60cc1a66e471fbdf6f90d/transformed/.gradle-instrumented-classpath.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/e14688b696e60cc1a66e471fbdf6f90d/transformed/instrumented/instrumented-asm-tree-9.7.1.jar b/.gradle-user/caches/9.7.1/transforms/e14688b696e60cc1a66e471fbdf6f90d/transformed/instrumented/instrumented-asm-tree-9.7.1.jar new file mode 100644 index 0000000..9a9c0fb Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/e14688b696e60cc1a66e471fbdf6f90d/transformed/instrumented/instrumented-asm-tree-9.7.1.jar differ diff --git a/.gradle-user/caches/9.7.1/transforms/e6393c4d3865401686169a1a243579b9/metadata.bin b/.gradle-user/caches/9.7.1/transforms/e6393c4d3865401686169a1a243579b9/metadata.bin new file mode 100644 index 0000000..75498c9 Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/e6393c4d3865401686169a1a243579b9/metadata.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/e6393c4d3865401686169a1a243579b9/results.bin b/.gradle-user/caches/9.7.1/transforms/e6393c4d3865401686169a1a243579b9/results.bin new file mode 100644 index 0000000..783522b --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/e6393c4d3865401686169a1a243579b9/results.bin @@ -0,0 +1,2 @@ +o/.gradle-instrumented-classpath.marker +i/ diff --git a/.gradle-user/caches/9.7.1/transforms/e6393c4d3865401686169a1a243579b9/transformed/.gradle-instrumented-classpath.marker b/.gradle-user/caches/9.7.1/transforms/e6393c4d3865401686169a1a243579b9/transformed/.gradle-instrumented-classpath.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/e9b11c7cafa9807ecd3030cc89489710/metadata.bin b/.gradle-user/caches/9.7.1/transforms/e9b11c7cafa9807ecd3030cc89489710/metadata.bin new file mode 100644 index 0000000..7cefd11 Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/e9b11c7cafa9807ecd3030cc89489710/metadata.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/e9b11c7cafa9807ecd3030cc89489710/results.bin b/.gradle-user/caches/9.7.1/transforms/e9b11c7cafa9807ecd3030cc89489710/results.bin new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/f13189d189e3ff50bc3cb21843970c89/metadata.bin b/.gradle-user/caches/9.7.1/transforms/f13189d189e3ff50bc3cb21843970c89/metadata.bin new file mode 100644 index 0000000..e68a67f Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/f13189d189e3ff50bc3cb21843970c89/metadata.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/f13189d189e3ff50bc3cb21843970c89/results.bin b/.gradle-user/caches/9.7.1/transforms/f13189d189e3ff50bc3cb21843970c89/results.bin new file mode 100644 index 0000000..1ed65e0 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/f13189d189e3ff50bc3cb21843970c89/results.bin @@ -0,0 +1 @@ +i/ diff --git a/.gradle-user/caches/9.7.1/transforms/f903870b7ef9fcd59c2e75171f9ef81e/metadata.bin b/.gradle-user/caches/9.7.1/transforms/f903870b7ef9fcd59c2e75171f9ef81e/metadata.bin new file mode 100644 index 0000000..ebf0de6 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/f903870b7ef9fcd59c2e75171f9ef81e/metadata.bin @@ -0,0 +1 @@ +›wviskalnfjcajntw2rttlz5qliQ$vÓÅ�iÄæuÁz¢[ù�outputDirectory ·k¯ü"«JÁþ°·ÍP„6ŒresultsFile:œ6ʺ_ÛŒuoT¼ð \ No newline at end of file diff --git a/.gradle-user/caches/9.7.1/transforms/f903870b7ef9fcd59c2e75171f9ef81e/results.bin b/.gradle-user/caches/9.7.1/transforms/f903870b7ef9fcd59c2e75171f9ef81e/results.bin new file mode 100644 index 0000000..b350a2d --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/f903870b7ef9fcd59c2e75171f9ef81e/results.bin @@ -0,0 +1,4 @@ +o/.gradle-instrumented-classpath.marker +o/.gradle-agent-instrumented-external.marker +o/instrumented/instrumented-commons-io-2.17.0.jar +i/ diff --git a/.gradle-user/caches/9.7.1/transforms/f903870b7ef9fcd59c2e75171f9ef81e/transformed/.gradle-agent-instrumented-external.marker b/.gradle-user/caches/9.7.1/transforms/f903870b7ef9fcd59c2e75171f9ef81e/transformed/.gradle-agent-instrumented-external.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/f903870b7ef9fcd59c2e75171f9ef81e/transformed/.gradle-instrumented-classpath.marker b/.gradle-user/caches/9.7.1/transforms/f903870b7ef9fcd59c2e75171f9ef81e/transformed/.gradle-instrumented-classpath.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/transforms/f903870b7ef9fcd59c2e75171f9ef81e/transformed/instrumented/instrumented-commons-io-2.17.0.jar b/.gradle-user/caches/9.7.1/transforms/f903870b7ef9fcd59c2e75171f9ef81e/transformed/instrumented/instrumented-commons-io-2.17.0.jar new file mode 100644 index 0000000..d723afd Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/f903870b7ef9fcd59c2e75171f9ef81e/transformed/instrumented/instrumented-commons-io-2.17.0.jar differ diff --git a/.gradle-user/caches/9.7.1/transforms/fcaa18a7c894d73e95c75eb3dfbf185f/metadata.bin b/.gradle-user/caches/9.7.1/transforms/fcaa18a7c894d73e95c75eb3dfbf185f/metadata.bin new file mode 100644 index 0000000..ef42a66 Binary files /dev/null and b/.gradle-user/caches/9.7.1/transforms/fcaa18a7c894d73e95c75eb3dfbf185f/metadata.bin differ diff --git a/.gradle-user/caches/9.7.1/transforms/fcaa18a7c894d73e95c75eb3dfbf185f/results.bin b/.gradle-user/caches/9.7.1/transforms/fcaa18a7c894d73e95c75eb3dfbf185f/results.bin new file mode 100644 index 0000000..1ed65e0 --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/fcaa18a7c894d73e95c75eb3dfbf185f/results.bin @@ -0,0 +1 @@ +i/ diff --git a/.gradle-user/caches/9.7.1/transforms/fcd4e90dec2aadfe6bbee4e2d9dda8f1/metadata.bin b/.gradle-user/caches/9.7.1/transforms/fcd4e90dec2aadfe6bbee4e2d9dda8f1/metadata.bin new file mode 100644 index 0000000..792751d --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/fcd4e90dec2aadfe6bbee4e2d9dda8f1/metadata.bin @@ -0,0 +1 @@ +›wviskalnfjcajntw2rttlz5qli¹¤²£Áˆ ²?t§9{ �outputDirectory:rôçäí —8TK§õJµŒresultsFile‰oÌ´ÝÌ;Z*Èç'Õ:BÛ \ No newline at end of file diff --git a/.gradle-user/caches/9.7.1/transforms/fcd4e90dec2aadfe6bbee4e2d9dda8f1/results.bin b/.gradle-user/caches/9.7.1/transforms/fcd4e90dec2aadfe6bbee4e2d9dda8f1/results.bin new file mode 100644 index 0000000..783522b --- /dev/null +++ b/.gradle-user/caches/9.7.1/transforms/fcd4e90dec2aadfe6bbee4e2d9dda8f1/results.bin @@ -0,0 +1,2 @@ +o/.gradle-instrumented-classpath.marker +i/ diff --git a/.gradle-user/caches/9.7.1/transforms/fcd4e90dec2aadfe6bbee4e2d9dda8f1/transformed/.gradle-instrumented-classpath.marker b/.gradle-user/caches/9.7.1/transforms/fcd4e90dec2aadfe6bbee4e2d9dda8f1/transformed/.gradle-instrumented-classpath.marker new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/9.7.1/workerMain/cache.properties b/.gradle-user/caches/9.7.1/workerMain/cache.properties new file mode 100644 index 0000000..42f6e41 --- /dev/null +++ b/.gradle-user/caches/9.7.1/workerMain/cache.properties @@ -0,0 +1 @@ +#Fri Oct 16 08:23:20 EDT 2026 diff --git a/.gradle-user/caches/9.7.1/workerMain/gradle-worker.jar b/.gradle-user/caches/9.7.1/workerMain/gradle-worker.jar new file mode 100644 index 0000000..21b9f62 Binary files /dev/null and b/.gradle-user/caches/9.7.1/workerMain/gradle-worker.jar differ diff --git a/.gradle-user/caches/9.7.1/workerMain/workerMain.lock b/.gradle-user/caches/9.7.1/workerMain/workerMain.lock new file mode 100644 index 0000000..3349915 Binary files /dev/null and b/.gradle-user/caches/9.7.1/workerMain/workerMain.lock differ diff --git a/.gradle-user/caches/CACHEDIR.TAG b/.gradle-user/caches/CACHEDIR.TAG new file mode 100644 index 0000000..c8907d7 --- /dev/null +++ b/.gradle-user/caches/CACHEDIR.TAG @@ -0,0 +1,4 @@ +Signature: 8a477f597d28d172789f06886806bc55 +# This file is a cache directory tag created by Gradle. +# For information about cache directory tags, see: +# https://bford.info/cachedir/ \ No newline at end of file diff --git a/.gradle-user/caches/jars-9/04fffb1b38ebcf18a0d99ee03cff371d/cp_settings.lock b/.gradle-user/caches/jars-9/04fffb1b38ebcf18a0d99ee03cff371d/cp_settings.lock new file mode 100644 index 0000000..35a0387 Binary files /dev/null and b/.gradle-user/caches/jars-9/04fffb1b38ebcf18a0d99ee03cff371d/cp_settings.lock differ diff --git a/.gradle-user/caches/jars-9/04fffb1b38ebcf18a0d99ee03cff371d/cp_settings.receipt b/.gradle-user/caches/jars-9/04fffb1b38ebcf18a0d99ee03cff371d/cp_settings.receipt new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/jars-9/0c505f997612fd1cde196095dbddd85c/proj.lock b/.gradle-user/caches/jars-9/0c505f997612fd1cde196095dbddd85c/proj.lock new file mode 100644 index 0000000..35a0387 Binary files /dev/null and b/.gradle-user/caches/jars-9/0c505f997612fd1cde196095dbddd85c/proj.lock differ diff --git a/.gradle-user/caches/jars-9/0c505f997612fd1cde196095dbddd85c/proj.receipt b/.gradle-user/caches/jars-9/0c505f997612fd1cde196095dbddd85c/proj.receipt new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/jars-9/0c505f997612fd1cde196095dbddd85c/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure1.class b/.gradle-user/caches/jars-9/0c505f997612fd1cde196095dbddd85c/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure1.class new file mode 100644 index 0000000..df8756d Binary files /dev/null and b/.gradle-user/caches/jars-9/0c505f997612fd1cde196095dbddd85c/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure1.class differ diff --git a/.gradle-user/caches/jars-9/0c505f997612fd1cde196095dbddd85c/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure2$_closure7.class b/.gradle-user/caches/jars-9/0c505f997612fd1cde196095dbddd85c/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure2$_closure7.class new file mode 100644 index 0000000..bf2ee77 Binary files /dev/null and b/.gradle-user/caches/jars-9/0c505f997612fd1cde196095dbddd85c/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure2$_closure7.class differ diff --git a/.gradle-user/caches/jars-9/0c505f997612fd1cde196095dbddd85c/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure2.class b/.gradle-user/caches/jars-9/0c505f997612fd1cde196095dbddd85c/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure2.class new file mode 100644 index 0000000..318a16a Binary files /dev/null and b/.gradle-user/caches/jars-9/0c505f997612fd1cde196095dbddd85c/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure2.class differ diff --git a/.gradle-user/caches/jars-9/0c505f997612fd1cde196095dbddd85c/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure3.class b/.gradle-user/caches/jars-9/0c505f997612fd1cde196095dbddd85c/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure3.class new file mode 100644 index 0000000..3d1198f Binary files /dev/null and b/.gradle-user/caches/jars-9/0c505f997612fd1cde196095dbddd85c/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure3.class differ diff --git a/.gradle-user/caches/jars-9/0c505f997612fd1cde196095dbddd85c/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure4$_closure8.class b/.gradle-user/caches/jars-9/0c505f997612fd1cde196095dbddd85c/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure4$_closure8.class new file mode 100644 index 0000000..94f4fcd Binary files /dev/null and b/.gradle-user/caches/jars-9/0c505f997612fd1cde196095dbddd85c/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure4$_closure8.class differ diff --git a/.gradle-user/caches/jars-9/0c505f997612fd1cde196095dbddd85c/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure4$_closure9.class b/.gradle-user/caches/jars-9/0c505f997612fd1cde196095dbddd85c/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure4$_closure9.class new file mode 100644 index 0000000..c956e85 Binary files /dev/null and b/.gradle-user/caches/jars-9/0c505f997612fd1cde196095dbddd85c/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure4$_closure9.class differ diff --git a/.gradle-user/caches/jars-9/0c505f997612fd1cde196095dbddd85c/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure4.class b/.gradle-user/caches/jars-9/0c505f997612fd1cde196095dbddd85c/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure4.class new file mode 100644 index 0000000..6e3fea0 Binary files /dev/null and b/.gradle-user/caches/jars-9/0c505f997612fd1cde196095dbddd85c/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure4.class differ diff --git a/.gradle-user/caches/jars-9/0c505f997612fd1cde196095dbddd85c/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure5.class b/.gradle-user/caches/jars-9/0c505f997612fd1cde196095dbddd85c/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure5.class new file mode 100644 index 0000000..426ceea Binary files /dev/null and b/.gradle-user/caches/jars-9/0c505f997612fd1cde196095dbddd85c/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure5.class differ diff --git a/.gradle-user/caches/jars-9/0c505f997612fd1cde196095dbddd85c/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure6.class b/.gradle-user/caches/jars-9/0c505f997612fd1cde196095dbddd85c/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure6.class new file mode 100644 index 0000000..27c92ee Binary files /dev/null and b/.gradle-user/caches/jars-9/0c505f997612fd1cde196095dbddd85c/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure6.class differ diff --git a/.gradle-user/caches/jars-9/0c505f997612fd1cde196095dbddd85c/proj/build_2kr8jwfs4t5as8ihh83wsqkbp.class b/.gradle-user/caches/jars-9/0c505f997612fd1cde196095dbddd85c/proj/build_2kr8jwfs4t5as8ihh83wsqkbp.class new file mode 100644 index 0000000..b2fd6f2 Binary files /dev/null and b/.gradle-user/caches/jars-9/0c505f997612fd1cde196095dbddd85c/proj/build_2kr8jwfs4t5as8ihh83wsqkbp.class differ diff --git a/.gradle-user/caches/jars-9/674432aa4f94f328086dd98598b91eb5/proj.lock b/.gradle-user/caches/jars-9/674432aa4f94f328086dd98598b91eb5/proj.lock new file mode 100644 index 0000000..35a0387 Binary files /dev/null and b/.gradle-user/caches/jars-9/674432aa4f94f328086dd98598b91eb5/proj.lock differ diff --git a/.gradle-user/caches/jars-9/674432aa4f94f328086dd98598b91eb5/proj.receipt b/.gradle-user/caches/jars-9/674432aa4f94f328086dd98598b91eb5/proj.receipt new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/jars-9/674432aa4f94f328086dd98598b91eb5/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure1.class b/.gradle-user/caches/jars-9/674432aa4f94f328086dd98598b91eb5/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure1.class new file mode 100644 index 0000000..daa445d Binary files /dev/null and b/.gradle-user/caches/jars-9/674432aa4f94f328086dd98598b91eb5/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure1.class differ diff --git a/.gradle-user/caches/jars-9/674432aa4f94f328086dd98598b91eb5/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure2$_closure7.class b/.gradle-user/caches/jars-9/674432aa4f94f328086dd98598b91eb5/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure2$_closure7.class new file mode 100644 index 0000000..5d01fc5 Binary files /dev/null and b/.gradle-user/caches/jars-9/674432aa4f94f328086dd98598b91eb5/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure2$_closure7.class differ diff --git a/.gradle-user/caches/jars-9/674432aa4f94f328086dd98598b91eb5/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure2.class b/.gradle-user/caches/jars-9/674432aa4f94f328086dd98598b91eb5/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure2.class new file mode 100644 index 0000000..e631447 Binary files /dev/null and b/.gradle-user/caches/jars-9/674432aa4f94f328086dd98598b91eb5/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure2.class differ diff --git a/.gradle-user/caches/jars-9/674432aa4f94f328086dd98598b91eb5/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure3.class b/.gradle-user/caches/jars-9/674432aa4f94f328086dd98598b91eb5/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure3.class new file mode 100644 index 0000000..f71c0c5 Binary files /dev/null and b/.gradle-user/caches/jars-9/674432aa4f94f328086dd98598b91eb5/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure3.class differ diff --git a/.gradle-user/caches/jars-9/674432aa4f94f328086dd98598b91eb5/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure4$_closure8.class b/.gradle-user/caches/jars-9/674432aa4f94f328086dd98598b91eb5/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure4$_closure8.class new file mode 100644 index 0000000..69d2152 Binary files /dev/null and b/.gradle-user/caches/jars-9/674432aa4f94f328086dd98598b91eb5/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure4$_closure8.class differ diff --git a/.gradle-user/caches/jars-9/674432aa4f94f328086dd98598b91eb5/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure4$_closure9.class b/.gradle-user/caches/jars-9/674432aa4f94f328086dd98598b91eb5/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure4$_closure9.class new file mode 100644 index 0000000..397222c Binary files /dev/null and b/.gradle-user/caches/jars-9/674432aa4f94f328086dd98598b91eb5/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure4$_closure9.class differ diff --git a/.gradle-user/caches/jars-9/674432aa4f94f328086dd98598b91eb5/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure4.class b/.gradle-user/caches/jars-9/674432aa4f94f328086dd98598b91eb5/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure4.class new file mode 100644 index 0000000..ec8c5a2 Binary files /dev/null and b/.gradle-user/caches/jars-9/674432aa4f94f328086dd98598b91eb5/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure4.class differ diff --git a/.gradle-user/caches/jars-9/674432aa4f94f328086dd98598b91eb5/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure5.class b/.gradle-user/caches/jars-9/674432aa4f94f328086dd98598b91eb5/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure5.class new file mode 100644 index 0000000..9295006 Binary files /dev/null and b/.gradle-user/caches/jars-9/674432aa4f94f328086dd98598b91eb5/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure5.class differ diff --git a/.gradle-user/caches/jars-9/674432aa4f94f328086dd98598b91eb5/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure6.class b/.gradle-user/caches/jars-9/674432aa4f94f328086dd98598b91eb5/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure6.class new file mode 100644 index 0000000..f916121 Binary files /dev/null and b/.gradle-user/caches/jars-9/674432aa4f94f328086dd98598b91eb5/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure6.class differ diff --git a/.gradle-user/caches/jars-9/674432aa4f94f328086dd98598b91eb5/proj/build_2kr8jwfs4t5as8ihh83wsqkbp.class b/.gradle-user/caches/jars-9/674432aa4f94f328086dd98598b91eb5/proj/build_2kr8jwfs4t5as8ihh83wsqkbp.class new file mode 100644 index 0000000..60afb64 Binary files /dev/null and b/.gradle-user/caches/jars-9/674432aa4f94f328086dd98598b91eb5/proj/build_2kr8jwfs4t5as8ihh83wsqkbp.class differ diff --git a/.gradle-user/caches/jars-9/68a806a8f0f4b78b77f46c7124ccac52/cp_proj.lock b/.gradle-user/caches/jars-9/68a806a8f0f4b78b77f46c7124ccac52/cp_proj.lock new file mode 100644 index 0000000..35a0387 Binary files /dev/null and b/.gradle-user/caches/jars-9/68a806a8f0f4b78b77f46c7124ccac52/cp_proj.lock differ diff --git a/.gradle-user/caches/jars-9/68a806a8f0f4b78b77f46c7124ccac52/cp_proj.receipt b/.gradle-user/caches/jars-9/68a806a8f0f4b78b77f46c7124ccac52/cp_proj.receipt new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/jars-9/68a806a8f0f4b78b77f46c7124ccac52/cp_proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure1.class b/.gradle-user/caches/jars-9/68a806a8f0f4b78b77f46c7124ccac52/cp_proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure1.class new file mode 100644 index 0000000..38d9de1 Binary files /dev/null and b/.gradle-user/caches/jars-9/68a806a8f0f4b78b77f46c7124ccac52/cp_proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure1.class differ diff --git a/.gradle-user/caches/jars-9/68a806a8f0f4b78b77f46c7124ccac52/cp_proj/build_2kr8jwfs4t5as8ihh83wsqkbp.class b/.gradle-user/caches/jars-9/68a806a8f0f4b78b77f46c7124ccac52/cp_proj/build_2kr8jwfs4t5as8ihh83wsqkbp.class new file mode 100644 index 0000000..1437245 Binary files /dev/null and b/.gradle-user/caches/jars-9/68a806a8f0f4b78b77f46c7124ccac52/cp_proj/build_2kr8jwfs4t5as8ihh83wsqkbp.class differ diff --git a/.gradle-user/caches/jars-9/cef7b0ab5bc031fcf9926baaa2fee1f5/cp_proj.lock b/.gradle-user/caches/jars-9/cef7b0ab5bc031fcf9926baaa2fee1f5/cp_proj.lock new file mode 100644 index 0000000..35a0387 Binary files /dev/null and b/.gradle-user/caches/jars-9/cef7b0ab5bc031fcf9926baaa2fee1f5/cp_proj.lock differ diff --git a/.gradle-user/caches/jars-9/cef7b0ab5bc031fcf9926baaa2fee1f5/cp_proj.receipt b/.gradle-user/caches/jars-9/cef7b0ab5bc031fcf9926baaa2fee1f5/cp_proj.receipt new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/jars-9/cef7b0ab5bc031fcf9926baaa2fee1f5/cp_proj/build_ddn08u2z04676kk1cqo8uw7ob$_run_closure1.class b/.gradle-user/caches/jars-9/cef7b0ab5bc031fcf9926baaa2fee1f5/cp_proj/build_ddn08u2z04676kk1cqo8uw7ob$_run_closure1.class new file mode 100644 index 0000000..b49f166 Binary files /dev/null and b/.gradle-user/caches/jars-9/cef7b0ab5bc031fcf9926baaa2fee1f5/cp_proj/build_ddn08u2z04676kk1cqo8uw7ob$_run_closure1.class differ diff --git a/.gradle-user/caches/jars-9/cef7b0ab5bc031fcf9926baaa2fee1f5/cp_proj/build_ddn08u2z04676kk1cqo8uw7ob.class b/.gradle-user/caches/jars-9/cef7b0ab5bc031fcf9926baaa2fee1f5/cp_proj/build_ddn08u2z04676kk1cqo8uw7ob.class new file mode 100644 index 0000000..233bcf9 Binary files /dev/null and b/.gradle-user/caches/jars-9/cef7b0ab5bc031fcf9926baaa2fee1f5/cp_proj/build_ddn08u2z04676kk1cqo8uw7ob.class differ diff --git a/.gradle-user/caches/jars-9/df1542747197b2dbc6752ae6d8a27ce0/proj.lock b/.gradle-user/caches/jars-9/df1542747197b2dbc6752ae6d8a27ce0/proj.lock new file mode 100644 index 0000000..35a0387 Binary files /dev/null and b/.gradle-user/caches/jars-9/df1542747197b2dbc6752ae6d8a27ce0/proj.lock differ diff --git a/.gradle-user/caches/jars-9/df1542747197b2dbc6752ae6d8a27ce0/proj.receipt b/.gradle-user/caches/jars-9/df1542747197b2dbc6752ae6d8a27ce0/proj.receipt new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/jars-9/df1542747197b2dbc6752ae6d8a27ce0/proj/build_ddn08u2z04676kk1cqo8uw7ob$_run_closure1.class b/.gradle-user/caches/jars-9/df1542747197b2dbc6752ae6d8a27ce0/proj/build_ddn08u2z04676kk1cqo8uw7ob$_run_closure1.class new file mode 100644 index 0000000..a8ec4df Binary files /dev/null and b/.gradle-user/caches/jars-9/df1542747197b2dbc6752ae6d8a27ce0/proj/build_ddn08u2z04676kk1cqo8uw7ob$_run_closure1.class differ diff --git a/.gradle-user/caches/jars-9/df1542747197b2dbc6752ae6d8a27ce0/proj/build_ddn08u2z04676kk1cqo8uw7ob$_run_closure2.class b/.gradle-user/caches/jars-9/df1542747197b2dbc6752ae6d8a27ce0/proj/build_ddn08u2z04676kk1cqo8uw7ob$_run_closure2.class new file mode 100644 index 0000000..a86cb0e Binary files /dev/null and b/.gradle-user/caches/jars-9/df1542747197b2dbc6752ae6d8a27ce0/proj/build_ddn08u2z04676kk1cqo8uw7ob$_run_closure2.class differ diff --git a/.gradle-user/caches/jars-9/df1542747197b2dbc6752ae6d8a27ce0/proj/build_ddn08u2z04676kk1cqo8uw7ob$_run_closure3.class b/.gradle-user/caches/jars-9/df1542747197b2dbc6752ae6d8a27ce0/proj/build_ddn08u2z04676kk1cqo8uw7ob$_run_closure3.class new file mode 100644 index 0000000..1b7f555 Binary files /dev/null and b/.gradle-user/caches/jars-9/df1542747197b2dbc6752ae6d8a27ce0/proj/build_ddn08u2z04676kk1cqo8uw7ob$_run_closure3.class differ diff --git a/.gradle-user/caches/jars-9/df1542747197b2dbc6752ae6d8a27ce0/proj/build_ddn08u2z04676kk1cqo8uw7ob.class b/.gradle-user/caches/jars-9/df1542747197b2dbc6752ae6d8a27ce0/proj/build_ddn08u2z04676kk1cqo8uw7ob.class new file mode 100644 index 0000000..524071c Binary files /dev/null and b/.gradle-user/caches/jars-9/df1542747197b2dbc6752ae6d8a27ce0/proj/build_ddn08u2z04676kk1cqo8uw7ob.class differ diff --git a/.gradle-user/caches/jars-9/f7127376ec910ee78496f44838eebab4/proj.lock b/.gradle-user/caches/jars-9/f7127376ec910ee78496f44838eebab4/proj.lock new file mode 100644 index 0000000..35a0387 Binary files /dev/null and b/.gradle-user/caches/jars-9/f7127376ec910ee78496f44838eebab4/proj.lock differ diff --git a/.gradle-user/caches/jars-9/f7127376ec910ee78496f44838eebab4/proj.receipt b/.gradle-user/caches/jars-9/f7127376ec910ee78496f44838eebab4/proj.receipt new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/jars-9/f7127376ec910ee78496f44838eebab4/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure1$_closure6.class b/.gradle-user/caches/jars-9/f7127376ec910ee78496f44838eebab4/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure1$_closure6.class new file mode 100644 index 0000000..304589b Binary files /dev/null and b/.gradle-user/caches/jars-9/f7127376ec910ee78496f44838eebab4/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure1$_closure6.class differ diff --git a/.gradle-user/caches/jars-9/f7127376ec910ee78496f44838eebab4/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure1.class b/.gradle-user/caches/jars-9/f7127376ec910ee78496f44838eebab4/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure1.class new file mode 100644 index 0000000..897a0c1 Binary files /dev/null and b/.gradle-user/caches/jars-9/f7127376ec910ee78496f44838eebab4/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure1.class differ diff --git a/.gradle-user/caches/jars-9/f7127376ec910ee78496f44838eebab4/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure2.class b/.gradle-user/caches/jars-9/f7127376ec910ee78496f44838eebab4/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure2.class new file mode 100644 index 0000000..f19152f Binary files /dev/null and b/.gradle-user/caches/jars-9/f7127376ec910ee78496f44838eebab4/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure2.class differ diff --git a/.gradle-user/caches/jars-9/f7127376ec910ee78496f44838eebab4/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure3$_closure7.class b/.gradle-user/caches/jars-9/f7127376ec910ee78496f44838eebab4/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure3$_closure7.class new file mode 100644 index 0000000..c549664 Binary files /dev/null and b/.gradle-user/caches/jars-9/f7127376ec910ee78496f44838eebab4/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure3$_closure7.class differ diff --git a/.gradle-user/caches/jars-9/f7127376ec910ee78496f44838eebab4/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure3$_closure8.class b/.gradle-user/caches/jars-9/f7127376ec910ee78496f44838eebab4/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure3$_closure8.class new file mode 100644 index 0000000..6ae3c69 Binary files /dev/null and b/.gradle-user/caches/jars-9/f7127376ec910ee78496f44838eebab4/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure3$_closure8.class differ diff --git a/.gradle-user/caches/jars-9/f7127376ec910ee78496f44838eebab4/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure3.class b/.gradle-user/caches/jars-9/f7127376ec910ee78496f44838eebab4/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure3.class new file mode 100644 index 0000000..dc71ad1 Binary files /dev/null and b/.gradle-user/caches/jars-9/f7127376ec910ee78496f44838eebab4/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure3.class differ diff --git a/.gradle-user/caches/jars-9/f7127376ec910ee78496f44838eebab4/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure4.class b/.gradle-user/caches/jars-9/f7127376ec910ee78496f44838eebab4/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure4.class new file mode 100644 index 0000000..d466a95 Binary files /dev/null and b/.gradle-user/caches/jars-9/f7127376ec910ee78496f44838eebab4/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure4.class differ diff --git a/.gradle-user/caches/jars-9/f7127376ec910ee78496f44838eebab4/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure5.class b/.gradle-user/caches/jars-9/f7127376ec910ee78496f44838eebab4/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure5.class new file mode 100644 index 0000000..ac47d07 Binary files /dev/null and b/.gradle-user/caches/jars-9/f7127376ec910ee78496f44838eebab4/proj/build_2kr8jwfs4t5as8ihh83wsqkbp$_run_closure5.class differ diff --git a/.gradle-user/caches/jars-9/f7127376ec910ee78496f44838eebab4/proj/build_2kr8jwfs4t5as8ihh83wsqkbp.class b/.gradle-user/caches/jars-9/f7127376ec910ee78496f44838eebab4/proj/build_2kr8jwfs4t5as8ihh83wsqkbp.class new file mode 100644 index 0000000..18e190c Binary files /dev/null and b/.gradle-user/caches/jars-9/f7127376ec910ee78496f44838eebab4/proj/build_2kr8jwfs4t5as8ihh83wsqkbp.class differ diff --git a/.gradle-user/caches/jars-9/f85124445344ae330c12fe5cb6c64722/settings.lock b/.gradle-user/caches/jars-9/f85124445344ae330c12fe5cb6c64722/settings.lock new file mode 100644 index 0000000..35a0387 Binary files /dev/null and b/.gradle-user/caches/jars-9/f85124445344ae330c12fe5cb6c64722/settings.lock differ diff --git a/.gradle-user/caches/jars-9/f85124445344ae330c12fe5cb6c64722/settings.receipt b/.gradle-user/caches/jars-9/f85124445344ae330c12fe5cb6c64722/settings.receipt new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/jars-9/f85124445344ae330c12fe5cb6c64722/settings/settings_3mnlxns4eg327qlxsyy8tof5s.class b/.gradle-user/caches/jars-9/f85124445344ae330c12fe5cb6c64722/settings/settings_3mnlxns4eg327qlxsyy8tof5s.class new file mode 100644 index 0000000..9bea35c Binary files /dev/null and b/.gradle-user/caches/jars-9/f85124445344ae330c12fe5cb6c64722/settings/settings_3mnlxns4eg327qlxsyy8tof5s.class differ diff --git a/.gradle-user/caches/jars-9/gc.properties b/.gradle-user/caches/jars-9/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/jars-9/jars-9.lock b/.gradle-user/caches/jars-9/jars-9.lock new file mode 100644 index 0000000..f6a02e4 Binary files /dev/null and b/.gradle-user/caches/jars-9/jars-9.lock differ diff --git a/.gradle-user/caches/journal-1/file-access.bin b/.gradle-user/caches/journal-1/file-access.bin new file mode 100644 index 0000000..ff03d6d Binary files /dev/null and b/.gradle-user/caches/journal-1/file-access.bin differ diff --git a/.gradle-user/caches/journal-1/file-access.properties b/.gradle-user/caches/journal-1/file-access.properties new file mode 100644 index 0000000..78ae511 --- /dev/null +++ b/.gradle-user/caches/journal-1/file-access.properties @@ -0,0 +1,2 @@ +#Fri Oct 16 08:22:42 EDT 2026 +inceptionTimestamp=1792153362085 diff --git a/.gradle-user/caches/journal-1/journal-1.lock b/.gradle-user/caches/journal-1/journal-1.lock new file mode 100644 index 0000000..f0fe687 Binary files /dev/null and b/.gradle-user/caches/journal-1/journal-1.lock differ diff --git a/.gradle-user/caches/modules-2/files-2.1/com.android.tools.smali/smali-baksmali/3.0.9/101848b962f9201ec4e299adfff3b938867ffec8/smali-baksmali-3.0.9.pom b/.gradle-user/caches/modules-2/files-2.1/com.android.tools.smali/smali-baksmali/3.0.9/101848b962f9201ec4e299adfff3b938867ffec8/smali-baksmali-3.0.9.pom new file mode 100644 index 0000000..148267f --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/com.android.tools.smali/smali-baksmali/3.0.9/101848b962f9201ec4e299adfff3b938867ffec8/smali-baksmali-3.0.9.pom @@ -0,0 +1,64 @@ + + + + + + + + 4.0.0 + com.android.tools.smali + smali-baksmali + 3.0.9 + baksmali + baksmali is a disassembler for dalvik bytecode + https://github.com/google/smali + + + The BSD 3-Clause License + http://opensource.org/licenses/BSD-3-Clause + repo + + + + + jesusfreke + Ben Gruver + jesusfreke@jesusfreke.com + + + The Android Open Source Project + + + + scm:git:git://github.com/google/smali.git + scm:git:git@github.com:google/smali.git + https://github.com/google/smali/tree/master/baksmali + + + + com.android.tools.smali + smali-dexlib2 + 3.0.9 + compile + + + com.android.tools.smali + smali-util + 3.0.9 + runtime + + + com.google.guava + guava + 31.1-android + runtime + + + com.beust + jcommander + 1.64 + runtime + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/com.android.tools.smali/smali-baksmali/3.0.9/469631b1faf10e1537aea8d4b451a1e239a9fea1/smali-baksmali-3.0.9.module b/.gradle-user/caches/modules-2/files-2.1/com.android.tools.smali/smali-baksmali/3.0.9/469631b1faf10e1537aea8d4b451a1e239a9fea1/smali-baksmali-3.0.9.module new file mode 100644 index 0000000..6bdf909 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/com.android.tools.smali/smali-baksmali/3.0.9/469631b1faf10e1537aea8d4b451a1e239a9fea1/smali-baksmali-3.0.9.module @@ -0,0 +1,139 @@ +{ + "formatVersion": "1.1", + "component": { + "group": "com.android.tools.smali", + "module": "smali-baksmali", + "version": "3.0.9", + "attributes": { + "org.gradle.status": "release" + } + }, + "createdBy": { + "gradle": { + "version": "8.5" + } + }, + "variants": [ + { + "name": "apiElements", + "attributes": { + "org.gradle.category": "library", + "org.gradle.dependency.bundling": "external", + "org.gradle.jvm.version": 8, + "org.gradle.libraryelements": "jar", + "org.gradle.usage": "java-api" + }, + "dependencies": [ + { + "group": "com.android.tools.smali", + "module": "smali-dexlib2", + "version": { + "requires": "3.0.9" + } + } + ], + "files": [ + { + "name": "smali-baksmali-3.0.9.jar", + "url": "smali-baksmali-3.0.9.jar", + "size": 132972, + "sha512": "3855af3ae6993304e01e0de946fb43393937af733125e01dd7fd793cf281a34ecf66e89e5ee3325ac7105fd4766b7cc9988f5976202a487b8fa612b7c9147ae7", + "sha256": "e7d0166945565a87f3997d1aea8779202dbb6cb0585a39ee20bab8a2f5ba87f6", + "sha1": "7cb3b3026b4fdf178bad1ac48f235fe41147561a", + "md5": "a1e33c9190604be88737325eb63e912d" + } + ] + }, + { + "name": "runtimeElements", + "attributes": { + "org.gradle.category": "library", + "org.gradle.dependency.bundling": "external", + "org.gradle.jvm.version": 8, + "org.gradle.libraryelements": "jar", + "org.gradle.usage": "java-runtime" + }, + "dependencies": [ + { + "group": "com.android.tools.smali", + "module": "smali-util", + "version": { + "requires": "3.0.9" + } + }, + { + "group": "com.google.guava", + "module": "guava", + "version": { + "requires": "31.1-android" + } + }, + { + "group": "com.beust", + "module": "jcommander", + "version": { + "requires": "1.64" + } + }, + { + "group": "com.android.tools.smali", + "module": "smali-dexlib2", + "version": { + "requires": "3.0.9" + } + } + ], + "files": [ + { + "name": "smali-baksmali-3.0.9.jar", + "url": "smali-baksmali-3.0.9.jar", + "size": 132972, + "sha512": "3855af3ae6993304e01e0de946fb43393937af733125e01dd7fd793cf281a34ecf66e89e5ee3325ac7105fd4766b7cc9988f5976202a487b8fa612b7c9147ae7", + "sha256": "e7d0166945565a87f3997d1aea8779202dbb6cb0585a39ee20bab8a2f5ba87f6", + "sha1": "7cb3b3026b4fdf178bad1ac48f235fe41147561a", + "md5": "a1e33c9190604be88737325eb63e912d" + } + ] + }, + { + "name": "javadocElements", + "attributes": { + "org.gradle.category": "documentation", + "org.gradle.dependency.bundling": "external", + "org.gradle.docstype": "javadoc", + "org.gradle.usage": "java-runtime" + }, + "files": [ + { + "name": "smali-baksmali-3.0.9-javadoc.jar", + "url": "smali-baksmali-3.0.9-javadoc.jar", + "size": 610370, + "sha512": "52afd72c344095da38edb768a339a1e8cd28b8783f613295093ce2ffd13cbd1d6afd472da6b8b113f899ef54bafead86f0e92a73728806472de60c6cccb236d3", + "sha256": "7f2abb2b711363ef1ba1d62bc6ce0214889f6277bfd493900fb5a9359f79c08d", + "sha1": "2b635099937c5eba22d61e576d810e7fec6a2e2e", + "md5": "79e66342d553510b01ba87992385bf68" + } + ] + }, + { + "name": "sourcesElements", + "attributes": { + "org.gradle.category": "documentation", + "org.gradle.dependency.bundling": "external", + "org.gradle.docstype": "sources", + "org.gradle.usage": "java-runtime" + }, + "files": [ + { + "name": "smali-baksmali-3.0.9-sources.jar", + "url": "smali-baksmali-3.0.9-sources.jar", + "size": 107498, + "sha512": "1754692037349fa030425f6c9b896d9678c068a78a4caf4daea95a8988ccf17f6b0b5e1747202d8dfa8998ffe00fb0609e0912bff8fb41ac7137f50f0b55cdad", + "sha256": "cb4a168ad787687ce2f0d9f4f258569c57cc0754aa447df538cb1f6b66c0459f", + "sha1": "377f3c01444143bf3cccc91c42ca6b68d6262825", + "md5": "6db814788b3f261e22f51210328d9995" + } + ] + } + ] +} diff --git a/.gradle-user/caches/modules-2/files-2.1/com.android.tools.smali/smali-baksmali/3.0.9/7cb3b3026b4fdf178bad1ac48f235fe41147561a/smali-baksmali-3.0.9.jar b/.gradle-user/caches/modules-2/files-2.1/com.android.tools.smali/smali-baksmali/3.0.9/7cb3b3026b4fdf178bad1ac48f235fe41147561a/smali-baksmali-3.0.9.jar new file mode 100644 index 0000000..2a0b138 Binary files /dev/null and b/.gradle-user/caches/modules-2/files-2.1/com.android.tools.smali/smali-baksmali/3.0.9/7cb3b3026b4fdf178bad1ac48f235fe41147561a/smali-baksmali-3.0.9.jar differ diff --git a/.gradle-user/caches/modules-2/files-2.1/com.android.tools.smali/smali-dexlib2/3.0.9/6b79a7f75afdf4f63e624943d3fb4d79f810b800/smali-dexlib2-3.0.9.pom b/.gradle-user/caches/modules-2/files-2.1/com.android.tools.smali/smali-dexlib2/3.0.9/6b79a7f75afdf4f63e624943d3fb4d79f810b800/smali-dexlib2-3.0.9.pom new file mode 100644 index 0000000..7ef3a5c --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/com.android.tools.smali/smali-dexlib2/3.0.9/6b79a7f75afdf4f63e624943d3fb4d79f810b800/smali-dexlib2-3.0.9.pom @@ -0,0 +1,52 @@ + + + + + + + + 4.0.0 + com.android.tools.smali + smali-dexlib2 + 3.0.9 + dexlib2 + dexlib2 is a library for reading/modifying/writing Android dex files + https://github.com/google/smali + + + The BSD 3-Clause License + http://opensource.org/licenses/BSD-3-Clause + repo + + + + + jesusfreke + Ben Gruver + jesusfreke@jesusfreke.com + + + The Android Open Source Project + + + + scm:git:git://github.com/google/smali.git + scm:git:git@github.com:google/smali.git + https://github.com/google/smali/tree/master/dexlib2 + + + + com.google.code.findbugs + jsr305 + 3.0.2 + runtime + + + com.google.guava + guava + 31.1-android + runtime + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/com.android.tools.smali/smali-dexlib2/3.0.9/be55626f7b94756a30c484b3ce37ed410f74e626/smali-dexlib2-3.0.9.module b/.gradle-user/caches/modules-2/files-2.1/com.android.tools.smali/smali-dexlib2/3.0.9/be55626f7b94756a30c484b3ce37ed410f74e626/smali-dexlib2-3.0.9.module new file mode 100644 index 0000000..b872460 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/com.android.tools.smali/smali-dexlib2/3.0.9/be55626f7b94756a30c484b3ce37ed410f74e626/smali-dexlib2-3.0.9.module @@ -0,0 +1,116 @@ +{ + "formatVersion": "1.1", + "component": { + "group": "com.android.tools.smali", + "module": "smali-dexlib2", + "version": "3.0.9", + "attributes": { + "org.gradle.status": "release" + } + }, + "createdBy": { + "gradle": { + "version": "8.5" + } + }, + "variants": [ + { + "name": "apiElements", + "attributes": { + "org.gradle.category": "library", + "org.gradle.dependency.bundling": "external", + "org.gradle.jvm.version": 8, + "org.gradle.libraryelements": "jar", + "org.gradle.usage": "java-api" + }, + "files": [ + { + "name": "smali-dexlib2-3.0.9.jar", + "url": "smali-dexlib2-3.0.9.jar", + "size": 1194123, + "sha512": "ddf07c5e8c5fe355ffdfcd16a76a82df68ba60107d98f44cab815505f7cdf40def788ee1780e6c7d8812ad6e9983658b21f8bec587a62577816d63681bf94ec9", + "sha256": "8b547506f62f91d74b70f4beb4989b99e1ff61fc50b2525e9796ca35f0a351dc", + "sha1": "ce8ab6d577bf076a67614c92157e92122b539dc3", + "md5": "741f4430bd71f6c14450dd16184cd659" + } + ] + }, + { + "name": "runtimeElements", + "attributes": { + "org.gradle.category": "library", + "org.gradle.dependency.bundling": "external", + "org.gradle.jvm.version": 8, + "org.gradle.libraryelements": "jar", + "org.gradle.usage": "java-runtime" + }, + "dependencies": [ + { + "group": "com.google.code.findbugs", + "module": "jsr305", + "version": { + "requires": "3.0.2" + } + }, + { + "group": "com.google.guava", + "module": "guava", + "version": { + "requires": "31.1-android" + } + } + ], + "files": [ + { + "name": "smali-dexlib2-3.0.9.jar", + "url": "smali-dexlib2-3.0.9.jar", + "size": 1194123, + "sha512": "ddf07c5e8c5fe355ffdfcd16a76a82df68ba60107d98f44cab815505f7cdf40def788ee1780e6c7d8812ad6e9983658b21f8bec587a62577816d63681bf94ec9", + "sha256": "8b547506f62f91d74b70f4beb4989b99e1ff61fc50b2525e9796ca35f0a351dc", + "sha1": "ce8ab6d577bf076a67614c92157e92122b539dc3", + "md5": "741f4430bd71f6c14450dd16184cd659" + } + ] + }, + { + "name": "javadocElements", + "attributes": { + "org.gradle.category": "documentation", + "org.gradle.dependency.bundling": "external", + "org.gradle.docstype": "javadoc", + "org.gradle.usage": "java-runtime" + }, + "files": [ + { + "name": "smali-dexlib2-3.0.9-javadoc.jar", + "url": "smali-dexlib2-3.0.9-javadoc.jar", + "size": 2963290, + "sha512": "7fd7ad66e1718aa4e65ad1994d957c11e899cf3f703132b0388c6806308cfe8722aa169bfdcd4f059692c8c77c4ea47e84aa88738d6089476623a0bf1fcb0ce5", + "sha256": "594b03df9e5d712d9e209aedea89d63ac0d0cc11590f1218f898590290d8b65d", + "sha1": "787e77817ad9dde5789a96e6f345cf5cbb781478", + "md5": "4d261bee58b9bea16bdc3239e0d3f81d" + } + ] + }, + { + "name": "sourcesElements", + "attributes": { + "org.gradle.category": "documentation", + "org.gradle.dependency.bundling": "external", + "org.gradle.docstype": "sources", + "org.gradle.usage": "java-runtime" + }, + "files": [ + { + "name": "smali-dexlib2-3.0.9-sources.jar", + "url": "smali-dexlib2-3.0.9-sources.jar", + "size": 1007281, + "sha512": "f739a78a38c038a85ac40324652a19d4c50b5b70b8356916863fde432f6e94b4469e451749906fcdbb01a5906ca0fe895a30cbf4641f66a72fe3c043c30d1ebb", + "sha256": "7834c32d5bb59f68ce28243fec0e92242f1ca55302c9dfb012bb23000b888ef1", + "sha1": "42329e732d059d28ea5da00c2a89feef4c9ec2f3", + "md5": "715990819eebb13a0a7101b9b503f735" + } + ] + } + ] +} diff --git a/.gradle-user/caches/modules-2/files-2.1/com.android.tools.smali/smali-dexlib2/3.0.9/ce8ab6d577bf076a67614c92157e92122b539dc3/smali-dexlib2-3.0.9.jar b/.gradle-user/caches/modules-2/files-2.1/com.android.tools.smali/smali-dexlib2/3.0.9/ce8ab6d577bf076a67614c92157e92122b539dc3/smali-dexlib2-3.0.9.jar new file mode 100644 index 0000000..56a234d Binary files /dev/null and b/.gradle-user/caches/modules-2/files-2.1/com.android.tools.smali/smali-dexlib2/3.0.9/ce8ab6d577bf076a67614c92157e92122b539dc3/smali-dexlib2-3.0.9.jar differ diff --git a/.gradle-user/caches/modules-2/files-2.1/com.android.tools.smali/smali-util/3.0.9/801b6895a7625dadb4f1c5119bc573868b463bcc/smali-util-3.0.9.pom b/.gradle-user/caches/modules-2/files-2.1/com.android.tools.smali/smali-util/3.0.9/801b6895a7625dadb4f1c5119bc573868b463bcc/smali-util-3.0.9.pom new file mode 100644 index 0000000..79b4edc --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/com.android.tools.smali/smali-util/3.0.9/801b6895a7625dadb4f1c5119bc573868b463bcc/smali-util-3.0.9.pom @@ -0,0 +1,64 @@ + + + + + + + + 4.0.0 + com.android.tools.smali + smali-util + 3.0.9 + util + This library contains random utilities used by smali/baksmali/dexlib2 + https://github.com/google/smali + + + The BSD 3-Clause License + http://opensource.org/licenses/BSD-3-Clause + repo + + + + + jesusfreke + Ben Gruver + jesusfreke@jesusfreke.com + + + The Android Open Source Project + + + + scm:git:git://github.com/google/smali.git + scm:git:git@github.com:google/smali.git + https://github.com/google/smali/tree/master/util + + + + com.android.tools.smali + smali-dexlib2 + 3.0.9 + runtime + + + com.google.code.findbugs + jsr305 + 3.0.2 + runtime + + + com.google.guava + guava + 31.1-android + runtime + + + com.beust + jcommander + 1.64 + runtime + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/com.android.tools.smali/smali-util/3.0.9/b8ecded9573ff8e1b9df2ab9ade0785cd2da1ea/smali-util-3.0.9.module b/.gradle-user/caches/modules-2/files-2.1/com.android.tools.smali/smali-util/3.0.9/b8ecded9573ff8e1b9df2ab9ade0785cd2da1ea/smali-util-3.0.9.module new file mode 100644 index 0000000..9f37a50 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/com.android.tools.smali/smali-util/3.0.9/b8ecded9573ff8e1b9df2ab9ade0785cd2da1ea/smali-util-3.0.9.module @@ -0,0 +1,130 @@ +{ + "formatVersion": "1.1", + "component": { + "group": "com.android.tools.smali", + "module": "smali-util", + "version": "3.0.9", + "attributes": { + "org.gradle.status": "release" + } + }, + "createdBy": { + "gradle": { + "version": "8.5" + } + }, + "variants": [ + { + "name": "apiElements", + "attributes": { + "org.gradle.category": "library", + "org.gradle.dependency.bundling": "external", + "org.gradle.jvm.version": 8, + "org.gradle.libraryelements": "jar", + "org.gradle.usage": "java-api" + }, + "files": [ + { + "name": "smali-util-3.0.9.jar", + "url": "smali-util-3.0.9.jar", + "size": 33331, + "sha512": "bf177d9bc0983d1ac3255c23fc1f60f830b5fc08164c22e62f2dc9d33bd3eb55b9dd9f2871633244d85be6082806b43809e5b79b72c37099377b850df7d88e4b", + "sha256": "4673762894ba4156081fc5c642f74d6e78aef8b1a9c7702d691e3171d8cc1153", + "sha1": "0ec9105899e5634ef710454bdd7102cea9c8565b", + "md5": "a8e44f62fea1f401f021ef174ab8ed6b" + } + ] + }, + { + "name": "runtimeElements", + "attributes": { + "org.gradle.category": "library", + "org.gradle.dependency.bundling": "external", + "org.gradle.jvm.version": 8, + "org.gradle.libraryelements": "jar", + "org.gradle.usage": "java-runtime" + }, + "dependencies": [ + { + "group": "com.android.tools.smali", + "module": "smali-dexlib2", + "version": { + "requires": "3.0.9" + } + }, + { + "group": "com.google.code.findbugs", + "module": "jsr305", + "version": { + "requires": "3.0.2" + } + }, + { + "group": "com.google.guava", + "module": "guava", + "version": { + "requires": "31.1-android" + } + }, + { + "group": "com.beust", + "module": "jcommander", + "version": { + "requires": "1.64" + } + } + ], + "files": [ + { + "name": "smali-util-3.0.9.jar", + "url": "smali-util-3.0.9.jar", + "size": 33331, + "sha512": "bf177d9bc0983d1ac3255c23fc1f60f830b5fc08164c22e62f2dc9d33bd3eb55b9dd9f2871633244d85be6082806b43809e5b79b72c37099377b850df7d88e4b", + "sha256": "4673762894ba4156081fc5c642f74d6e78aef8b1a9c7702d691e3171d8cc1153", + "sha1": "0ec9105899e5634ef710454bdd7102cea9c8565b", + "md5": "a8e44f62fea1f401f021ef174ab8ed6b" + } + ] + }, + { + "name": "javadocElements", + "attributes": { + "org.gradle.category": "documentation", + "org.gradle.dependency.bundling": "external", + "org.gradle.docstype": "javadoc", + "org.gradle.usage": "java-runtime" + }, + "files": [ + { + "name": "smali-util-3.0.9-javadoc.jar", + "url": "smali-util-3.0.9-javadoc.jar", + "size": 430697, + "sha512": "ade0787afe3f06b01be2e7b70ce66c331fa50cdf44fbb9ee562b799ea9c087ea6ac138923c73a6c74c981a5f038ab2454183d574c3ac79806fc849738d2e90eb", + "sha256": "52e19adc3c7c71a8409bce61a09f025d1139e5fdd909b33d9b00d923e97f7b49", + "sha1": "012d6b2e96dee6730c29bbac9f1672a7c7531e34", + "md5": "f0ce61f5122130ce64ee8e6e20e30c72" + } + ] + }, + { + "name": "sourcesElements", + "attributes": { + "org.gradle.category": "documentation", + "org.gradle.dependency.bundling": "external", + "org.gradle.docstype": "sources", + "org.gradle.usage": "java-runtime" + }, + "files": [ + { + "name": "smali-util-3.0.9-sources.jar", + "url": "smali-util-3.0.9-sources.jar", + "size": 21762, + "sha512": "2c001e0b55673b4cc751baf8fe014694d4c82dd49ca90302d2556e80e3e3ae946caf854dca082f1a2dbae35593bbd9740d5cc8d495ad168076b4ecea13443912", + "sha256": "36b1282519e5aa66875d7e58dd732c0afcffd09f6968fc327acc101c29874b62", + "sha1": "ea3cbbfe4da2269794aeb9d9ef3e5d109de22071", + "md5": "19d998a52fe67bf5cec7c53ada58ae9e" + } + ] + } + ] +} diff --git a/.gradle-user/caches/modules-2/files-2.1/com.android.tools.smali/smali-util/3.0.9/ec9105899e5634ef710454bdd7102cea9c8565b/smali-util-3.0.9.jar b/.gradle-user/caches/modules-2/files-2.1/com.android.tools.smali/smali-util/3.0.9/ec9105899e5634ef710454bdd7102cea9c8565b/smali-util-3.0.9.jar new file mode 100644 index 0000000..38c9899 Binary files /dev/null and b/.gradle-user/caches/modules-2/files-2.1/com.android.tools.smali/smali-util/3.0.9/ec9105899e5634ef710454bdd7102cea9c8565b/smali-util-3.0.9.jar differ diff --git a/.gradle-user/caches/modules-2/files-2.1/com.beust/jcommander/1.64/2c228689d367a4076013f851621f70d680099aab/jcommander-1.64.pom b/.gradle-user/caches/modules-2/files-2.1/com.beust/jcommander/1.64/2c228689d367a4076013f851621f70d680099aab/jcommander-1.64.pom new file mode 100644 index 0000000..9688698 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/com.beust/jcommander/1.64/2c228689d367a4076013f851621f70d680099aab/jcommander-1.64.pom @@ -0,0 +1,36 @@ + + + 4.0.0 + com.beust + jcommander + 1.64 + jcommander + Command line parsing + http://jcommander.org + + + Apache 2.0 + http://www.apache.org/licenses/LICENSE-2.0 + + + + + Cedric Beust + cedric@beust.com + + + + https://github.com/cbeust/jcommander.git + git@github.com:cbeust/jcommander.git + http://github.com/cbeust/jcommander + + + + org.testng + testng + 6.10 + test + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/com.beust/jcommander/1.64/456a985ac9b12d34820e4d5de063b2c2fc43ed5a/jcommander-1.64.jar b/.gradle-user/caches/modules-2/files-2.1/com.beust/jcommander/1.64/456a985ac9b12d34820e4d5de063b2c2fc43ed5a/jcommander-1.64.jar new file mode 100644 index 0000000..805df99 Binary files /dev/null and b/.gradle-user/caches/modules-2/files-2.1/com.beust/jcommander/1.64/456a985ac9b12d34820e4d5de063b2c2fc43ed5a/jcommander-1.64.jar differ diff --git a/.gradle-user/caches/modules-2/files-2.1/com.fasterxml.jackson/jackson-bom/2.17.2/e772457e00739867a8f382ef0a8c4dcb03558772/jackson-bom-2.17.2.pom b/.gradle-user/caches/modules-2/files-2.1/com.fasterxml.jackson/jackson-bom/2.17.2/e772457e00739867a8f382ef0a8c4dcb03558772/jackson-bom-2.17.2.pom new file mode 100644 index 0000000..04babd2 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/com.fasterxml.jackson/jackson-bom/2.17.2/e772457e00739867a8f382ef0a8c4dcb03558772/jackson-bom-2.17.2.pom @@ -0,0 +1,456 @@ + + + 4.0.0 + + + com.fasterxml.jackson + jackson-parent + + 2.17 + + + jackson-bom + Jackson BOM + Bill of Materials pom for getting full, complete set of compatible versions +of Jackson components maintained by FasterXML.com + + 2.17.2 + pom + + + base + + + + FasterXML + http://fasterxml.com/ + + + + Apache License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + cowtowncoder + Tatu Saloranta + tatu@fasterxml.com + + + + https://github.com/FasterXML/jackson-bom + + scm:git:git@github.com:FasterXML/jackson-bom.git + scm:git:git@github.com:FasterXML/jackson-bom.git + https://github.com/FasterXML/jackson-bom + jackson-bom-2.17.2 + + + + 2.17.2 + + + ${jackson.version} + ${jackson.version} + ${jackson.version} + ${jackson.version} + ${jackson.version} + ${jackson.version} + ${jackson.version} + ${jackson.version} + + ${jackson.version} + ${jackson.version.module} + ${jackson.version.module} + + 1.2.0 + + + 2024-07-05T16:48:23Z + + + + + + + + com.fasterxml.jackson.core + jackson-annotations + ${jackson.version.annotations} + + + com.fasterxml.jackson.core + jackson-core + ${jackson.version.core} + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version.databind} + + + + + com.fasterxml.jackson.dataformat + jackson-dataformat-avro + ${jackson.version.dataformat} + + + com.fasterxml.jackson.dataformat + jackson-dataformat-cbor + ${jackson.version.dataformat} + + + com.fasterxml.jackson.dataformat + jackson-dataformat-csv + ${jackson.version.dataformat} + + + com.fasterxml.jackson.dataformat + jackson-dataformat-ion + ${jackson.version.dataformat} + + + com.fasterxml.jackson.dataformat + jackson-dataformat-properties + ${jackson.version.dataformat} + + + com.fasterxml.jackson.dataformat + jackson-dataformat-protobuf + ${jackson.version.dataformat} + + + com.fasterxml.jackson.dataformat + jackson-dataformat-smile + ${jackson.version.dataformat} + + + com.fasterxml.jackson.dataformat + jackson-dataformat-toml + ${jackson.version.dataformat} + + + com.fasterxml.jackson.dataformat + jackson-dataformat-xml + ${jackson.version.dataformat} + + + com.fasterxml.jackson.dataformat + jackson-dataformat-yaml + ${jackson.version.dataformat} + + + + + com.fasterxml.jackson.datatype + jackson-datatype-eclipse-collections + ${jackson.version.datatype} + + + com.fasterxml.jackson.datatype + jackson-datatype-guava + ${jackson.version.datatype} + + + + + + + com.fasterxml.jackson.datatype + jackson-datatype-hibernate4 + ${jackson.version.datatype} + + + com.fasterxml.jackson.datatype + jackson-datatype-hibernate5 + ${jackson.version.datatype} + + + com.fasterxml.jackson.datatype + jackson-datatype-hibernate5-jakarta + ${jackson.version.datatype} + + + com.fasterxml.jackson.datatype + jackson-datatype-hibernate6 + ${jackson.version.datatype} + + + com.fasterxml.jackson.datatype + jackson-datatype-hppc + ${jackson.version.datatype} + + + com.fasterxml.jackson.datatype + jackson-datatype-jakarta-jsonp + ${jackson.version.datatype} + + + com.fasterxml.jackson.datatype + jackson-datatype-jaxrs + + ${jackson.version.datatype} + + + com.fasterxml.jackson.datatype + jackson-datatype-joda + ${jackson.version.datatype} + + + com.fasterxml.jackson.datatype + jackson-datatype-joda-money + ${jackson.version.datatype} + + + com.fasterxml.jackson.datatype + jackson-datatype-jdk8 + ${jackson.version.datatype} + + + com.fasterxml.jackson.datatype + jackson-datatype-json-org + ${jackson.version.datatype} + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + ${jackson.version.datatype} + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr353 + ${jackson.version.datatype} + + + com.fasterxml.jackson.datatype + jackson-datatype-pcollections + ${jackson.version.datatype} + + + + + com.fasterxml.jackson.jaxrs + jackson-jaxrs-base + ${jackson.version.jaxrs} + + + com.fasterxml.jackson.jaxrs + jackson-jaxrs-cbor-provider + ${jackson.version.jaxrs} + + + com.fasterxml.jackson.jaxrs + jackson-jaxrs-json-provider + ${jackson.version.jaxrs} + + + com.fasterxml.jackson.jaxrs + jackson-jaxrs-smile-provider + ${jackson.version.jaxrs} + + + com.fasterxml.jackson.jaxrs + jackson-jaxrs-xml-provider + ${jackson.version.jaxrs} + + + com.fasterxml.jackson.jaxrs + jackson-jaxrs-yaml-provider + ${jackson.version.jaxrs} + + + + + com.fasterxml.jackson.jakarta.rs + jackson-jakarta-rs-base + ${jackson.version.jakarta.rs} + + + com.fasterxml.jackson.jakarta.rs + jackson-jakarta-rs-cbor-provider + ${jackson.version.jakarta.rs} + + + com.fasterxml.jackson.jakarta.rs + jackson-jakarta-rs-json-provider + ${jackson.version.jakarta.rs} + + + com.fasterxml.jackson.jakarta.rs + jackson-jakarta-rs-smile-provider + ${jackson.version.jakarta.rs} + + + com.fasterxml.jackson.jakarta.rs + jackson-jakarta-rs-xml-provider + ${jackson.version.jakarta.rs} + + + com.fasterxml.jackson.jakarta.rs + jackson-jakarta-rs-yaml-provider + ${jackson.version.jakarta.rs} + + + + + com.fasterxml.jackson.jr + jackson-jr-all + ${jackson.version.jacksonjr} + + + com.fasterxml.jackson.jr + jackson-jr-annotation-support + ${jackson.version.jacksonjr} + + + com.fasterxml.jackson.jr + jackson-jr-extension-javatime + ${jackson.version.jacksonjr} + + + com.fasterxml.jackson.jr + jackson-jr-objects + ${jackson.version.jacksonjr} + + + com.fasterxml.jackson.jr + jackson-jr-retrofit2 + ${jackson.version.jacksonjr} + + + com.fasterxml.jackson.jr + jackson-jr-stree + ${jackson.version.jacksonjr} + + + + + com.fasterxml.jackson.module + jackson-module-afterburner + ${jackson.version.module} + + + com.fasterxml.jackson.module + jackson-module-android-record + ${jackson.version.module} + + + com.fasterxml.jackson.module + jackson-module-blackbird + ${jackson.version.module} + + + com.fasterxml.jackson.module + jackson-module-guice + ${jackson.version.module} + + + com.fasterxml.jackson.module + jackson-module-guice7 + ${jackson.version.module} + + + com.fasterxml.jackson.module + jackson-module-jaxb-annotations + ${jackson.version.module} + + + com.fasterxml.jackson.module + jackson-module-jakarta-xmlbind-annotations + ${jackson.version.module} + + + com.fasterxml.jackson.module + jackson-module-jsonSchema + ${jackson.version.module} + + + com.fasterxml.jackson.module + jackson-module-jsonSchema-jakarta + ${jackson.version.module} + + + com.fasterxml.jackson.module + jackson-module-kotlin + ${jackson.version.module.kotlin} + + + com.fasterxml.jackson.module + jackson-module-mrbean + ${jackson.version.module} + + + com.fasterxml.jackson.module + jackson-module-no-ctor-deser + ${jackson.version.module} + + + com.fasterxml.jackson.module + jackson-module-osgi + ${jackson.version.module} + + + com.fasterxml.jackson.module + jackson-module-parameter-names + ${jackson.version.module} + + + com.fasterxml.jackson.module + jackson-module-paranamer + ${jackson.version.module} + + + + + + + com.fasterxml.jackson.module + jackson-module-scala_2.11 + ${jackson.version.module.scala} + + + com.fasterxml.jackson.module + jackson-module-scala_2.12 + ${jackson.version.module.scala} + + + com.fasterxml.jackson.module + jackson-module-scala_2.13 + ${jackson.version.module.scala} + + + com.fasterxml.jackson.module + jackson-module-scala_3 + ${jackson.version.module.scala} + + + + + + + + + sonatype-nexus-snapshots + Sonatype Nexus Snapshots + https://oss.sonatype.org/content/repositories/snapshots + false + true + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/com.fasterxml.jackson/jackson-parent/2.17/df97fedb1aae67d608a69fa9262410247f3d31af/jackson-parent-2.17.pom b/.gradle-user/caches/modules-2/files-2.1/com.fasterxml.jackson/jackson-parent/2.17/df97fedb1aae67d608a69fa9262410247f3d31af/jackson-parent-2.17.pom new file mode 100644 index 0000000..b08540a --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/com.fasterxml.jackson/jackson-parent/2.17/df97fedb1aae67d608a69fa9262410247f3d31af/jackson-parent-2.17.pom @@ -0,0 +1,169 @@ + + + 4.0.0 + + + com.fasterxml + oss-parent + 58 + + + com.fasterxml.jackson + jackson-parent + 2.17 + pom + + Jackson parent poms + Parent pom for all Jackson components + http://github.com/FasterXML/ + + FasterXML + http://fasterxml.com/ + + + + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + + cowtowncoder + Tatu Saloranta + tatu@fasterxml.com + + + + + scm:git:git@github.com:FasterXML/jackson-parent.git + scm:git:git@github.com:FasterXML/jackson-parent.git + http://github.com/FasterXML/jackson-parent + jackson-parent-2.17 + + + + + + 1.8 + 1.8 + ${javac.src.version} + ${javac.target.version} + + lines,source,vars + + + ${basedir}/src/main/java/${packageVersion.dir}/PackageVersion.java.in + ${generatedSourcesDir}/${packageVersion.dir}/PackageVersion.java + + 2024-03-12T03:33:51Z + + + + + + + + sonatype-nexus-snapshots + Sonatype Nexus Snapshots + https://oss.sonatype.org/content/repositories/snapshots + false + true + + + + + + + + + + org.apache.maven.plugins + maven-enforcer-plugin + + + enforce-java + validate + + enforce + + + + + [3.6,) + [ERROR] The currently supported version of Maven is 3.6 or higher + + + true + true + true + clean,deploy,site + [ERROR] Best Practice is to always define plugin versions! + + + + + + + + + com.google.code.maven-replacer-plugin + replacer + ${version.plugin.replacer} + + + process-packageVersion + + replace + + + + + + ${packageVersion.template.input} + ${packageVersion.template.output} + + + @package@ + ${packageVersion.package} + + + @projectversion@ + ${project.version} + + + @projectgroupid@ + ${project.groupId} + + + @projectartifactid@ + ${project.artifactId} + + + + + + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/com.fasterxml.woodstox/woodstox-core/6.5.1/79200ba197e64dfc3bebc33db5a85c42ca744188/woodstox-core-6.5.1.pom b/.gradle-user/caches/modules-2/files-2.1/com.fasterxml.woodstox/woodstox-core/6.5.1/79200ba197e64dfc3bebc33db5a85c42ca744188/woodstox-core-6.5.1.pom new file mode 100644 index 0000000..ee3df0b --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/com.fasterxml.woodstox/woodstox-core/6.5.1/79200ba197e64dfc3bebc33db5a85c42ca744188/woodstox-core-6.5.1.pom @@ -0,0 +1,263 @@ + + + + oss-parent + com.fasterxml + 50 + ../pom.xml/pom.xml + + 4.0.0 + com.fasterxml.woodstox + woodstox-core + bundle + Woodstox + 6.5.1 + Woodstox is a high-performance XML processor that implements Stax (JSR-173), +SAX2 and Stax2 APIs + https://github.com/FasterXML/woodstox + + https://github.com/FasterXML/woodstox/issues + + + + cowtowncoder + Tatu Saloranta + tatu@fasterxml.com + + + + + The Apache License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + scm:git:git@github.com:FasterXML/woodstox.git + scm:git:git@github.com:FasterXML/woodstox.git + woodstox-core-6.5.1 + https://github.com/FasterXML/woodstox + + + FasterXML + http://fasterxml.com + + + + + org.jacoco + jacoco-maven-plugin + + + + prepare-agent + + + + report + test + + report + + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.6 + true + + sonatype-nexus-staging + https://oss.sonatype.org/ + b34f19b9cc6224 + + + + maven-compiler-plugin + + 1.6 + 1.6 + + + + maven-surefire-plugin + + + failing/*.java + **/Abstract*.java + **/Base*.java + **/*$*.java + + + **/*Test.java + **/Test*.java + + + + + org.apache.felix + maven-bundle-plugin + true + + + <_removeheaders>Require-Capability + + + + + maven-shade-plugin + + + package + + shade + + + false + + + net.java.dev.msv:msv-core + net.java.dev.msv:xsdlib + relaxngDatatype:relaxngDatatype + com.sun.xml.bind.jaxb:isorelax + + + + + net.java.dev.msv:msv-core + + com/sun/msv/** + + + com/sun/msv/driver/textui/DebugController* + com/sun/msv/driver/textui/Driver* + com/sun/msv/driver/textui/Messages* + + + + + + com.sun.msv.xsd + com.ctc.wstx.shaded.msv.xsd + + + com.sun.xml.util + com.ctc.wstx.shaded.msv.xsd_util + + + org.relaxng.datatype + com.ctc.wstx.shaded.msv.relaxng_datatype + + + org.iso_relax + com.ctc.wstx.shaded.msv.org_isorelax + + + jp.gr.xml.relax + com.ctc.wstx.shaded.msv.org_jp_gr_xml + + + com.sun.msv + com.ctc.wstx.shaded.msv_core + + + + + + + osgi.extender;filter:="(&(osgi.extender=osgi.serviceloader.registrar)(version>=1.0.0)(!(version>=2.0.0)))";resolution:=optional,osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.6))" + + + + + + + + + org.moditect + moditect-maven-plugin + + + add-module-infos + package + + add-module-info + + + true + + src/moditect/module-info.java + + + + + + + + + + org.codehaus.woodstox + stax2-api + 4.2.1 + compile + + + stax-api + javax.xml.stream + + + + + org.osgi + osgi.core + 5.0.0 + provided + true + + + biz.aQute.bnd + biz.aQute.bnd.annotation + 6.4.0 + provided + true + + + junit + junit + 4.13.2 + test + + + hamcrest-core + org.hamcrest + + + + + + + + maven-javadoc-plugin + + private + true + true + ${project.name} ${project.version} API + ${project.name} ${project.version} API + + + + maven-surefire-report-plugin + + + + + 2013.6.1 + 1.6 + 6.4.0 + com.ctc.wstx.*;version=${project.version} + 1.6 + 3.1.1 + + diff --git a/.gradle-user/caches/modules-2/files-2.1/com.fasterxml.woodstox/woodstox-core/6.5.1/c6e52e84fe959e69a243c83ec7d24cd889444ddf/woodstox-core-6.5.1.jar b/.gradle-user/caches/modules-2/files-2.1/com.fasterxml.woodstox/woodstox-core/6.5.1/c6e52e84fe959e69a243c83ec7d24cd889444ddf/woodstox-core-6.5.1.jar new file mode 100644 index 0000000..b22b384 Binary files /dev/null and b/.gradle-user/caches/modules-2/files-2.1/com.fasterxml.woodstox/woodstox-core/6.5.1/c6e52e84fe959e69a243c83ec7d24cd889444ddf/woodstox-core-6.5.1.jar differ diff --git a/.gradle-user/caches/modules-2/files-2.1/com.fasterxml/oss-parent/38/ff6b9e9e40c23235f87a44b463995b47adca8dc9/oss-parent-38.pom b/.gradle-user/caches/modules-2/files-2.1/com.fasterxml/oss-parent/38/ff6b9e9e40c23235f87a44b463995b47adca8dc9/oss-parent-38.pom new file mode 100644 index 0000000..fe1baf0 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/com.fasterxml/oss-parent/38/ff6b9e9e40c23235f87a44b463995b47adca8dc9/oss-parent-38.pom @@ -0,0 +1,642 @@ + + + + 4.0.0 + + com.fasterxml + oss-parent + 38 + pom + + FasterXML.com parent pom + FasterXML.com parent pom + http://github.com/FasterXML/ + + FasterXML + http://fasterxml.com/ + + + + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + + + cowtowncoder + Tatu Saloranta + tatu@fasterxml.com + + + + + scm:git:git@github.com:FasterXML/oss-parent.git + scm:git:git@github.com:FasterXML/oss-parent.git + http://github.com/FasterXML/oss-parent + oss-parent-38 + + + GitHub Issue Management + https://github.com/FasterXML/${project.artifactId}/issues + + + + + sonatype-nexus-snapshots + Sonatype Nexus Snapshots + https://oss.sonatype.org/content/repositories/snapshots + + + + sonatype-nexus-staging + Nexus Release Repository + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + + + + UTF-8 + UTF-8 + UTF-8 + + ${project.build.directory}/generated-sources + + 1g + + + 1.6 + 1.6 + + + lines,source,vars + yyyy-MM-dd HH:mm:ssZ + + ${project.groupId}.*;version=${project.version} + * + + + + ${range;[===,=+);${@}} + {maven-resources} + + + + + + + 4.2.0 + + 2.6.1 + 2.7 + + + 3.8.0 + 3.0.0-M1 + + 1.6 + + + 3.0.0-M1 + + 3.0.0-M1 + 3.1.2 + + + 3.0.1 + + + 1.0.0.Beta2 + + 2.5.3 + 1.5.3 + 2.7 + + + 3.2.1 + 3.1 + + + 3.0.1 + + + + 2.22.2 + + + 4.12 + + + + + + sonatype-nexus-snapshots + Sonatype Nexus Snapshots + https://oss.sonatype.org/content/repositories/snapshots + + false + + + true + + + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.7 + + + org.apache.maven.plugins + maven-clean-plugin + ${version.plugin.clean} + + + org.apache.maven.plugins + maven-dependency-plugin + 3.1.1 + + + org.apache.maven.plugins + maven-deploy-plugin + ${version.plugin.deploy} + + + org.apache.maven.plugins + maven-gpg-plugin + ${version.plugin.gpg} + + + org.apache.maven.plugins + maven-install-plugin + ${version.plugin.install} + + + org.apache.maven.plugins + maven-javadoc-plugin + ${version.plugin.javadoc} + + + + org.moditect + moditect-maven-plugin + ${version.plugin.moditect} + + + + + com.google.code.maven-replacer-plugin + replacer + + ${version.plugin.replacer} + + + org.apache.maven.plugins + maven-resources-plugin + ${version.plugin.resources} + + + + org.apache.maven.plugins + maven-shade-plugin + ${version.plugin.shade} + + + org.apache.maven.plugins + maven-site-plugin + ${version.plugin.site} + + + org.codehaus.mojo + cobertura-maven-plugin + ${version.plugin.cobertura} + + + + org.apache.felix + maven-bundle-plugin + ${version.plugin.bundle} + + + + + + + <_removeheaders>Include-Resource,JAVA_1_3_HOME,JAVA_1_4_HOME,JAVA_1_5_HOME,JAVA_1_6_HOME,JAVA_1_7_HOME + <_versionpolicy>${osgi.versionpolicy} + ${project.name} + ${project.groupId}.${project.artifactId} + ${project.description} + ${osgi.export} + ${osgi.private} + ${osgi.import} + ${osgi.dynamicImport} + ${osgi.includeResource} + ${project.url} + ${osgi.requiredExecutionEnvironment} + + ${maven.build.timestamp} + ${javac.src.version} + ${javac.target.version} + + ${project.name} + ${project.version} + ${project.groupId} + ${project.organization.name} + + ${project.name} + ${project.version} + ${project.organization.name} + + ${osgi.mainClass} + + + + + + + + org.apache.maven.plugins + maven-release-plugin + ${version.plugin.release} + + forked-path + false + -Prelease + + + + org.sonatype.plugins + nexus-maven-plugin + 2.1 + + https://oss.sonatype.org/ + sonatype-nexus-staging + + + + + + + + + org.apache.maven.plugins + maven-enforcer-plugin + ${version.plugin.enforcer} + + + enforce-java + validate + + enforce + + + + + + [1.6,) + [ERROR] The currently supported version of Java is 1.6 or higher + + + [3.0,) + [ERROR] The currently supported version of Maven is 3.0 or higher + + + true + true + true + clean,deploy,site + [ERROR] Best Practice is to always define plugin versions! + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${version.plugin.compiler} + + + + org.ow2.asm + asm + 7.0 + + + + ${javac.src.version} + ${javac.target.version} + true + true + true + + true + ${javac.debuglevel} + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + add-generated-sources + generate-sources + + add-source + + + + ${generatedSourcesDir} + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + ${version.plugin.surefire} + + + + org.apache.felix + maven-bundle-plugin + ${version.plugin.bundle} + true + + + + org.apache.maven.plugins + maven-jar-plugin + ${version.plugin.jar} + + + maven-site-plugin + + + attach-descriptor + + attach-descriptor + + + + + + + org.apache.maven.plugins + maven-scm-plugin + 1.9.1 + + + org.apache.maven.scm + maven-scm-provider-gitexe + 1.9.1 + + + + + + + + org.apache.maven.scm + maven-scm-provider-gitexe + 1.9.1 + + + + org.apache.maven.scm + maven-scm-manager-plexus + 1.9.1 + + + + + org.kathrynhuxtable.maven.wagon + wagon-gitsite + 0.3.1 + + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${version.plugin.javadoc} + + ${sun.boot.class.path} + com.google.doclava.Doclava + false + -J-Xmx1024m + ${javadoc.maxmemory} + + http://docs.oracle.com/javase/7/docs/api/ + + + com.google.doclava + doclava + 1.0.3 + + + -hdf project.name "${project.name}" + -d ${project.reporting.outputDirectory}/apidocs + + + + + default + + javadoc + + + + + + + org.apache.maven.plugins + maven-project-info-reports-plugin + 2.5 + + + + org.apache.maven.plugins + maven-jxr-plugin + 2.3 + + + + org.codehaus.mojo + jdepend-maven-plugin + 2.0 + + + + org.apache.maven.plugins + maven-surefire-report-plugin + ${version.plugin.surefire} + + + + org.apache.maven.plugins + maven-pmd-plugin + 2.7.1 + + true + 100 + 1.5 + + + + + org.codehaus.mojo + taglist-maven-plugin + 2.4 + + + + + Todo Work + + + TODO + ignoreCase + + + FIXME + ignoreCase + + + + + + + + + + + + + release + + + + org.apache.maven.plugins + maven-source-plugin + ${version.plugin.source} + + + attach-sources + + jar-no-fork + + + + + true + true + + + ${maven.build.timestamp} + ${javac.src.version} + ${javac.target.version} + + + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${version.plugin.javadoc} + + + attach-javadocs + + jar + + + true + + + true + true + + + ${maven.build.timestamp} + ${javac.src.version} + ${javac.target.version} + + + + + + + + + org.apache.maven.plugins + maven-gpg-plugin + + + sign-artifacts + verify + + sign + + + + + + + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/com.fasterxml/oss-parent/50/2e5ec5928fa4a136254d3dfeb8c56f47b049d8ed/oss-parent-50.pom b/.gradle-user/caches/modules-2/files-2.1/com.fasterxml/oss-parent/50/2e5ec5928fa4a136254d3dfeb8c56f47b049d8ed/oss-parent-50.pom new file mode 100644 index 0000000..1a14a57 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/com.fasterxml/oss-parent/50/2e5ec5928fa4a136254d3dfeb8c56f47b049d8ed/oss-parent-50.pom @@ -0,0 +1,665 @@ + + + + 4.0.0 + + com.fasterxml + oss-parent + 50 + pom + + FasterXML.com parent pom + FasterXML.com parent pom + http://github.com/FasterXML/ + + FasterXML + http://fasterxml.com/ + + + + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + + + cowtowncoder + Tatu Saloranta + tatu@fasterxml.com + + + + + scm:git:git@github.com:FasterXML/oss-parent.git + scm:git:git@github.com:FasterXML/oss-parent.git + http://github.com/FasterXML/oss-parent + oss-parent-50 + + + GitHub Issue Management + https://github.com/FasterXML/${project.artifactId}/issues + + + + + sonatype-nexus-snapshots + Sonatype Nexus Snapshots + https://oss.sonatype.org/content/repositories/snapshots + + + + sonatype-nexus-staging + Nexus Release Repository + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + + + + UTF-8 + UTF-8 + UTF-8 + + 2023-03-05T04:38:31Z + + ${project.build.directory}/generated-sources + + 1g + + + 1.6 + 1.6 + + + lines,source,vars + yyyy-MM-dd HH:mm:ssZ + + ${project.groupId}.*;version=${project.version} + * + + + + ${range;[===,=+);${@}} + {maven-resources} + + + + + + + 5.1.8 + + 3.2.0 + 2.7 + + + 3.10.1 + 3.1.0 + + + 3.2.1 + 3.0.1 + + 3.1.0 + 0.8.8 + 3.3.0 + + 3.5.0 + + + 1.0.0.RC2 + + 3.0.0-M7 + 1.5.3 + 3.3.0 + + 3.4.1 + 3.12.1 + + 3.2.1 + + 3.0.0-M9 + + 3.1.1 + + + + + 4.13.2 + + + + + + sonatype-nexus-snapshots + Sonatype Nexus Snapshots + https://oss.sonatype.org/content/repositories/snapshots + + false + + + true + + + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 3.3.0 + + + org.apache.maven.plugins + maven-clean-plugin + ${version.plugin.clean} + + + org.apache.maven.plugins + maven-dependency-plugin + 3.5.0 + + + org.apache.maven.plugins + maven-deploy-plugin + ${version.plugin.deploy} + + + org.apache.maven.plugins + maven-gpg-plugin + ${version.plugin.gpg} + + + org.apache.maven.plugins + maven-install-plugin + ${version.plugin.install} + + + org.apache.maven.plugins + maven-javadoc-plugin + ${version.plugin.javadoc} + + + org.apache.maven.plugins + maven-resources-plugin + ${version.plugin.resources} + + + + org.apache.maven.plugins + maven-shade-plugin + ${version.plugin.shade} + + + org.apache.maven.plugins + maven-site-plugin + ${version.plugin.site} + + + org.apache.maven.plugins + maven-source-plugin + ${version.plugin.source} + + + org.apache.maven.plugins + maven-wrapper-plugin + ${version.plugin.wrapper} + + + + + org.moditect + moditect-maven-plugin + ${version.plugin.moditect} + + + + + com.google.code.maven-replacer-plugin + replacer + + ${version.plugin.replacer} + + + org.codehaus.mojo + cobertura-maven-plugin + ${version.plugin.cobertura} + + + + org.apache.felix + maven-bundle-plugin + ${version.plugin.bundle} + + + + + + + <_removeheaders>Include-Resource,JAVA_1_3_HOME,JAVA_1_4_HOME,JAVA_1_5_HOME,JAVA_1_6_HOME,JAVA_1_7_HOME + <_versionpolicy>${osgi.versionpolicy} + ${project.name} + ${project.groupId}.${project.artifactId} + ${project.description} + ${osgi.export} + ${osgi.private} + ${osgi.import} + ${osgi.dynamicImport} + ${osgi.includeResource} + ${project.url} + ${osgi.requiredExecutionEnvironment} + + ${javac.src.version} + ${javac.target.version} + + ${project.name} + ${project.version} + ${project.groupId} + ${project.organization.name} + + ${project.name} + ${project.version} + ${project.organization.name} + + ${osgi.mainClass} + + + + + + + + org.apache.maven.plugins + maven-release-plugin + ${version.plugin.release} + + forked-path + false + -Prelease + + + + + + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + add-generated-sources + generate-sources + + add-source + + + + ${generatedSourcesDir} + + + + + + + + org.jacoco + jacoco-maven-plugin + ${version.plugin.jacoco} + + + + org.apache.maven.plugins + maven-compiler-plugin + ${version.plugin.compiler} + + + + org.ow2.asm + asm + 9.4 + + + + ${javac.src.version} + ${javac.target.version} + true + true + true + + true + ${javac.debuglevel} + + + + + org.apache.maven.plugins + maven-enforcer-plugin + ${version.plugin.enforcer} + + + enforce-java + validate + + enforce + + + + + + [1.6,) + [ERROR] The currently supported version of Java is 1.6 or higher + + + [3.0,) + [ERROR] The currently supported version of Maven is 3.0 or higher + + + true + true + true + clean,deploy,site + [ERROR] Best Practice is to always define plugin versions! + + + + + + + + + org.apache.felix + maven-bundle-plugin + true + + + + org.apache.maven.plugins + maven-jar-plugin + ${version.plugin.jar} + + + + org.apache.maven.plugins + maven-scm-plugin + 1.13.0 + + + org.apache.maven.scm + maven-scm-provider-gitexe + 1.13.0 + + + + + + org.apache.maven.plugins + maven-site-plugin + + + attach-descriptor + + attach-descriptor + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + ${version.plugin.surefire} + + + + + + + org.apache.maven.scm + maven-scm-provider-gitexe + 1.13.0 + + + + org.apache.maven.scm + maven-scm-manager-plexus + 1.13.0 + + + + + org.kathrynhuxtable.maven.wagon + wagon-gitsite + 0.3.1 + + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${version.plugin.javadoc} + + ${sun.boot.class.path} + com.google.doclava.Doclava + false + -J-Xmx1024m + ${javadoc.maxmemory} + + http://docs.oracle.com/javase/8/docs/api/ + + + com.google.doclava + doclava + 1.0.3 + + + -hdf project.name "${project.name}" + -d ${project.reporting.outputDirectory}/apidocs + + + + + default + + javadoc + + + + + + + org.apache.maven.plugins + maven-project-info-reports-plugin + 3.4.2 + + + + org.apache.maven.plugins + maven-jxr-plugin + 3.3.0 + + + + org.codehaus.mojo + jdepend-maven-plugin + 2.0 + + + + org.apache.maven.plugins + maven-surefire-report-plugin + ${version.plugin.surefire} + + + + org.apache.maven.plugins + maven-pmd-plugin + 3.20.0 + + true + 100 + 1.5 + + + + + org.codehaus.mojo + taglist-maven-plugin + 3.0.0 + + + + + Todo Work + + + TODO + ignoreCase + + + FIXME + ignoreCase + + + + + + + + + + + + + release + + + + org.apache.maven.plugins + maven-source-plugin + ${version.plugin.source} + + + attach-sources + + jar-no-fork + + + + + true + true + + + ${javac.src.version} + ${javac.target.version} + + + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${version.plugin.javadoc} + + + attach-javadocs + + jar + + + true + + + true + true + + + ${javac.src.version} + ${javac.target.version} + + + + + + + + + org.apache.maven.plugins + maven-gpg-plugin + + + sign-artifacts + verify + + sign + + + + + + + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/com.fasterxml/oss-parent/58/ed9e5d9e7cad24fce51b18455e0cf5ccd2c94b6/oss-parent-58.pom b/.gradle-user/caches/modules-2/files-2.1/com.fasterxml/oss-parent/58/ed9e5d9e7cad24fce51b18455e0cf5ccd2c94b6/oss-parent-58.pom new file mode 100644 index 0000000..10a835a --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/com.fasterxml/oss-parent/58/ed9e5d9e7cad24fce51b18455e0cf5ccd2c94b6/oss-parent-58.pom @@ -0,0 +1,661 @@ + + + + 4.0.0 + + com.fasterxml + oss-parent + 58 + pom + + FasterXML.com parent pom + FasterXML.com parent pom + http://github.com/FasterXML/ + + FasterXML + http://fasterxml.com/ + + + + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + + + cowtowncoder + Tatu Saloranta + tatu@fasterxml.com + + + + + scm:git:git@github.com:FasterXML/oss-parent.git + scm:git:git@github.com:FasterXML/oss-parent.git + http://github.com/FasterXML/oss-parent + oss-parent-58 + + + GitHub Issue Management + https://github.com/FasterXML/${project.artifactId}/issues + + + + + sonatype-nexus-snapshots + Sonatype Nexus Snapshots + https://oss.sonatype.org/content/repositories/snapshots + + + + sonatype-nexus-staging + Nexus Release Repository + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + + + + UTF-8 + UTF-8 + UTF-8 + + 2024-02-19T21:48:46Z + + ${project.build.directory}/generated-sources + + 1g + + + 1.6 + 1.6 + + + lines,source,vars + yyyy-MM-dd HH:mm:ssZ + + ${project.groupId}.*;version=${project.version} + * + + + + ${range;[===,=+);${@}} + {maven-resources} + + + + + + 5.1.9 + + 3.3.2 + 3.6.1 + 2.7 + 3.12.1 + 3.1.1 + 3.4.1 + 3.1.0 + + 3.1.1 + 0.8.11 + 3.3.0 + + 3.6.2 + + + 1.1.0 + + 3.21.2 + 3.0.1 + 1.5.3 + 3.3.1 + + 2.0.1 + 3.5.1 + 4.0.0-M11 + + 3.3.0 + + 3.2.5 + + 3.2.0 + + + + + 4.13.2 + + + 5.10.2 + + 3.24.2 + + + + + + sonatype-nexus-snapshots + Sonatype Nexus Snapshots + https://oss.sonatype.org/content/repositories/snapshots + + false + + + true + + + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 3.5.0 + + + org.apache.maven.plugins + maven-clean-plugin + ${version.plugin.clean} + + + org.apache.maven.plugins + maven-dependency-plugin + ${version.plugin.dependency} + + + org.apache.maven.plugins + maven-deploy-plugin + ${version.plugin.deploy} + + + org.apache.maven.plugins + maven-gpg-plugin + ${version.plugin.gpg} + + + org.apache.maven.plugins + maven-install-plugin + ${version.plugin.install} + + + org.apache.maven.plugins + maven-javadoc-plugin + ${version.plugin.javadoc} + + + org.apache.maven.plugins + maven-resources-plugin + ${version.plugin.resources} + + + + org.apache.maven.plugins + maven-shade-plugin + ${version.plugin.shade} + + + org.apache.maven.plugins + maven-site-plugin + ${version.plugin.site} + + + org.apache.maven.plugins + maven-source-plugin + ${version.plugin.source} + + + org.apache.maven.plugins + maven-wrapper-plugin + ${version.plugin.wrapper} + + + + + org.moditect + moditect-maven-plugin + ${version.plugin.moditect} + + + + + com.google.code.maven-replacer-plugin + replacer + + ${version.plugin.replacer} + + + org.codehaus.mojo + cobertura-maven-plugin + ${version.plugin.cobertura} + + + + org.apache.felix + maven-bundle-plugin + ${version.plugin.bundle} + + + + + + + <_removeheaders>Include-Resource,JAVA_1_3_HOME,JAVA_1_4_HOME,JAVA_1_5_HOME,JAVA_1_6_HOME,JAVA_1_7_HOME + <_versionpolicy>${osgi.versionpolicy} + ${project.name} + ${project.groupId}.${project.artifactId} + ${project.description} + ${osgi.export} + ${osgi.private} + ${osgi.import} + ${osgi.dynamicImport} + ${osgi.includeResource} + ${project.url} + ${osgi.requiredExecutionEnvironment} + + ${javac.src.version} + ${javac.target.version} + + ${project.name} + ${project.version} + ${project.groupId} + ${project.organization.name} + + ${project.name} + ${project.version} + ${project.organization.name} + + ${osgi.mainClass} + + + + + + + + org.apache.maven.plugins + maven-release-plugin + ${version.plugin.release} + + forked-path + false + -Prelease + + + + + + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + add-generated-sources + generate-sources + + add-source + + + + ${generatedSourcesDir} + + + + + + + + org.jacoco + jacoco-maven-plugin + ${version.plugin.jacoco} + + + + org.apache.maven.plugins + maven-compiler-plugin + ${version.plugin.compiler} + + + + org.ow2.asm + asm + 9.6 + + + + ${javac.src.version} + ${javac.target.version} + true + true + + true + ${javac.debuglevel} + + + + + org.apache.maven.plugins + maven-enforcer-plugin + ${version.plugin.enforcer} + + + enforce-java + validate + + enforce + + + + + + [1.6,) + [ERROR] The currently supported version of Java is 1.6 or higher + + + [3.0,) + [ERROR] The currently supported version of Maven is 3.0 or higher + + + true + true + true + clean,deploy,site + [ERROR] Best Practice is to always define plugin versions! + + + + + + + + + org.apache.felix + maven-bundle-plugin + true + + + + org.apache.maven.plugins + maven-jar-plugin + ${version.plugin.jar} + + + + org.apache.maven.plugins + maven-scm-plugin + ${version.plugin.scm} + + + org.apache.maven.scm + maven-scm-provider-gitexe + ${version.plugin.scm} + + + + + + org.apache.maven.plugins + maven-site-plugin + + + attach-descriptor + + attach-descriptor + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + ${version.plugin.surefire} + + + + + + + org.apache.maven.scm + maven-scm-provider-gitexe + ${version.plugin.scm} + + + + org.apache.maven.scm + maven-scm-manager-plexus + ${version.plugin.scm} + + + + + org.kathrynhuxtable.maven.wagon + wagon-gitsite + 0.3.1 + + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${version.plugin.javadoc} + + ${sun.boot.class.path} + com.google.doclava.Doclava + false + -J-Xmx1024m + ${javadoc.maxmemory} + + http://docs.oracle.com/javase/8/docs/api/ + + + com.google.doclava + doclava + 1.0.3 + + + -hdf project.name "${project.name}" + -d ${project.reporting.outputDirectory}/apidocs + + + + + default + + javadoc + + + + + + + org.apache.maven.plugins + maven-project-info-reports-plugin + 3.5.0 + + + + org.apache.maven.plugins + maven-jxr-plugin + 3.3.2 + + + + org.codehaus.mojo + jdepend-maven-plugin + 2.0 + + + + org.apache.maven.plugins + maven-surefire-report-plugin + ${version.plugin.surefire} + + + + org.apache.maven.plugins + maven-pmd-plugin + ${version.plugin.pmd} + + true + 100 + 1.5 + + + + + org.codehaus.mojo + taglist-maven-plugin + 3.0.0 + + + + + Todo Work + + + TODO + ignoreCase + + + FIXME + ignoreCase + + + + + + + + + + + + + release + + + + org.apache.maven.plugins + maven-source-plugin + ${version.plugin.source} + + + attach-sources + + jar-no-fork + + + + + true + true + + + ${javac.src.version} + ${javac.target.version} + + + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${version.plugin.javadoc} + + + attach-javadocs + + jar + + + true + + + true + true + + + ${javac.src.version} + ${javac.target.version} + + + + + + + + + org.apache.maven.plugins + maven-gpg-plugin + + + sign-artifacts + verify + + sign + + + + + + + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/com.google.code.findbugs/jsr305/3.0.2/25ea2e8b0c338a877313bd4672d3fe056ea78f0d/jsr305-3.0.2.jar b/.gradle-user/caches/modules-2/files-2.1/com.google.code.findbugs/jsr305/3.0.2/25ea2e8b0c338a877313bd4672d3fe056ea78f0d/jsr305-3.0.2.jar new file mode 100644 index 0000000..59222d9 Binary files /dev/null and b/.gradle-user/caches/modules-2/files-2.1/com.google.code.findbugs/jsr305/3.0.2/25ea2e8b0c338a877313bd4672d3fe056ea78f0d/jsr305-3.0.2.jar differ diff --git a/.gradle-user/caches/modules-2/files-2.1/com.google.code.findbugs/jsr305/3.0.2/8d93cdf4d84d7e1de736df607945c6df0730a10f/jsr305-3.0.2.pom b/.gradle-user/caches/modules-2/files-2.1/com.google.code.findbugs/jsr305/3.0.2/8d93cdf4d84d7e1de736df607945c6df0730a10f/jsr305-3.0.2.pom new file mode 100644 index 0000000..3a6e2c6 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/com.google.code.findbugs/jsr305/3.0.2/8d93cdf4d84d7e1de736df607945c6df0730a10f/jsr305-3.0.2.pom @@ -0,0 +1,135 @@ + + 4.0.0 + + org.sonatype.oss + oss-parent + 7 + + + + com.google.code.findbugs + jsr305 + 3.0.2 + jar + + http://findbugs.sourceforge.net/ + FindBugs-jsr305 + JSR305 Annotations for Findbugs + + + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + 3.0 + + + + scm:git:https://code.google.com/p/jsr-305/ + scm:git:https://code.google.com/p/jsr-305/ + https://code.google.com/p/jsr-305/ + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.9.1 + + + package + + jar + + + true + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.0 + + 1.5 + 1.5 + + + + org.apache.maven.plugins + maven-source-plugin + 2.4 + + + attach-sources + + jar-no-fork + + + + + + org.apache.felix + maven-bundle-plugin + 2.4.0 + true + + + bundle-manifest + process-classes + + manifest + + + + + + org.jsr-305 + ${project.name} + javax.annotation;javax.annotation.concurrent;javax.annotation.meta + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + ${project.build.outputDirectory}/META-INF/MANIFEST.MF + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.3 + true + + ossrh + https://oss.sonatype.org/ + true + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.5 + + + sign-artifacts + verify + + sign + + + + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/com.google.errorprone/error_prone_annotations/2.11.0/c5a0ace696d3f8b1c1d8cc036d8c03cc0cbe6b69/error_prone_annotations-2.11.0.jar b/.gradle-user/caches/modules-2/files-2.1/com.google.errorprone/error_prone_annotations/2.11.0/c5a0ace696d3f8b1c1d8cc036d8c03cc0cbe6b69/error_prone_annotations-2.11.0.jar new file mode 100644 index 0000000..bec7656 Binary files /dev/null and b/.gradle-user/caches/modules-2/files-2.1/com.google.errorprone/error_prone_annotations/2.11.0/c5a0ace696d3f8b1c1d8cc036d8c03cc0cbe6b69/error_prone_annotations-2.11.0.jar differ diff --git a/.gradle-user/caches/modules-2/files-2.1/com.google.errorprone/error_prone_annotations/2.11.0/ced1afa200bbf344ccdef14b92aa84f7863f395c/error_prone_annotations-2.11.0.pom b/.gradle-user/caches/modules-2/files-2.1/com.google.errorprone/error_prone_annotations/2.11.0/ced1afa200bbf344ccdef14b92aa84f7863f395c/error_prone_annotations-2.11.0.pom new file mode 100644 index 0000000..a453c85 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/com.google.errorprone/error_prone_annotations/2.11.0/ced1afa200bbf344ccdef14b92aa84f7863f395c/error_prone_annotations-2.11.0.pom @@ -0,0 +1,69 @@ + + + + + 4.0.0 + + + com.google.errorprone + error_prone_parent + 2.11.0 + + + error-prone annotations + error_prone_annotations + + + + junit + junit + ${junit.version} + test + + + + + + Apache 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.7 + 1.7 + + + + + maven-jar-plugin + + + + com.google.errorprone.annotations + + + + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/com.google.errorprone/error_prone_parent/2.11.0/bd585f378139da5b5e670840892c48e75d03cf7b/error_prone_parent-2.11.0.pom b/.gradle-user/caches/modules-2/files-2.1/com.google.errorprone/error_prone_parent/2.11.0/bd585f378139da5b5e670840892c48e75d03cf7b/error_prone_parent-2.11.0.pom new file mode 100644 index 0000000..c6f4c9c --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/com.google.errorprone/error_prone_parent/2.11.0/bd585f378139da5b5e670840892c48e75d03cf7b/error_prone_parent-2.11.0.pom @@ -0,0 +1,298 @@ + + + + + 4.0.0 + + Error Prone parent POM + com.google.errorprone + error_prone_parent + 2.11.0 + pom + + Error Prone is a static analysis tool for Java that catches common programming mistakes at compile-time. + https://errorprone.info + + + UTF-8 + 31.0.1-jre + 2.8.2 + 1.1.3 + 1.0-rc6 + 1.9 + 4.13.1 + 3.15.0 + 3.12.4 + 0.19 + 2.8.8 + 0.6 + 3.1.0 + 3.2.1 + 1.6.7 + 3.19.2 + 1.43.2 + + + + Google LLC + http://www.google.com + + + + + Eddie Aftandilian + + + + + check_api + test_helpers + core + annotation + annotations + type_annotations + docgen + docgen_processor + refaster + + + + scm:git:https://github.com/google/error-prone.git + scm:git:git@github.com:google/error-prone.git + https://github.com/google/error-prone + + + + + Apache 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + + + + + + + src/main/java + + **/*.properties + **/*.binarypb + + + + + + src/test/java + + **/testdata/** + + + + + + + org.apache.maven.plugins + maven-shade-plugin + 2.1 + + ${project.build.directory}/dependency-reduced-pom.xml + + + + + + + org.apache.maven.plugins + maven-enforcer-plugin + 3.0.0 + + + enforce-maven + + enforce + + + + + 3.0.5 + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.2.2 + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.1.1 + + 8 + true + Error Prone ${project.version} API + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 11 + 11 + + + --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED + --add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED + --add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED + --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED + --add-exports=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED + --add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED + --add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED + --add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED + --add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED + --add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED + --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED + + + **/testdata/** + + + + + org.apache.maven.plugins + maven-source-plugin + 2.1.2 + + + attach-sources + package + + jar-no-fork + + + + + + org.apache.maven.plugins + maven-site-plugin + 3.7.1 + + + attach-descriptor + + attach-descriptor + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.2 + + + -Xmx1g + --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED + --add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED + --add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED + --add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED + --add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED + --add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED + --add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED + --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED + --add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED + --add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED + --add-opens=java.base/java.math=ALL-UNNAMED + --add-opens=java.base/java.nio=ALL-UNNAMED + + false + + + + + + + + ossrh + https://oss.sonatype.org/content/repositories/snapshots/ + + + + + + release + + + + org.sonatype.plugins + nexus-staging-maven-plugin + ${nexus-staging-maven-plugin.version} + true + + ossrh + https://oss.sonatype.org/ + true + + + + org.apache.maven.plugins + maven-source-plugin + ${maven-source-plugin.version} + + + attach-sources + + jar-no-fork + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${maven-javadoc-plugin.version} + + + attach-javadocs + + jar + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.6 + + + sign-artifacts + verify + + sign + + + + + + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/com.google.guava/failureaccess/1.0.1/1dcf1de382a0bf95a3d8b0849546c88bac1292c9/failureaccess-1.0.1.jar b/.gradle-user/caches/modules-2/files-2.1/com.google.guava/failureaccess/1.0.1/1dcf1de382a0bf95a3d8b0849546c88bac1292c9/failureaccess-1.0.1.jar new file mode 100644 index 0000000..9b56dc7 Binary files /dev/null and b/.gradle-user/caches/modules-2/files-2.1/com.google.guava/failureaccess/1.0.1/1dcf1de382a0bf95a3d8b0849546c88bac1292c9/failureaccess-1.0.1.jar differ diff --git a/.gradle-user/caches/modules-2/files-2.1/com.google.guava/failureaccess/1.0.1/e8160e78fdaaf7088621dc1649d9dd2dfcf8d0e8/failureaccess-1.0.1.pom b/.gradle-user/caches/modules-2/files-2.1/com.google.guava/failureaccess/1.0.1/e8160e78fdaaf7088621dc1649d9dd2dfcf8d0e8/failureaccess-1.0.1.pom new file mode 100644 index 0000000..6cce782 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/com.google.guava/failureaccess/1.0.1/e8160e78fdaaf7088621dc1649d9dd2dfcf8d0e8/failureaccess-1.0.1.pom @@ -0,0 +1,68 @@ + + + 4.0.0 + + com.google.guava + guava-parent + 26.0-android + + failureaccess + 1.0.1 + bundle + Guava InternalFutureFailureAccess and InternalFutures + + Contains + com.google.common.util.concurrent.internal.InternalFutureFailureAccess and + InternalFutures. Most users will never need to use this artifact. Its + classes is conceptually a part of Guava, but they're in this separate + artifact so that Android libraries can use them without pulling in all of + Guava (just as they can use ListenableFuture by depending on the + listenablefuture artifact). + + + + + maven-source-plugin + + + org.codehaus.mojo + animal-sniffer-maven-plugin + + + true + org.apache.felix + maven-bundle-plugin + 2.5.0 + + + bundle-manifest + process-classes + + manifest + + + + + + com.google.common.util.concurrent.internal + https://github.com/google/guava/ + + + + + maven-javadoc-plugin + + + attach-docs + + + generate-javadoc-site-report + site + javadoc + + + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/com.google.guava/guava-parent/26.0-android/a2c0df489614352b7e8e503e274bd1dee5c42a64/guava-parent-26.0-android.pom b/.gradle-user/caches/modules-2/files-2.1/com.google.guava/guava-parent/26.0-android/a2c0df489614352b7e8e503e274bd1dee5c42a64/guava-parent-26.0-android.pom new file mode 100644 index 0000000..7fd8054 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/com.google.guava/guava-parent/26.0-android/a2c0df489614352b7e8e503e274bd1dee5c42a64/guava-parent-26.0-android.pom @@ -0,0 +1,293 @@ + + + + 4.0.0 + + org.sonatype.oss + oss-parent + 9 + + com.google.guava + guava-parent + 26.0-android + pom + Guava Maven Parent + https://github.com/google/guava + + + %regex[.*.class] + 0.41 + 1.14 + 3.0.0 + + + GitHub Issues + https://github.com/google/guava/issues + + 2010 + + + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + 3.0.3 + + + scm:git:https://github.com/google/guava.git + scm:git:git@github.com:google/guava.git + https://github.com/google/guava + + + + kevinb9n + Kevin Bourrillion + kevinb@google.com + Google + http://www.google.com + + owner + developer + + -8 + + + + Travis CI + https://travis-ci.org/google/guava + + + guava + guava-testlib + guava-tests + + + + src + test + + + src + + **/*.java + + + + + + test + + **/*.java + + + + + + maven-javadoc-plugin + ${maven-javadoc-plugin.version} + + + + + + maven-compiler-plugin + 3.6.1 + + 1.7 + 1.7 + + + + maven-jar-plugin + 3.0.2 + + + **/ForceGuavaCompilation* + + + + + maven-source-plugin + 2.1.2 + + + attach-sources + post-integration-test + jar + + + + + **/ForceGuavaCompilation* + + + + + org.codehaus.mojo + animal-sniffer-maven-plugin + ${animal.sniffer.version} + + + org.codehaus.mojo.signature + java16-sun + 1.10 + + + + sun.misc.Unsafe + + + + + check-java-version-compatibility + test + + check + + + + + + maven-javadoc-plugin + ${maven-javadoc-plugin.version} + + true + true + UTF-8 + UTF-8 + UTF-8 + + -XDignore.symbol.file + -Xdoclint:-html + + true + + + + attach-docs + post-integration-test + jar + + + + + maven-dependency-plugin + 2.10 + + + maven-antrun-plugin + 1.6 + + + maven-surefire-plugin + 2.7.2 + + + ${test.include} + + + + + %regex[.*PackageSanityTests.*.class] + + %regex[.*Tester.class] + + %regex[.*[$]\d+.class] + + true + alphabetical + + + -Xmx1536M -Duser.language=hi -Duser.country=IN + + + + + + + + guava-site + Guava Documentation Site + scp://dummy.server/dontinstall/usestaging + + + + + + com.google.code.findbugs + jsr305 + 3.0.2 + + + org.checkerframework + checker-compat-qual + 2.5.2 + + + com.google.errorprone + error_prone_annotations + 2.1.3 + + + com.google.j2objc + j2objc-annotations + 1.1 + + + junit + junit + 4.11 + test + + + org.easymock + easymock + 3.0 + test + + + org.mockito + mockito-core + 2.19.0 + test + + + com.google.jimfs + jimfs + 1.1 + test + + + com.google.truth + truth + ${truth.version} + test + + + + com.google.guava + guava + + + + + com.google.caliper + caliper + 1.0-beta-2 + test + + + + com.google.guava + guava + + + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/com.google.guava/guava-parent/31.1-android/13c71653747af29c2b7b3293d00d3a1b0df3a841/guava-parent-31.1-android.pom b/.gradle-user/caches/modules-2/files-2.1/com.google.guava/guava-parent/31.1-android/13c71653747af29c2b7b3293d00d3a1b0df3a841/guava-parent-31.1-android.pom new file mode 100644 index 0000000..3784c9f --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/com.google.guava/guava-parent/31.1-android/13c71653747af29c2b7b3293d00d3a1b0df3a841/guava-parent-31.1-android.pom @@ -0,0 +1,408 @@ + + + + 4.0.0 + com.google.guava + guava-parent + 31.1-android + pom + Guava Maven Parent + Parent for guava artifacts + https://github.com/google/guava + + + %regex[.*.class] + 1.1.2 + 3.12.0 + 1.20 + 3.1.0 + + + 3.2.1 + UTF-8 + + + GitHub Issues + https://github.com/google/guava/issues + + 2010 + + + Apache License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + scm:git:https://github.com/google/guava.git + scm:git:git@github.com:google/guava.git + https://github.com/google/guava + + + + kevinb9n + Kevin Bourrillion + kevinb@google.com + Google + http://www.google.com + + owner + developer + + -8 + + + + GitHub Actions + https://github.com/google/guava/actions + + + guava + guava-bom + guava-testlib + guava-tests + + + + src + test + + + src + + **/*.java + **/*.sw* + + + + + + test + + **/*.java + + + + + + org.apache.maven.plugins + maven-enforcer-plugin + + + enforce-versions + + enforce + + + + + 3.0.5 + + + 1.8.0 + + + + + + + + maven-javadoc-plugin + ${maven-javadoc-plugin.version} + + + + + + maven-compiler-plugin + 3.8.1 + + 1.8 + 1.8 + + + -sourcepath + doesnotexist + + + + + maven-jar-plugin + 3.2.0 + + + maven-source-plugin + ${maven-source-plugin.version} + + + attach-sources + post-integration-test + jar + + + + + org.codehaus.mojo + animal-sniffer-maven-plugin + ${animal.sniffer.version} + + true + + org.codehaus.mojo.signature + java16-sun + 1.10 + + + + java.util.Objects + + sun.misc.Unsafe + + + + + check-java-version-compatibility + test + + check + + + + + + maven-javadoc-plugin + ${maven-javadoc-plugin.version} + + true + true + UTF-8 + UTF-8 + UTF-8 + + -XDignore.symbol.file + -Xdoclint:-html + + true + 8 + ${maven-javadoc-plugin.additionalJOptions} + + + + attach-docs + post-integration-test + jar + + + + + maven-dependency-plugin + 3.1.1 + + + maven-antrun-plugin + 1.6 + + + maven-surefire-plugin + 2.7.2 + + + ${test.include} + + + + + %regex[.*PackageSanityTests.*.class] + + %regex[.*Tester.class] + + %regex[.*[$]\d+.class] + + true + alphabetical + + + -Xmx1536M -Duser.language=hi -Duser.country=IN + + + + org.apache.maven.plugins + maven-enforcer-plugin + 3.0.0-M3 + + + + + + + sonatype-nexus-snapshots + Sonatype Nexus Snapshots + https://oss.sonatype.org/content/repositories/snapshots/ + + + sonatype-nexus-staging + Nexus Release Repository + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + + guava-site + Guava Documentation Site + scp://dummy.server/dontinstall/usestaging + + + + + + com.google.code.findbugs + jsr305 + 3.0.2 + + + org.checkerframework + checker-qual + ${checker-framework.version} + + + org.checkerframework + checker-qual + ${checker-framework.version} + sources + + + com.google.errorprone + error_prone_annotations + 2.11.0 + + + com.google.j2objc + j2objc-annotations + 1.3 + + + junit + junit + 4.13.2 + test + + + org.easymock + easymock + 4.3 + test + + + org.mockito + mockito-core + 3.9.0 + test + + + com.google.jimfs + jimfs + 1.2 + test + + + com.google.truth + truth + ${truth.version} + test + + + + com.google.guava + guava + + + + + com.google.caliper + caliper + 1.0-beta-2 + test + + + + com.google.guava + guava + + + + + + + + sonatype-oss-release + + + + org.apache.maven.plugins + maven-source-plugin + ${maven-source-plugin.version} + + + attach-sources + + jar-no-fork + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${maven-javadoc-plugin.version} + + + attach-javadocs + + jar + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.6 + + + sign-artifacts + verify + + sign + + + + + + + + + + javadocs-jdk9-12 + + [9,13) + + + --no-module-directories + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/com.google.guava/guava/31.1-android/9222c47cc3ae890f07f7c961bbb3cb69050fe4aa/guava-31.1-android.jar b/.gradle-user/caches/modules-2/files-2.1/com.google.guava/guava/31.1-android/9222c47cc3ae890f07f7c961bbb3cb69050fe4aa/guava-31.1-android.jar new file mode 100644 index 0000000..8ff77a8 Binary files /dev/null and b/.gradle-user/caches/modules-2/files-2.1/com.google.guava/guava/31.1-android/9222c47cc3ae890f07f7c961bbb3cb69050fe4aa/guava-31.1-android.jar differ diff --git a/.gradle-user/caches/modules-2/files-2.1/com.google.guava/guava/31.1-android/d3b929509399a698915b24ff47db781d0c526760/guava-31.1-android.pom b/.gradle-user/caches/modules-2/files-2.1/com.google.guava/guava/31.1-android/d3b929509399a698915b24ff47db781d0c526760/guava-31.1-android.pom new file mode 100644 index 0000000..39611d4 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/com.google.guava/guava/31.1-android/d3b929509399a698915b24ff47db781d0c526760/guava-31.1-android.pom @@ -0,0 +1,253 @@ + + + 4.0.0 + + com.google.guava + guava-parent + 31.1-android + + guava + bundle + Guava: Google Core Libraries for Java + https://github.com/google/guava + + Guava is a suite of core and expanded libraries that include + utility classes, Google's collections, I/O classes, and + much more. + + + + com.google.guava + failureaccess + 1.0.1 + + + com.google.guava + listenablefuture + 9999.0-empty-to-avoid-conflict-with-guava + + + com.google.code.findbugs + jsr305 + + + org.checkerframework + checker-qual + + + com.google.errorprone + error_prone_annotations + + + com.google.j2objc + j2objc-annotations + + + + + + + + maven-jar-plugin + + + + com.google.common + + + + + + true + org.apache.felix + maven-bundle-plugin + 2.5.0 + + + bundle-manifest + process-classes + + manifest + + + + + + + !com.google.common.base.internal, + !com.google.common.util.concurrent.internal, + com.google.common.* + + + com.google.common.util.concurrent.internal, + javax.annotation;resolution:=optional, + javax.crypto.*;resolution:=optional, + sun.misc.*;resolution:=optional + + https://github.com/google/guava/ + + + + + maven-compiler-plugin + + + maven-source-plugin + + + + maven-dependency-plugin + + + unpack-jdk-sources + generate-sources + unpack-dependencies + + srczip + ${project.build.directory}/jdk-sources + false + + **/module-info.java,**/java/io/FileDescriptor.java + + + + + + org.codehaus.mojo + animal-sniffer-maven-plugin + + + maven-javadoc-plugin + + + + + ${project.build.sourceDirectory}:${project.build.directory}/jdk-sources + + + + + com.azul.tooling.in,com.google.common.base.internal,com.google.common.base.internal.*,com.google.thirdparty.publicsuffix,com.google.thirdparty.publicsuffix.*,com.oracle.*,com.sun.*,java.*,javax.*,jdk,jdk.*,org.*,sun.* + + + + + apiNote + X + + + implNote + X + + + implSpec + X + + + jls + X + + + revised + X + + + spec + X + + + + + + false + + + + + https://static.javadoc.io/com.google.code.findbugs/jsr305/3.0.1/ + ${project.basedir}/javadoc-link/jsr305 + + + https://static.javadoc.io/com.google.j2objc/j2objc-annotations/1.1/ + ${project.basedir}/javadoc-link/j2objc-annotations + + + + https://docs.oracle.com/javase/9/docs/api/ + https://docs.oracle.com/javase/9/docs/api/ + + + + https://checkerframework.org/api/ + ${project.basedir}/javadoc-link/checker-framework + + + + https://errorprone.info/api/latest/ + + + + + attach-docs + + + generate-javadoc-site-report + site + javadoc + + + + + + + + srczip-parent + + + ${java.home}/../src.zip + + + + + jdk + srczip + 999 + system + ${java.home}/../src.zip + true + + + + + srczip-lib + + + ${java.home}/lib/src.zip + + + + + jdk + srczip + 999 + system + ${java.home}/lib/src.zip + true + + + + + + maven-javadoc-plugin + + + ${project.build.sourceDirectory}:${project.build.directory}/jdk-sources/java.base + + + + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/com.google.guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/1b77ba79f9b2b7dfd4e15ea7bb0d568d5eb9cb8d/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.pom b/.gradle-user/caches/modules-2/files-2.1/com.google.guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/1b77ba79f9b2b7dfd4e15ea7bb0d568d5eb9cb8d/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.pom new file mode 100644 index 0000000..ad3f23e --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/com.google.guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/1b77ba79f9b2b7dfd4e15ea7bb0d568d5eb9cb8d/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.pom @@ -0,0 +1,56 @@ + + + 4.0.0 + + com.google.guava + guava-parent + 26.0-android + + listenablefuture + 9999.0-empty-to-avoid-conflict-with-guava + Guava ListenableFuture only + + An empty artifact that Guava depends on to signal that it is providing + ListenableFuture -- but is also available in a second "version" that + contains com.google.common.util.concurrent.ListenableFuture class, without + any other Guava classes. The idea is: + + - If users want only ListenableFuture, they depend on listenablefuture-1.0. + + - If users want all of Guava, they depend on guava, which, as of Guava + 27.0, depends on + listenablefuture-9999.0-empty-to-avoid-conflict-with-guava. The 9999.0-... + version number is enough for some build systems (notably, Gradle) to select + that empty artifact over the "real" listenablefuture-1.0 -- avoiding a + conflict with the copy of ListenableFuture in guava itself. If users are + using an older version of Guava or a build system other than Gradle, they + may see class conflicts. If so, they can solve them by manually excluding + the listenablefuture artifact or manually forcing their build systems to + use 9999.0-.... + + + + + maven-source-plugin + + + org.codehaus.mojo + animal-sniffer-maven-plugin + + + maven-javadoc-plugin + + + attach-docs + + + generate-javadoc-site-report + site + javadoc + + + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/com.google.guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/b421526c5f297295adef1c886e5246c39d4ac629/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar b/.gradle-user/caches/modules-2/files-2.1/com.google.guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/b421526c5f297295adef1c886e5246c39d4ac629/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar new file mode 100644 index 0000000..45832c0 Binary files /dev/null and b/.gradle-user/caches/modules-2/files-2.1/com.google.guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/b421526c5f297295adef1c886e5246c39d4ac629/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar differ diff --git a/.gradle-user/caches/modules-2/files-2.1/com.google.j2objc/j2objc-annotations/1.3/47e0dd93285dcc6b33181713bc7e8aed66742964/j2objc-annotations-1.3.pom b/.gradle-user/caches/modules-2/files-2.1/com.google.j2objc/j2objc-annotations/1.3/47e0dd93285dcc6b33181713bc7e8aed66742964/j2objc-annotations-1.3.pom new file mode 100644 index 0000000..d32414a --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/com.google.j2objc/j2objc-annotations/1.3/47e0dd93285dcc6b33181713bc7e8aed66742964/j2objc-annotations-1.3.pom @@ -0,0 +1,87 @@ + + + + 4.0.0 + + + org.sonatype.oss + oss-parent + 7 + + + com.google.j2objc + j2objc-annotations + jar + 1.3 + + J2ObjC Annotations + + A set of annotations that provide additional information to the J2ObjC + translator to modify the result of translation. + + https://github.com/google/j2objc/ + + + + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.10.3 + + + generate-docs + package + jar + + + + + org.apache.maven.plugins + maven-source-plugin + 2.4 + + + generate-sources + package + jar-no-fork + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.6 + + + sign-artifacts + verify + sign + + + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/com.google.j2objc/j2objc-annotations/1.3/ba035118bc8bac37d7eff77700720999acd9986d/j2objc-annotations-1.3.jar b/.gradle-user/caches/modules-2/files-2.1/com.google.j2objc/j2objc-annotations/1.3/ba035118bc8bac37d7eff77700720999acd9986d/j2objc-annotations-1.3.jar new file mode 100644 index 0000000..a429c72 Binary files /dev/null and b/.gradle-user/caches/modules-2/files-2.1/com.google.j2objc/j2objc-annotations/1.3/ba035118bc8bac37d7eff77700720999acd9986d/j2objc-annotations-1.3.jar differ diff --git a/.gradle-user/caches/modules-2/files-2.1/com.gradleup.shadow/com.gradleup.shadow.gradle.plugin/8.3.6/80f0fb84cbad09511dab8593c5546815bb3cee46/com.gradleup.shadow.gradle.plugin-8.3.6.pom b/.gradle-user/caches/modules-2/files-2.1/com.gradleup.shadow/com.gradleup.shadow.gradle.plugin/8.3.6/80f0fb84cbad09511dab8593c5546815bb3cee46/com.gradleup.shadow.gradle.plugin-8.3.6.pom new file mode 100644 index 0000000..ed0c010 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/com.gradleup.shadow/com.gradleup.shadow.gradle.plugin/8.3.6/80f0fb84cbad09511dab8593c5546815bb3cee46/com.gradleup.shadow.gradle.plugin-8.3.6.pom @@ -0,0 +1,14 @@ + + 4.0.0 + com.gradleup.shadow + com.gradleup.shadow.gradle.plugin + 8.3.6 + pom + + + com.gradleup.shadow + shadow-gradle-plugin + 8.3.6 + + + \ No newline at end of file diff --git a/.gradle-user/caches/modules-2/files-2.1/com.gradleup.shadow/shadow-gradle-plugin/8.3.6/dd6b3e8ea0e641aab39774dbe3924126d5948813/shadow-gradle-plugin-8.3.6.pom b/.gradle-user/caches/modules-2/files-2.1/com.gradleup.shadow/shadow-gradle-plugin/8.3.6/dd6b3e8ea0e641aab39774dbe3924126d5948813/shadow-gradle-plugin-8.3.6.pom new file mode 100644 index 0000000..49ac094 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/com.gradleup.shadow/shadow-gradle-plugin/8.3.6/dd6b3e8ea0e641aab39774dbe3924126d5948813/shadow-gradle-plugin-8.3.6.pom @@ -0,0 +1,86 @@ + + + + + + + + 4.0.0 + com.gradleup.shadow + shadow-gradle-plugin + 8.3.6 + Shadow Gradle Plugin + Gradle plugin to create fat/uber JARs, apply file transforms, and relocate packages for applications and libraries. Gradle version of Maven's Shade plugin. + https://github.com/GradleUp/shadow + 2024 + + + Apache-2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + gradleup + GradleUp developers + https://github.com/GradleUp + + + + scm:git:git://github.com/GradleUp/shadow.git + scm:git:ssh://git@github.com/GradleUp/shadow.git + https://github.com/GradleUp/shadow + + + + org.jdom + jdom2 + 2.0.6.1 + runtime + + + org.ow2.asm + asm-commons + 9.7.1 + runtime + + + commons-io + commons-io + 2.17.0 + runtime + + + org.apache.ant + ant + 1.10.15 + runtime + + + org.codehaus.plexus + plexus-utils + 4.0.2 + runtime + + + org.codehaus.plexus + plexus-xml + 4.0.4 + runtime + + + org.apache.logging.log4j + log4j-core + 2.24.1 + runtime + + + org.vafer + jdependency + 2.12 + runtime + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/com.gradleup.shadow/shadow-gradle-plugin/8.3.6/f1586fec7dcd851eb91cab4c1f7cf50c6d04b73c/shadow-gradle-plugin-8.3.6.module b/.gradle-user/caches/modules-2/files-2.1/com.gradleup.shadow/shadow-gradle-plugin/8.3.6/f1586fec7dcd851eb91cab4c1f7cf50c6d04b73c/shadow-gradle-plugin-8.3.6.module new file mode 100644 index 0000000..4b7d371 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/com.gradleup.shadow/shadow-gradle-plugin/8.3.6/f1586fec7dcd851eb91cab4c1f7cf50c6d04b73c/shadow-gradle-plugin-8.3.6.module @@ -0,0 +1,286 @@ +{ + "formatVersion": "1.1", + "component": { + "group": "com.gradleup.shadow", + "module": "shadow-gradle-plugin", + "version": "8.3.6", + "attributes": { + "org.gradle.status": "release" + } + }, + "createdBy": { + "gradle": { + "version": "8.12.1" + } + }, + "variants": [ + { + "name": "apiElements", + "attributes": { + "org.gradle.category": "library", + "org.gradle.dependency.bundling": "external", + "org.gradle.jvm.version": 8, + "org.gradle.libraryelements": "jar", + "org.gradle.usage": "java-api" + }, + "files": [ + { + "name": "shadow-gradle-plugin-8.3.6.jar", + "url": "shadow-gradle-plugin-8.3.6.jar", + "size": 350260, + "sha512": "dd93db129569c6011699182380f0ec09d8b105c198b818f83c08df9dcd2f63aca199d97a3e0145ba6d4c0fc5105d8d1d666bcb3cd8142926f582603fe54efc31", + "sha256": "7ce20ebf01ee29eec524563bd142bac291d75135ed79d0d951a98fd2c9265c3b", + "sha1": "ff5e250da1a3b935c85246e2ac5af562bc53599c", + "md5": "fd1d5ffcb55ea8cd84116891146d0364" + } + ], + "capabilities": [ + { + "group": "com.github.johnrengelman", + "name": "shadow", + "version": "8.3.6" + }, + { + "group": "com.github.jengelman.gradle.plugins", + "name": "shadow", + "version": "8.3.6" + }, + { + "group": "com.gradleup.shadow", + "name": "shadow-gradle-plugin", + "version": "8.3.6" + }, + { + "group": "io.github.goooler.shadow", + "name": "shadow-gradle-plugin", + "version": "8.3.6" + }, + { + "group": "gradle.plugin.com.github.jengelman.gradle.plugins", + "name": "shadow", + "version": "8.3.6" + }, + { + "group": "gradle.plugin.com.github.johnrengelman", + "name": "shadow", + "version": "8.3.6" + } + ] + }, + { + "name": "runtimeElements", + "attributes": { + "org.gradle.category": "library", + "org.gradle.dependency.bundling": "external", + "org.gradle.jvm.version": 8, + "org.gradle.libraryelements": "jar", + "org.gradle.usage": "java-runtime" + }, + "dependencies": [ + { + "group": "org.jdom", + "module": "jdom2", + "version": { + "requires": "2.0.6.1" + } + }, + { + "group": "org.ow2.asm", + "module": "asm-commons", + "version": { + "requires": "9.7.1" + } + }, + { + "group": "commons-io", + "module": "commons-io", + "version": { + "requires": "2.17.0" + } + }, + { + "group": "org.apache.ant", + "module": "ant", + "version": { + "requires": "1.10.15" + } + }, + { + "group": "org.codehaus.plexus", + "module": "plexus-utils", + "version": { + "requires": "4.0.2" + } + }, + { + "group": "org.codehaus.plexus", + "module": "plexus-xml", + "version": { + "requires": "4.0.4" + } + }, + { + "group": "org.apache.logging.log4j", + "module": "log4j-core", + "version": { + "requires": "2.24.1" + } + }, + { + "group": "org.vafer", + "module": "jdependency", + "version": { + "requires": "2.12" + } + } + ], + "files": [ + { + "name": "shadow-gradle-plugin-8.3.6.jar", + "url": "shadow-gradle-plugin-8.3.6.jar", + "size": 350260, + "sha512": "dd93db129569c6011699182380f0ec09d8b105c198b818f83c08df9dcd2f63aca199d97a3e0145ba6d4c0fc5105d8d1d666bcb3cd8142926f582603fe54efc31", + "sha256": "7ce20ebf01ee29eec524563bd142bac291d75135ed79d0d951a98fd2c9265c3b", + "sha1": "ff5e250da1a3b935c85246e2ac5af562bc53599c", + "md5": "fd1d5ffcb55ea8cd84116891146d0364" + } + ], + "capabilities": [ + { + "group": "com.github.johnrengelman", + "name": "shadow", + "version": "8.3.6" + }, + { + "group": "com.github.jengelman.gradle.plugins", + "name": "shadow", + "version": "8.3.6" + }, + { + "group": "com.gradleup.shadow", + "name": "shadow-gradle-plugin", + "version": "8.3.6" + }, + { + "group": "io.github.goooler.shadow", + "name": "shadow-gradle-plugin", + "version": "8.3.6" + }, + { + "group": "gradle.plugin.com.github.jengelman.gradle.plugins", + "name": "shadow", + "version": "8.3.6" + }, + { + "group": "gradle.plugin.com.github.johnrengelman", + "name": "shadow", + "version": "8.3.6" + } + ] + }, + { + "name": "sourcesElements", + "attributes": { + "org.gradle.category": "documentation", + "org.gradle.dependency.bundling": "external", + "org.gradle.docstype": "sources", + "org.gradle.usage": "java-runtime" + }, + "files": [ + { + "name": "shadow-gradle-plugin-8.3.6-sources.jar", + "url": "shadow-gradle-plugin-8.3.6-sources.jar", + "size": 65504, + "sha512": "ccce862135bf2da70c7e62482d94d118acc344aea083651ab1620c18234c69d3cb3432f1672de25dc8408b040cb7b5205ed05c85da8f561222de4ea035305003", + "sha256": "075c092aa2f3a0d0bd785a985f18e613f391cbb5b9bc8a878a624ecdb9295894", + "sha1": "cae2217bfbbc4dcf65c34ea3442482377126a638", + "md5": "e133c974fac597c871fb895446133eba" + } + ], + "capabilities": [ + { + "group": "com.github.johnrengelman", + "name": "shadow", + "version": "8.3.6" + }, + { + "group": "com.github.jengelman.gradle.plugins", + "name": "shadow", + "version": "8.3.6" + }, + { + "group": "com.gradleup.shadow", + "name": "shadow-gradle-plugin", + "version": "8.3.6" + }, + { + "group": "io.github.goooler.shadow", + "name": "shadow-gradle-plugin", + "version": "8.3.6" + }, + { + "group": "gradle.plugin.com.github.jengelman.gradle.plugins", + "name": "shadow", + "version": "8.3.6" + }, + { + "group": "gradle.plugin.com.github.johnrengelman", + "name": "shadow", + "version": "8.3.6" + } + ] + }, + { + "name": "javadocElements", + "attributes": { + "org.gradle.category": "documentation", + "org.gradle.dependency.bundling": "external", + "org.gradle.docstype": "javadoc", + "org.gradle.usage": "java-runtime" + }, + "files": [ + { + "name": "shadow-gradle-plugin-8.3.6-javadoc.jar", + "url": "shadow-gradle-plugin-8.3.6-javadoc.jar", + "size": 98773, + "sha512": "0b693a8fc56e0ef685cd7645d2f80f7db367ecc9bddd98b04c474c15f53a24d4452dfa2979567e7faf3379e2dbb6796de11b742d67840e0392584c9c7295d3e0", + "sha256": "c1b2c9d0bc23e12b6d4b8341efe045ff4ba61c8906032db22e8fda9c2dcadf7f", + "sha1": "21641b38132305a43cbef5bfc64d34901de3c4e5", + "md5": "192ac2ffc5842ae2728d22b8aba06e4c" + } + ], + "capabilities": [ + { + "group": "com.github.johnrengelman", + "name": "shadow", + "version": "8.3.6" + }, + { + "group": "com.github.jengelman.gradle.plugins", + "name": "shadow", + "version": "8.3.6" + }, + { + "group": "com.gradleup.shadow", + "name": "shadow-gradle-plugin", + "version": "8.3.6" + }, + { + "group": "io.github.goooler.shadow", + "name": "shadow-gradle-plugin", + "version": "8.3.6" + }, + { + "group": "gradle.plugin.com.github.jengelman.gradle.plugins", + "name": "shadow", + "version": "8.3.6" + }, + { + "group": "gradle.plugin.com.github.johnrengelman", + "name": "shadow", + "version": "8.3.6" + } + ] + } + ] +} diff --git a/.gradle-user/caches/modules-2/files-2.1/com.gradleup.shadow/shadow-gradle-plugin/8.3.6/ff5e250da1a3b935c85246e2ac5af562bc53599c/shadow-gradle-plugin-8.3.6.jar b/.gradle-user/caches/modules-2/files-2.1/com.gradleup.shadow/shadow-gradle-plugin/8.3.6/ff5e250da1a3b935c85246e2ac5af562bc53599c/shadow-gradle-plugin-8.3.6.jar new file mode 100644 index 0000000..a9cae47 Binary files /dev/null and b/.gradle-user/caches/modules-2/files-2.1/com.gradleup.shadow/shadow-gradle-plugin/8.3.6/ff5e250da1a3b935c85246e2ac5af562bc53599c/shadow-gradle-plugin-8.3.6.jar differ diff --git a/.gradle-user/caches/modules-2/files-2.1/commons-io/commons-io/2.17.0/af3aa19bcc67a14e5d0dad042e7d985f733cdff4/commons-io-2.17.0.pom b/.gradle-user/caches/modules-2/files-2.1/commons-io/commons-io/2.17.0/af3aa19bcc67a14e5d0dad042e7d985f733cdff4/commons-io-2.17.0.pom new file mode 100644 index 0000000..d3146fe --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/commons-io/commons-io/2.17.0/af3aa19bcc67a14e5d0dad042e7d985f733cdff4/commons-io-2.17.0.pom @@ -0,0 +1,600 @@ + + + + + org.apache.commons + commons-parent + 74 + + 4.0.0 + commons-io + commons-io + 2.17.0 + Apache Commons IO + + 2002 + +The Apache Commons IO library contains utility classes, stream implementations, file filters, +file comparators, endian transformation classes, and much more. + + + https://commons.apache.org/proper/commons-io/ + + + jira + https://issues.apache.org/jira/browse/IO + + + + + apache.website + Apache Commons Site + scm:svn:https://svn.apache.org/repos/infra/websites/production/commons/content/proper/commons-io/ + + + + + scm:git:https://gitbox.apache.org/repos/asf/commons-io.git + scm:git:https://gitbox.apache.org/repos/asf/commons-io.git + https://gitbox.apache.org/repos/asf?p=commons-io.git + rel/commons-io-2.17.0 + + + + + org.junit.jupiter + junit-jupiter + test + + + org.junit-pioneer + junit-pioneer + 1.9.1 + test + + + + net.bytebuddy + byte-buddy + ${commons.bytebuddy.version} + test + + + + net.bytebuddy + byte-buddy-agent + ${commons.bytebuddy.version} + test + + + org.mockito + mockito-inline + 4.11.0 + test + + + com.google.jimfs + jimfs + 1.3.0 + test + + + org.apache.commons + commons-lang3 + 3.17.0 + test + + + commons-codec + commons-codec + 1.17.1 + test + + + org.openjdk.jmh + jmh-core + ${jmh.version} + test + + + org.openjdk.jmh + jmh-generator-annprocess + ${jmh.version} + test + + + + + 1.8 + 1.8 + io + org.apache.commons.io + RC1 + 2.16.1 + 2.17.0 + 2.17.1 + 2024-09-15T14:44:33Z + (requires Java 8) + IO + 12310477 + + + org.apache.commons.io; + org.apache.commons.io.comparator; + org.apache.commons.io.filefilter; + org.apache.commons.io.input; + org.apache.commons.io.output;version=1.4.9999;-noimport:=true, + + org.apache.commons.io; + org.apache.commons.io.comparator; + org.apache.commons.io.filefilter; + org.apache.commons.io.input; + org.apache.commons.io.output; + org.apache.commons.io.*;version=${project.version};-noimport:=true + + + + sun.nio.ch;resolution:=optional, + sun.misc;resolution:=optional, + * + + https://svn.apache.org/repos/infra/websites/production/commons/content/proper/commons-io/ + site-content + 1.37 + 1.15.1 + false + true + + ${env.JACOCO_SKIP} + true + 0.98 + 0.90 + 0.90 + 0.85 + 0.90 + 0.85 + + + + clean verify apache-rat:check japicmp:cmp checkstyle:check spotbugs:check pmd:check javadoc:javadoc + + + + org.apache.rat + apache-rat-plugin + + + src/test/resources/**/*.bin + src/test/resources/dir-equals-tests/** + test/** + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + ${basedir}/src/conf/checkstyle.xml + ${basedir}/src/conf/checkstyle-suppressions.xml + false + true + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + test-jar + + + + + + + ${commons.module.name} + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + xerces:xercesImpl + + 1 + false + + + ${argLine} -Xmx25M + + + **/*Test*.class + + + **/*AbstractTestCase* + **/testtools/** + + **/*$* + + + + + maven-assembly-plugin + + + src/assembly/bin.xml + src/assembly/src.xml + + gnu + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + + org.apache.maven.plugins + maven-scm-publish-plugin + + + javadocs + + + + + com.github.spotbugs + spotbugs-maven-plugin + + ${basedir}/src/conf/spotbugs-exclude-filter.xml + + + + com.github.siom79.japicmp + japicmp-maven-plugin + + + org.apache.maven.plugins + maven-pmd-plugin + + + src/conf/maven-pmd-plugin.xml + + + + + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + + com.github.spotbugs + spotbugs-maven-plugin + + ${basedir}/src/conf/spotbugs-exclude-filter.xml + + + + com.github.siom79.japicmp + japicmp-maven-plugin + + + + + org.apache.commons.io.StreamIterator + + + + + + + + + setup-checkout + + + site-content + + + + + + org.apache.maven.plugins + maven-antrun-plugin + 3.1.0 + + + prepare-checkout + pre-site + + run + + + + + + + + + + + + + + + + + + + + + + + + + java9-compile + + [9,) + + + 8 + + + + benchmark + + true + org.apache + + + + + org.codehaus.mojo + exec-maven-plugin + + + benchmark + test + + exec + + + test + java + + -classpath + + org.openjdk.jmh.Main + -rf + json + -rff + target/jmh-result.${benchmark}.json + ${benchmark} + + + + + + + + + + + + + Scott Sanders + sanders + sanders@apache.org + + + Java Developer + + + + dIon Gillard + + dion + dion@apache.org + + + Java Developer + + + + Nicola Ken Barozzi + nicolaken + nicolaken@apache.org + + + Java Developer + + + + Henri Yandell + bayard + bayard@apache.org + + + Java Developer + + + + Stephen Colebourne + scolebourne + + + Java Developer + + 0 + + + Jeremias Maerki + jeremias + jeremias@apache.org + + + Java Developer + + +1 + + + Matthew Hawthorne + matth + matth@apache.org + + + Java Developer + + + + Martin Cooper + martinc + martinc@apache.org + + + Java Developer + + + + Rob Oxspring + roxspring + roxspring@apache.org + + + Java Developer + + + + Jochen Wiedmann + jochen + jochen.wiedmann@gmail.com + + + Niall Pemberton + niallp + + Java Developer + + + + Jukka Zitting + jukka + + Java Developer + + + + ggregory + Gary Gregory + ggregory at apache.org + https://www.garygregory.com + The Apache Software Foundation + https://www.apache.org/ + + PMC Member + + America/New_York + + https://people.apache.org/~ggregory/img/garydgregory80.png + + + + Kristian Rosenvold + krosenvold + krosenvold@apache.org + +1 + + + + + + Rahul Akolkar + + + Jason Anderson + + + Nathan Beyer + + + Emmanuel Bourg + + + Chris Eldredge + + + Magnus Grimsell + + + Jim Harrington + + + Thomas Ledoux + + + Andy Lehane + + + Marcelo Liberato + + + Alban Peignier + alban.peignier at free.fr + + + Adam Retter + Evolved Binary + + + Ian Springer + + + Dominik Stadler + + + Masato Tezuka + + + James Urie + + + Frank W. Zammetti + + + Martin Grigorov + mgrigorov@apache.org + + + Arturo Bernal + + + Miguel Muñoz + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/commons-io/commons-io/2.17.0/ddcc8433eb019fb48fe25207c0278143f3e1d7e2/commons-io-2.17.0.jar b/.gradle-user/caches/modules-2/files-2.1/commons-io/commons-io/2.17.0/ddcc8433eb019fb48fe25207c0278143f3e1d7e2/commons-io-2.17.0.jar new file mode 100644 index 0000000..ad00ddc Binary files /dev/null and b/.gradle-user/caches/modules-2/files-2.1/commons-io/commons-io/2.17.0/ddcc8433eb019fb48fe25207c0278143f3e1d7e2/commons-io-2.17.0.jar differ diff --git a/.gradle-user/caches/modules-2/files-2.1/jakarta.platform/jakarta.jakartaee-bom/9.1.0/39a915229cabfe6bba43e0566b1a74bf8fe3eefe/jakarta.jakartaee-bom-9.1.0.pom b/.gradle-user/caches/modules-2/files-2.1/jakarta.platform/jakarta.jakartaee-bom/9.1.0/39a915229cabfe6bba43e0566b1a74bf8fe3eefe/jakarta.jakartaee-bom-9.1.0.pom new file mode 100644 index 0000000..920a230 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/jakarta.platform/jakarta.jakartaee-bom/9.1.0/39a915229cabfe6bba43e0566b1a74bf8fe3eefe/jakarta.jakartaee-bom-9.1.0.pom @@ -0,0 +1,220 @@ + + + + + 4.0.0 + + jakarta.platform + jakartaee-api-parent + 9.1.0 + + jakarta.jakartaee-bom + pom + Jakarta EE API BOM + Jakarta EE API BOM + + + + + org.glassfish.build + glassfishbuild-maven-plugin + + + generate-pom + + generate-pom + + + + attach-all-artifacts + + attach-all-artifacts + + + + + + + + + + + + jakarta.servlet + jakarta.servlet-api + ${jakarta.servlet-api.version} + + + jakarta.servlet.jsp + jakarta.servlet.jsp-api + ${jakarta.servlet.jsp-api.version} + + + jakarta.el + jakarta.el-api + ${jakarta.el-api.version} + + + jakarta.servlet.jsp.jstl + jakarta.servlet.jsp.jstl-api + ${jakarta.servlet.jsp.jstl-api.version} + + + jakarta.faces + jakarta.faces-api + ${jakarta.faces-api.version} + + + jakarta.ws.rs + jakarta.ws.rs-api + ${jakarta.ws.rs-api.version} + + + jakarta.websocket + jakarta.websocket-api + ${jakarta.websocket-api.version} + + + jakarta.json + jakarta.json-api + ${jakarta.json-api.version} + + + jakarta.json.bind + jakarta.json.bind-api + ${jakarta.json.bind-api.version} + + + jakarta.annotation + jakarta.annotation-api + ${jakarta.annotation-api.version} + + + jakarta.ejb + jakarta.ejb-api + ${jakarta.ejb-api.version} + + + jakarta.transaction + jakarta.transaction-api + ${jakarta.transaction-api.version} + + + jakarta.persistence + jakarta.persistence-api + ${jakarta.persistence-api.version} + + + jakarta.validation + jakarta.validation-api + ${jakarta.validation-api.version} + + + jakarta.interceptor + jakarta.interceptor-api + ${jakarta.interceptor-api.version} + + + jakarta.enterprise + jakarta.enterprise.cdi-api + ${jakarta.enterprise.cdi-api.version} + + + jakarta.inject + jakarta.inject-api + ${jakarta.inject.version} + + + jakarta.authentication + jakarta.authentication-api + ${jakarta.authentication-api.version} + + + jakarta.security.enterprise + jakarta.security.enterprise-api + ${jakarta.security.enterprise-api.version} + + + + + jakarta.jms + jakarta.jms-api + ${jakarta.jms-api.version} + + + jakarta.activation + jakarta.activation-api + ${jakarta.activation-api.version} + + + jakarta.mail + jakarta.mail-api + ${jakarta.mail-api.version} + + + com.sun.mail + jakarta.mail + ${jakarta.mail-api.version} + + + jakarta.resource + jakarta.resource-api + ${jakarta.resource-api.version} + + + jakarta.authorization + jakarta.authorization-api + ${jakarta.authorization-api.version} + + + jakarta.enterprise.concurrent + jakarta.enterprise.concurrent-api + ${jakarta.enterprise.concurrent-api.version} + + + jakarta.batch + jakarta.batch-api + ${jakarta.batch-api.version} + + + + + jakarta.xml.bind + jakarta.xml.bind-api + ${jakarta.xml.bind-api.version} + + + jakarta.xml.ws + jakarta.xml.ws-api + ${jakarta.xml.ws-api.version} + + + jakarta.jws + jakarta.jws-api + ${jakarta.jws-api.version} + + + jakarta.xml.soap + jakarta.xml.soap-api + ${jakarta.xml.soap-api.version} + + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/jakarta.platform/jakartaee-api-parent/9.1.0/e5020a636b3c0cc4c5dd110e17213aaded1d6895/jakartaee-api-parent-9.1.0.pom b/.gradle-user/caches/modules-2/files-2.1/jakarta.platform/jakartaee-api-parent/9.1.0/e5020a636b3c0cc4c5dd110e17213aaded1d6895/jakartaee-api-parent-9.1.0.pom new file mode 100644 index 0000000..4915538 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/jakarta.platform/jakartaee-api-parent/9.1.0/e5020a636b3c0cc4c5dd110e17213aaded1d6895/jakartaee-api-parent-9.1.0.pom @@ -0,0 +1,320 @@ + + + + + 4.0.0 + + org.eclipse.ee4j + project + 1.0.7 + + jakarta.platform + jakartaee-api-parent + 9.1.0 + pom + Jakarta EE API parent + Jakarta EE API parent + + + jakartaee-bom + jakartaee-web-api + jakartaee-api + + + + UTF-8 + 9.0.0 + + + + 5.0.0 + 3.0.0 + 2.0.0 + 3.0.0 + 4.0.0 + 2.0.0 + 2.0.1 + 2.0.0 + 2.0.0 + 4.0.0 + 2.0.0 + 3.0.0 + 3.0.0 + 2.0.0 + 3.0.0 + 2.0.0 + 2.0.0 + 2.0.0 + 3.0.0 + + + 3.0.0 + 2.0.1 + 2.0.1 + 2.0.0 + 2.0.0 + 2.0.0 + 2.0.0 + + + 3.0.1 + 3.0.1 + 2.0.1 + 3.0.0 + + + 1.50 + + + 3.0.0 + + + + + package + + + org.apache.maven.plugins + maven-jar-plugin + + true + + + false + false + false + + + + + + org.apache.maven.plugins + maven-resources-plugin + + + copy-resource-files + process-resources + + copy-resources + + + + + ${project.build.directory}/sources-dependency + + **/*.properties + + + + ${project.build.directory}/classes + + + + copy-javadoc-resources + process-resources + + copy-resources + + + + + ${project.build.directory}/sources-dependency + + **/*.jpg + **/*.gif + **/*.pdf + + + + ${project.build.directory}/site/apidocs + + + + + + maven-compiler-plugin + + + default-compile + + 1.8 + 1.8 + + + + + default-testCompile + + 1.8 + 1.8 + + + + + + org.apache.maven.plugins + maven-deploy-plugin + + true + + false + + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + org.apache.maven.plugins + maven-resources-plugin + 2.4.3 + + + org.apache.maven.plugins + maven-compiler-plugin + 3.7.0 + + + org.apache.maven.plugins + maven-source-plugin + 2.1 + + true + + + + org.apache.maven.plugins + maven-deploy-plugin + 2.8.2 + + + org.glassfish.build + glassfishbuild-maven-plugin + 3.2.28 + + + unpack-sources + process-sources + + true + tools-jar,servlet-api,jakarta.faces + ${extra.excludes} + jakarta/**, resources/** + true + + + + generate-pom + package + + + org.eclipse.ee4j + project + 1.0 + + jakarta.platform + ${project.artifactId} + ${jakartaee.version} + + + + attach-all-artifacts + verify + + ${project.build.directory}/pom.xml + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.1.0 + + false + ${javadoc.options} + true + ${project.basedir}/../src/main/javadoc + true + none + ${project.name} + ${project.name} +
${project.name} v${project.version}]]>
+ +Copyright © 2018,2020 Eclipse Foundation.
Use is subject to +license terms.]]> +
+ + + implSpec + a + Implementation Specification: + + +
+
+
+
+ + + META-INF/ + false + ${project.basedir}/.. + + LICENSE.txt + + + +
+ + + + + check-serial-version-uid + + + + org.apache.maven.plugins + maven-compiler-plugin + + false + true + + -Xlint:serial + + + + + + + +
diff --git a/.gradle-user/caches/modules-2/files-2.1/org.apache.ant/ant-launcher/1.10.15/81431ce614ae38b187de683381f4a35a1db3b1c6/ant-launcher-1.10.15.jar b/.gradle-user/caches/modules-2/files-2.1/org.apache.ant/ant-launcher/1.10.15/81431ce614ae38b187de683381f4a35a1db3b1c6/ant-launcher-1.10.15.jar new file mode 100644 index 0000000..62c3e47 Binary files /dev/null and b/.gradle-user/caches/modules-2/files-2.1/org.apache.ant/ant-launcher/1.10.15/81431ce614ae38b187de683381f4a35a1db3b1c6/ant-launcher-1.10.15.jar differ diff --git a/.gradle-user/caches/modules-2/files-2.1/org.apache.ant/ant-launcher/1.10.15/96261c9c141aacb79d84fba9f194334e54863f0c/ant-launcher-1.10.15.pom b/.gradle-user/caches/modules-2/files-2.1/org.apache.ant/ant-launcher/1.10.15/96261c9c141aacb79d84fba9f194334e54863f0c/ant-launcher-1.10.15.pom new file mode 100644 index 0000000..cb3187b --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.apache.ant/ant-launcher/1.10.15/96261c9c141aacb79d84fba9f194334e54863f0c/ant-launcher-1.10.15.pom @@ -0,0 +1,82 @@ + + + + + + org.apache.ant + ant-parent + ../pom.xml + 1.10.15 + + 4.0.0 + https://ant.apache.org/ + org.apache.ant + ant-launcher + 1.10.15 + Apache Ant Launcher + + + + org.apache.maven.plugins + maven-compiler-plugin + + + org/apache/tools/ant/launch/*.java + + + org/apache/tools/ant/launch/*.java + + + + + org.apache.maven.plugins + maven-jar-plugin + + + true + + org.apache.tools.ant.launch.Launcher + + + + + + + + ../../../.. + META-INF + + LICENSE + NOTICE + + + + ../../../../src/main + + ../../../../src/testcases + ../../../../target/${project.artifactId}/classes + ../../../../target/${project.artifactId}/testcases + ../../../../target/${project.artifactId} + + diff --git a/.gradle-user/caches/modules-2/files-2.1/org.apache.ant/ant-parent/1.10.15/3080889f8568c2ff61ebdb3e5a40f7f75d11a4de/ant-parent-1.10.15.pom b/.gradle-user/caches/modules-2/files-2.1/org.apache.ant/ant-parent/1.10.15/3080889f8568c2ff61ebdb3e5a40f7f75d11a4de/ant-parent-1.10.15.pom new file mode 100644 index 0000000..4fb730b --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.apache.ant/ant-parent/1.10.15/3080889f8568c2ff61ebdb3e5a40f7f75d11a4de/ant-parent-1.10.15.pom @@ -0,0 +1,184 @@ + + + + + 4.0.0 + org.apache.ant + ant-parent + 1.10.15 + pom + master POM + + + The Apache Software License, Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + Apache Ant + https://ant.apache.org/ + 2000 + + The Apache Software Foundation + https://www.apache.org/ + + + + + dummy + Dummy to avoid accidental deploys + https://nowhere.net/ + + + + scm:git:https://gitbox.apache.org/repos/asf/ant.git + scm:git:https://gitbox.apache.org/repos/asf/ant.git + https://gitbox.apache.org/repos/asf/ant.git + + + jenkins + https://builds.apache.org/job/Ant-Build-from-POMs/ + + + + Ant Developers List + dev-subscribe@ant.apache.org + dev-unsubscribe@ant.apache.org + dev@ant.apache.org + https://mail-archives.apache.org/mod_mbox/ant-dev + + + Ant Users List + user-subscribe@ant.apache.org + user-unsubscribe@ant.apache.org + user@ant.apache.org + https://mail-archives.apache.org/mod_mbox/ant-user + + + + bugzilla + https://issues.apache.org/bugzilla/ + + + ant + ant-antlr + ant-apache-bcel + ant-apache-bsf + ant-apache-log4j + ant-apache-oro + ant-apache-regexp + ant-apache-resolver + ant-apache-xalan2 + ant-commons-logging + ant-commons-net + ant-imageio + ant-jai + ant-javamail + ant-jakartamail + ant-jdepend + ant-jmf + ant-jsch + ant-junit + ant-junit4 + ant-junitlauncher + ant-launcher + ant-netrexx + ant-swing + ant-testutil + ant-xz + + + + junit + junit + 4.13.2 + test + + + org.hamcrest + hamcrest-library + 1.3 + test + + + + ../../../src/main + ../../../src/testcases + ../../../target/classes + ../../../target/testcases + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-jar-plugin + 3.1.0 + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.1 + + + org.apache.maven.plugins + maven-surefire-report-plugin + 2.22.1 + + + org.apache.maven.plugins + maven-antrun-plugin + 1.8 + + + + + + UTF-8 + + + + javac-8 + + 1.8 + + + + com.sun + tools + 1.8.0 + system + ${java.home}/../lib/tools.jar + + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/org.apache.ant/ant/1.10.15/94e5ad677754ceae5ce3173e6f848dccc7283ccd/ant-1.10.15.pom b/.gradle-user/caches/modules-2/files-2.1/org.apache.ant/ant/1.10.15/94e5ad677754ceae5ce3173e6f848dccc7283ccd/ant-1.10.15.pom new file mode 100644 index 0000000..a33c149 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.apache.ant/ant/1.10.15/94e5ad677754ceae5ce3173e6f848dccc7283ccd/ant-1.10.15.pom @@ -0,0 +1,375 @@ + + + + + + org.apache.ant + ant-parent + ../pom.xml + 1.10.15 + + 4.0.0 + https://ant.apache.org/ + org.apache.ant + ant + 1.10.15 + Apache Ant Core + + org/apache/tools/ant/taskdefs/modules/ + + + + org.apache.ant + ant-launcher + 1.10.15 + compile + + + org.apache.ant + ant-antunit + 1.4.1 + test + + + org.apache.ant + ant + + + org.apache.ant + ant-launcher + + + + + xerces + xercesImpl + 2.12.2 + test + + + com.sun.mail + javax.mail + 1.6.2 + test + + + org.beanshell + bsh + 2.0b5 + test + + + + + ../../../../target/ant/.build.timestamp.properties + + + + maven-antrun-plugin + + + create-timestamp-file + generate-resources + + run + + + + + + + + + + + + create-antlib-test-jar + process-test-classes + + run + + + + + + + + + + + + + + + + + + + + + + + delete-timestamp-file + clean + + run + + + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + org/apache/tools/ant/filters/util/JavaClassHelper* + org/apache/tools/ant/launch/ + org/apache/tools/ant/listener/CommonsLoggingListener* + org/apache/tools/ant/listener/Log4jListener* + org/apache/tools/ant/taskdefs/email/*MimeMailer* + ${modules.exclude} + org/apache/tools/ant/taskdefs/optional/NetRexxC* + org/apache/tools/ant/taskdefs/optional/Xalan2TraceSupport* + org/apache/tools/ant/taskdefs/optional/image/ + org/apache/tools/ant/taskdefs/optional/jdepend/ + org/apache/tools/ant/taskdefs/optional/junit/ + org/apache/tools/ant/taskdefs/optional/junitlauncher/ + org/apache/tools/ant/taskdefs/optional/net/FTP* + org/apache/tools/ant/taskdefs/optional/net/RExec* + org/apache/tools/ant/taskdefs/optional/net/TelnetTask* + org/apache/tools/ant/taskdefs/optional/sound/ + org/apache/tools/ant/taskdefs/optional/splash/ + org/apache/tools/ant/taskdefs/optional/ssh/ + org/apache/tools/ant/taskdefs/optional/xz/ + org/apache/tools/ant/types/optional/image/ + org/apache/tools/ant/types/optional/imageio/ + org/apache/tools/ant/types/optional/xz/ + org/apache/tools/ant/types/resolver/ + org/apache/tools/ant/util/depend/bcel/ + org/apache/tools/ant/util/ScriptRunner.java + org/apache/tools/ant/util/optional/ScriptRunner.java + org/apache/tools/ant/util/regexp/JakartaOro* + org/apache/tools/ant/util/regexp/JakartaRegexp* + + + + org/apache/tools/ant/launch/ + + org/apache/tools/ant/listener/CommonsLoggingListener* + + org/apache/tools/ant/listener/Log4jListener* + + org/apache/tools/ant/taskdefs/AbstractCvs* + + org/apache/tools/ant/taskdefs/Javac* + + org/apache/tools/ant/taskdefs/StyleTest* + + org/apache/tools/ant/taskdefs/email/EmailTask* + + ${modules.exclude} + + org/apache/tools/ant/taskdefs/optional/ANTLR* + + org/apache/tools/ant/taskdefs/optional/Jspc* + org/apache/tools/ant/taskdefs/optional/Pvcs* + + org/apache/tools/ant/taskdefs/optional/TraXLiaison* + + org/apache/tools/ant/taskdefs/optional/XmlValidateCatalog* + + org/apache/tools/ant/taskdefs/optional/image/ + + org/apache/tools/ant/taskdefs/optional/jdepend/ + + org/apache/tools/ant/taskdefs/optional/junit/ + + org/apache/tools/ant/taskdefs/optional/junitlauncher/ + + org/apache/tools/ant/taskdefs/optional/net/FTP* + + org/apache/tools/ant/taskdefs/optional/splash/ + + org/apache/tools/ant/taskdefs/optional/ssh/ + + org/apache/tools/ant/types/Assertions* + + org/apache/tools/ant/types/optional/depend/ClassFileSet* + + org/apache/tools/ant/util/ClasspathUtils* + org/apache/tools/ant/util/LoaderUtils* + + org/apache/tools/ant/util/regexp/JakartaOro* + + org/apache/tools/ant/util/regexp/JakartaRegexp* + + org/apache/tools/ant/AntClassLoaderDelegation* + + org/apache/tools/ant/Include* + + org/example/junitlauncher/ + + org/apache/tools/ant/taskdefs/optional/script/graal/ + + org/apache/tools/ant/types/CommandlineJavaTest* + org/apache/tools/ant/types/selectors/ModifiedSelectorTest* + org/apache/tools/ant/taskdefs/AvailableTest* + + + + + org.apache.maven.plugins + maven-jar-plugin + + + true + + org.apache.tools.ant.Main + true + true + true + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + ../../../.. + ../../../.. + + + ant.home + ${env.ANT_HOME} + + + build.classes.value + ${project.basedir}/../../../../target/${project.artifactId}/classes + + + build.tests.value + ${project.basedir}/../../../../target/${project.artifactId}/testcases + + + offline + true + + + ant.test.basedir.ignore + true + + + + + + org.apache.maven.plugins + maven-surefire-report-plugin + + + + + ../../../.. + META-INF + + LICENSE + NOTICE + + + + ../../../../src/main + true + + org/apache/tools/ant/listener/defaults.properties + org/apache/tools/ant/taskdefs/defaults.properties + org/apache/tools/ant/types/defaults.properties + org/apache/tools/ant/antlib.xml + org/apache/tools/ant/types/conditions/antlib.xml + org/apache/tools/ant/defaultManifest.mf + org/apache/tools/ant/version.txt + + + + ../../../../src/resources + true + + **/antlib.xml + **/javadoc-frame-injections-fix.txt + + + + ../../../../manual + false + + images/ant_logo_large.gif + + + + + + ../../../../src/etc/testcases + true + + + ../../../../src/main + true + + **/*.java + + + + ../../../../src/main + ../../../../src/tests/junit + ../../../../src/etc + + ../../../../target/${project.artifactId}/classes + ../../../../target/${project.artifactId}/testcases + ../../../../target/${project.artifactId} + + + + java9+ + + [9,) + + + not/here + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/org.apache.ant/ant/1.10.15/da854f5503ee061a5a3b2cfcbe98ee27aa4a5ef9/ant-1.10.15.jar b/.gradle-user/caches/modules-2/files-2.1/org.apache.ant/ant/1.10.15/da854f5503ee061a5a3b2cfcbe98ee27aa4a5ef9/ant-1.10.15.jar new file mode 100644 index 0000000..e06c352 Binary files /dev/null and b/.gradle-user/caches/modules-2/files-2.1/org.apache.ant/ant/1.10.15/da854f5503ee061a5a3b2cfcbe98ee27aa4a5ef9/ant-1.10.15.jar differ diff --git a/.gradle-user/caches/modules-2/files-2.1/org.apache.commons/commons-parent/74/704abf062c1f6e03f8bcf6929b4777b9af5048a5/commons-parent-74.pom b/.gradle-user/caches/modules-2/files-2.1/org.apache.commons/commons-parent/74/704abf062c1f6e03f8bcf6929b4777b9af5048a5/commons-parent-74.pom new file mode 100644 index 0000000..a8e6117 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.apache.commons/commons-parent/74/704abf062c1f6e03f8bcf6929b4777b9af5048a5/commons-parent-74.pom @@ -0,0 +1,1908 @@ + + + + 4.0.0 + + org.apache + apache + 33 + + org.apache.commons + commons-parent + 74 + pom + Apache Commons Parent + The Apache Commons Parent POM provides common settings for all Apache Commons components. + + 2006 + https://commons.apache.org/proper/commons-parent/ + + + + + + 3.6.3 + + 8 + + + 2024-08-24T17:39:39Z + 74 + 75 + RC1 + COMMONSSITE + + + 73 + true + + + + + + 1.3 + 1.3 + + + 8 + + + false + + + + + + 3.2.1 + + + 1.24 + + 1.0 + 3.7.1 + 3.6.0 + 1.14.0 + 2.12.1 + 3.5.0 + + 9.3 + 2.7 + 3.13.0 + 2.8.1 + 0.7.4 + 3.4.0 + 5.1.9 + 0.8.12 + 0.23.0 + 3.4.2 + 3.8.0 + 3.5.0 + 3.24.0 + 7.4.0 + + 3.6.2 + 0.16.1 + 1.8.2 + 1.1 + 3.2.0 + 1.2.2.Final + true + + 6.4.1 + 5.11.0 + 1.37 + + + 3.12.1 + 4.8.6.2 + 4.8.6 + 3.4.0 + 3.4.0 + 3.5.3 + + + ${project.artifactId}-${commons.release.version} + + -bin + ${project.artifactId}-${commons.release.2.version} + + -bin + ${project.artifactId}-${commons.release.3.version} + + -bin + + -bin + + + false + 1.00 + 1.00 + 1.00 + 1.00 + 1.00 + 1.00 + + + parent + + + ${project.artifactId} + + + org.apache.commons.${commons.packageId} + + + org.apache.commons.${commons.packageId} + org.apache.commons.*;version=${project.version};-noimport:=true + * + + + true + + + ${project.build.directory}/osgi/MANIFEST.MF + + + scp + + + iso-8859-1 + + ${commons.encoding} + + ${commons.encoding} + + ${commons.encoding} + + + + https://docs.oracle.com/en/java/javase/21/docs/api/ + + https://docs.oracle.com/javaee/5/api/ + https://docs.oracle.com/javaee/6/api/ + https://docs.oracle.com/javaee/7/api/ + https://jakarta.ee/specifications/platform/8/apidocs/ + https://jakarta.ee/specifications/platform/9/apidocs/ + https://jakarta.ee/specifications/platform/9.1/apidocs/ + https://jakarta.ee/specifications/platform/10/apidocs/ + + ${commons.javadoc.javaee6.link} + + + info + + + false + + + false + + 100 + + false + + + ${user.home}/commons-sites + + ${commons.componentid} + + https://svn.apache.org/repos/infra/websites/production/commons/content/proper/commons-${commons.componentid} + ${commons.site.cache}/${commons.site.path} + commons.site + + + true + false + false + + + scm:svn:https://dist.apache.org/repos/dist/dev/commons/${commons.componentid} + + src/conf + + https://analysis.apache.org/ + + + . + RELEASE-NOTES.txt + + + + + + + + + Commons User List + user-subscribe@commons.apache.org + user-unsubscribe@commons.apache.org + user@commons.apache.org + https://mail-archives.apache.org/mod_mbox/commons-user/ + + https://www.mail-archive.com/user@commons.apache.org/ + + + + Commons Dev List + dev-subscribe@commons.apache.org + dev-unsubscribe@commons.apache.org + dev@commons.apache.org + https://mail-archives.apache.org/mod_mbox/commons-dev/ + + https://www.mail-archive.com/dev@commons.apache.org/ + + + + Commons Issues List + issues-subscribe@commons.apache.org + issues-unsubscribe@commons.apache.org + https://mail-archives.apache.org/mod_mbox/commons-issues/ + + https://www.mail-archive.com/issues@commons.apache.org/ + + + + Commons Commits List + commits-subscribe@commons.apache.org + commits-unsubscribe@commons.apache.org + https://mail-archives.apache.org/mod_mbox/commons-commits/ + + https://www.mail-archive.com/commits@commons.apache.org/ + + + + Apache Announce List + announce-subscribe@apache.org + announce-unsubscribe@apache.org + https://mail-archives.apache.org/mod_mbox/www-announce/ + + https://www.mail-archive.com/announce@apache.org/ + + + + + + + scm:git:http://gitbox.apache.org/repos/asf/commons-parent.git + scm:git:https://gitbox.apache.org/repos/asf/commons-parent.git + https://gitbox.apache.org/repos/asf?p=commons-parent.git + + + + jira + https://issues.apache.org/jira/browse/COMMONSSITE + + + + GitHub + https://github.com/apache/commons-parent/actions + + + + + + org.junit + junit-bom + ${commons.junit.version} + pom + import + + + + + + + clean apache-rat:check verify site + + + + src/main/resources + + + + ${basedir} + META-INF + + NOTICE.txt + LICENSE.txt + NOTICE + LICENSE + + + + + + + + src/test/resources + + + + ${basedir} + META-INF + + NOTICE.txt + LICENSE.txt + NOTICE + LICENSE + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${commons.compiler.version} + + ${maven.compiler.source} + ${maven.compiler.target} + ${commons.encoding} + + ${commons.compiler.fork} + + ${commons.compiler.compilerVersion} + ${commons.compiler.javac} + + + + org.apache.maven.plugins + maven-assembly-plugin + ${commons.assembly-plugin.version} + + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${commons.javadoc.version} + + + true + ${maven.compiler.source} + ${commons.compiler.javadoc} + ${commons.encoding} + ${commons.docEncoding} + + true + true + + ${commons.javadoc.java.link} + ${commons.javadoc.javaee.link} + + ${commons.javadoc.options} + + + true + true + + + + + + + org.apache.maven.plugins + maven-remote-resources-plugin + + + true + + + + + org.apache.maven.plugins + maven-site-plugin + ${commons.site-plugin.version} + + + true + + + + + org.apache.maven.wagon + wagon-ssh + ${commons.wagon-ssh.version} + + + + + attach-descriptor + + attach-descriptor + + + + + + org.apache.maven.plugins + maven-surefire-plugin + ${commons.surefire.version} + + + org.apache.maven.plugins + maven-failsafe-plugin + ${commons.failsafe.version} + + + + com.github.siom79.japicmp + japicmp-maven-plugin + ${commons.japicmp.version} + + + + ${project.groupId} + ${project.artifactId} + ${commons.bc.version} + jar + + + + + ${project.build.directory}/${project.artifactId}-${project.version}.jar + + + + true + ${commons.japicmp.breakBuildOnBinaryIncompatibleModifications} + ${commons.japicmp.breakBuildOnSourceIncompatibleModifications} + + true + true + true + ${commons.japicmp.ignoreMissingClasses} + + + METHOD_NEW_DEFAULT + true + true + PATCH + + + + METHOD_ADDED_TO_INTERFACE + false + false + PATCH + + + + + + + org.apache.commons + commons-build-plugin + ${commons.build-plugin.version} + + ${commons.release.name} + + + + org.apache.commons + commons-release-plugin + ${commons.release-plugin.version} + + + org.apache.felix + maven-bundle-plugin + ${commons.felix.version} + true + + + + biz.aQute.bnd + biz.aQute.bndlib + ${commons.biz.aQute.bndlib.version} + + + + + org.apache.rat + apache-rat-plugin + ${commons.rat.version} + + + org.apache.maven.plugins + maven-artifact-plugin + 3.5.1 + + + org.codehaus.mojo + build-helper-maven-plugin + ${commons.build-helper.version} + + + org.codehaus.mojo + buildnumber-maven-plugin + ${commons.buildnumber-plugin.version} + + + org.codehaus.mojo + versions-maven-plugin + + 2.17.1 + + + org.jacoco + jacoco-maven-plugin + ${commons.jacoco.version} + + + + prepare-agent + process-test-classes + + prepare-agent + + + + report + site + + report + + + + check + + check + + + + + BUNDLE + + + CLASS + COVEREDRATIO + ${commons.jacoco.classRatio} + + + INSTRUCTION + COVEREDRATIO + ${commons.jacoco.instructionRatio} + + + METHOD + COVEREDRATIO + ${commons.jacoco.methodRatio} + + + BRANCH + COVEREDRATIO + ${commons.jacoco.branchRatio} + + + LINE + COVEREDRATIO + ${commons.jacoco.lineRatio} + + + COMPLEXITY + COVEREDRATIO + ${commons.jacoco.complexityRatio} + + + + + ${commons.jacoco.haltOnFailure} + + + + + + org.apache.maven.plugins + maven-project-info-reports-plugin + ${commons.project-info.version} + + + + org.apache.bcel + bcel + 6.10.0 + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + ${commons.checkstyle-plugin.version} + + + com.puppycrawl.tools + checkstyle + ${commons.checkstyle.version} + + + + + com.github.spotbugs + spotbugs-maven-plugin + ${commons.spotbugs.plugin.version} + + + com.github.spotbugs + spotbugs + ${commons.spotbugs.impl.version} + + + + + org.apache.maven.plugins + maven-pmd-plugin + ${commons.pmd.version} + + + net.sourceforge.pmd + pmd-core + ${commons.pmd-impl.version} + + + net.sourceforge.pmd + pmd-java + ${commons.pmd-impl.version} + + + net.sourceforge.pmd + pmd-javascript + ${commons.pmd-impl.version} + + + net.sourceforge.pmd + pmd-jsp + ${commons.pmd-impl.version} + + + + + org.cyclonedx + cyclonedx-maven-plugin + ${commons.cyclonedx.version} + + + build-sbom-cyclonedx + package + + makeAggregateBom + + + + + ${project.artifactId}-${project.version}-bom + + + + org.spdx + spdx-maven-plugin + ${commons.spdx.version} + + + build-sbom-spdx + package + + createSPDX + + + + + + org.codehaus.mojo + javancss-maven-plugin + 2.1 + + + + + + + **/*.java + + + + + org.codehaus.mojo + exec-maven-plugin + 3.4.1 + + + org.codehaus.mojo + taglist-maven-plugin + 3.1.0 + + + + + + + maven-assembly-plugin + + + src/assembly/src.xml + + gnu + + + + + org.apache.maven.plugins + maven-antrun-plugin + + + javadoc.resources + generate-sources + + run + + + + + + + + + + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + org.apache.maven.plugins + maven-jar-plugin + ${commons.jar-plugin.version} + + + + test-jar + + + + true + + + + + + ${commons.manifestfile} + + ${project.name} + ${project.version} + ${project.organization.name} + ${project.name} + ${project.version} + ${project.organization.name} + org.apache + ${maven.compiler.source} + ${maven.compiler.target} + + + + + + maven-source-plugin + + + + true + true + + + + + + create-source-jar + + jar-no-fork + test-jar-no-fork + + + + + + org.apache.maven.plugins + maven-surefire-plugin + ${commons.surefire.version} + + + ${commons.surefire.java} + + + + + org.apache.commons + commons-build-plugin + + + org.apache.felix + maven-bundle-plugin + + + + true + + ${commons.osgi.excludeDependencies} + ${project.build.directory}/osgi + + + <_nouses>true + + <_removeheaders>JAVA_1_3_HOME,JAVA_1_4_HOME,JAVA_1_5_HOME,JAVA_1_6_HOME,JAVA_1_7_HOME,JAVA_1_8_HOME,JAVA_1_9_HOME + ${commons.osgi.symbolicName} + ${commons.osgi.export} + ${commons.osgi.private} + ${commons.osgi.import} + ${commons.osgi.dynamicImport} + ${project.url} + + + + + bundle-manifest + process-classes + + manifest + + + + + + + org.apache.rat + apache-rat-plugin + + + + + site-content/** + .checkstyle + .fbprefs + .pmd + .asf.yaml + .gitattributes + src/site/resources/download_*.cgi + src/site/resources/profile.* + profile.* + + maven-eclipse.xml + .externalToolBuilders/** + + .vscode/** + + + + + rat-check + validate + + check + + + + + + org.apache.maven.plugins + maven-artifact-plugin + + + check-buildplan + validate + + check-buildplan + + + + + + org.apache.maven.plugins + maven-scm-publish-plugin + + ${project.reporting.outputDirectory} + scm:svn:${commons.scmPubUrl} + ${commons.scmPubCheckoutDirectory} + ${commons.scmPubServer} + true + + + + scm-publish + site-deploy + + publish-scm + + + + + + org.codehaus.mojo + versions-maven-plugin + + + org.cyclonedx + cyclonedx-maven-plugin + + + org.spdx + spdx-maven-plugin + + + + + + + + + + org.apache.maven.plugins + maven-changes-plugin + ${commons.changes.version} + + ${basedir}/src/changes/changes.xml + Fix Version,Key,Component,Summary,Type,Resolution,Status + + Fix Version DESC,Type,Key DESC + Fixed + Resolved,Closed + + Bug,New Feature,Task,Improvement,Wish,Test + + true + ${commons.changes.onlyCurrentVersion} + ${commons.changes.maxEntries} + ${commons.changes.runOnlyAtExecutionRoot} + + + + + changes-report + jira-report + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${commons.javadoc.version} + + + + default + + javadoc + + + + + + org.apache.maven.plugins + maven-jxr-plugin + ${commons.jxr.version} + + + org.apache.maven.plugins + maven-project-info-reports-plugin + ${commons.project-info.version} + + + + + index + summary + modules + + team + scm + issue-management + mailing-lists + dependency-info + dependency-management + dependencies + dependency-convergence + ci-management + + + distribution-management + + + + + + org.apache.maven.plugins + maven-site-plugin + ${commons.site-plugin.version} + + + + navigation.xml,changes.xml + + + + + org.apache.maven.plugins + maven-surefire-report-plugin + ${commons.surefire-report.version} + + ${commons.surefire-report.aggregate} + + + + + org.apache.rat + apache-rat-plugin + ${commons.rat.version} + + + + + site-content/** + .checkstyle + .fbprefs + .pmd + .asf.yaml + .gitattributes + src/site/resources/download_*.cgi + src/site/resources/profile.* + profile.* + + maven-eclipse.xml + .externalToolBuilders/** + + .vscode/** + + + + + + + + + + + module-name + + + profile.module-name + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + ${commons.module.name} + + + + + + + + + + + parse-target-version + + + + user.home + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + parse-version + + + parse-version + + + javaTarget + ${maven.compiler.target} + + + + + + + + + + + + animal-sniffer + + + (,9) + + + src/site/resources/profile.noanimal + + + + + + java${javaTarget.majorVersion}${javaTarget.minorVersion} + + + + + + + + org.codehaus.mojo + animal-sniffer-maven-plugin + ${commons.animal-sniffer.version} + + + checkAPIcompatibility + + + + check + + + + + + org.codehaus.mojo.signature + ${animal-sniffer.signature} + ${commons.animal-sniffer.signature.version} + + + + + + + + + + jacoco + + + + src/site/resources/profile.jacoco + + + + + + org.jacoco + jacoco-maven-plugin + ${commons.jacoco.version} + + + + + + + org.jacoco + jacoco-maven-plugin + ${commons.jacoco.version} + + + + + report + + + + + + + + + + cobertura + + + src/site/resources/profile.cobertura + + + + + + org.codehaus.mojo + cobertura-maven-plugin + ${commons.cobertura.version} + + + + + + + japicmp + + [1.8,) + + src/site/resources/profile.japicmp + + + + + + com.github.siom79.japicmp + japicmp-maven-plugin + + + verify + + cmp + + + + + + + + + + com.github.siom79.japicmp + japicmp-maven-plugin + ${commons.japicmp.version} + + + true + ${commons.japicmp.breakBuildOnBinaryIncompatibleModifications} + ${commons.japicmp.breakBuildOnSourceIncompatibleModifications} + + true + true + true + ${commons.japicmp.ignoreMissingClasses} + + + METHOD_NEW_DEFAULT + true + true + PATCH + + + + + + + + + + + + release + + + + maven-install-plugin + + + maven-release-plugin + + + -Prelease + + + + maven-javadoc-plugin + + + create-javadoc-jar + + javadoc + jar + + package + + + + ${maven.compiler.source} + ${commons.compiler.javadoc} + + + + maven-assembly-plugin + ${commons.assembly-plugin.version} + true + + + + single + + + verify + + + + + + maven-gpg-plugin + + + sign-artifacts + verify + + sign + + + + + + org.apache.commons + commons-release-plugin + + + clean-staging + clean + + clean-staging + + + + detatch-distributions + verify + + detach-distributions + + + + stage-distributions + deploy + + stage-distributions + + + + + + + + + + + apache-release + + + + maven-release-plugin + + apache-release + + + + org.apache.maven.plugins + maven-source-plugin + + + attach-test-sources + + test-jar + + + + + + maven-install-plugin + + + org.apache.maven.plugins + maven-jar-plugin + + + + test-jar + + + + + + + + + + + java-1.8 + + true + 1.8 + ${JAVA_1_8_HOME}/bin/javac + ${JAVA_1_8_HOME}/bin/javadoc + ${JAVA_1_8_HOME}/bin/java + + + + + + java-1.11 + + true + 1.11 + ${JAVA_1_11_HOME}/bin/javac + ${JAVA_1_11_HOME}/bin/javadoc + ${JAVA_1_11_HOME}/bin/java + + + + + + + + test-deploy + + id::default::file:target/deploy + true + + + + + + release-notes + + + + org.apache.maven.plugins + maven-changes-plugin + ${commons.changes.version} + + + src/changes + true + ${changes.announcementDirectory} + ${changes.announcementFile} + + ${commons.release.version} + + + + + create-release-notes + generate-resources + + announcement-generate + + + + + + + + + + + svn-buildnumber + + + !buildNumber.skip + !true + + + + + + org.codehaus.mojo + buildnumber-maven-plugin + + + generate-resources + + create + + + + + + true + + ?????? + false + false + + + + + + + + jdk7-plugin-fix-version + + [1.7,1.8) + + + 3.5.1 + 1.17 + 3.5.0 + + + + + jdk8-plugin-fix-version + + [1.8,1.9) + + + 0.6.3 + + + + + + site-basic + + true + true + true + true + true + true + true + true + + + + + java-9-up + + [9,) + + + 9 + true + + ${commons.compiler.release} + + + + + org.moditect + moditect-maven-plugin + ${commons.moditect-maven-plugin.version} + + + add-module-infos + package + + add-module-info + + + ${moditect.java.version} + + --multi-release=${moditect.java.version} + + ${project.build.directory} + true + false + + + ${commons.module.name} + ${commons.moditect-maven-plugin.addServiceUses} + + + + + + + + + + + + java-11-up + + [11,) + + + 10.17.0 + + + + + java-17-up + + [17,) + + + + + + + + benchmark + + true + org.apache + + + + + org.codehaus.mojo + exec-maven-plugin + 3.4.1 + + + benchmark + test + + exec + + + test + java + + -classpath + + org.openjdk.jmh.Main + -rf + json + -rff + target/jmh-result.${benchmark}.json + ${benchmark} + + + + + + + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/org.apache.groovy/groovy-bom/4.0.22/99061b86fb8b0c72c40a2999a3553927bc9095de/groovy-bom-4.0.22.module b/.gradle-user/caches/modules-2/files-2.1/org.apache.groovy/groovy-bom/4.0.22/99061b86fb8b0c72c40a2999a3553927bc9095de/groovy-bom-4.0.22.module new file mode 100644 index 0000000..9e3fdec --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.apache.groovy/groovy-bom/4.0.22/99061b86fb8b0c72c40a2999a3553927bc9095de/groovy-bom-4.0.22.module @@ -0,0 +1,456 @@ +{ + "formatVersion": "1.1", + "component": { + "group": "org.apache.groovy", + "module": "groovy-bom", + "version": "4.0.22", + "attributes": { + "org.gradle.status": "release" + } + }, + "createdBy": { + "gradle": { + "version": "8.8" + } + }, + "variants": [ + { + "name": "apiElements", + "attributes": { + "org.gradle.category": "platform", + "org.gradle.usage": "java-api" + }, + "dependencyConstraints": [ + { + "group": "org.apache.groovy", + "module": "groovy", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-ant", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-astbuilder", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-cli-commons", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-cli-picocli", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-console", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-contracts", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-datetime", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-dateutil", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-docgenerator", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-ginq", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-groovydoc", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-groovysh", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-jmx", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-json", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-jsr223", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-macro", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-macro-library", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-nio", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-servlet", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-sql", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-swing", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-templates", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-test", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-test-junit5", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-testng", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-toml", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-typecheckers", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-xml", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-yaml", + "version": { + "requires": "4.0.22" + } + } + ] + }, + { + "name": "runtimeElements", + "attributes": { + "org.gradle.category": "platform", + "org.gradle.usage": "java-runtime" + }, + "dependencyConstraints": [ + { + "group": "org.apache.groovy", + "module": "groovy", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-ant", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-astbuilder", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-cli-commons", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-cli-picocli", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-console", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-contracts", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-datetime", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-dateutil", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-docgenerator", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-ginq", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-groovydoc", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-groovysh", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-jmx", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-json", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-jsr223", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-macro", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-macro-library", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-nio", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-servlet", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-sql", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-swing", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-templates", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-test", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-test-junit5", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-testng", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-toml", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-typecheckers", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-xml", + "version": { + "requires": "4.0.22" + } + }, + { + "group": "org.apache.groovy", + "module": "groovy-yaml", + "version": { + "requires": "4.0.22" + } + } + ] + } + ] +} diff --git a/.gradle-user/caches/modules-2/files-2.1/org.apache.groovy/groovy-bom/4.0.22/f5595adfc27fdcd4865ce6e3cb5c1f93bf50afda/groovy-bom-4.0.22.pom b/.gradle-user/caches/modules-2/files-2.1/org.apache.groovy/groovy-bom/4.0.22/f5595adfc27fdcd4865ce6e3cb5c1f93bf50afda/groovy-bom-4.0.22.pom new file mode 100644 index 0000000..b8797ee --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.apache.groovy/groovy-bom/4.0.22/f5595adfc27fdcd4865ce6e3cb5c1f93bf50afda/groovy-bom-4.0.22.pom @@ -0,0 +1,996 @@ + + + + + + + + 4.0.0 + org.apache.groovy + groovy-bom + 4.0.22 + pom + Apache Groovy + Groovy: A powerful multi-faceted language for the JVM + https://groovy-lang.org + 2003 + + Apache Software Foundation + https://apache.org + + + + The Apache Software License, Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + glaforge + Guillaume Laforge + Google + + Developer + + + + bob + bob mcwhirter + bob@werken.com + The Werken Company + + Founder + + + + jstrachan + James Strachan + james@coredevelopers.com + Core Developers Network + + Founder + + + + joe + Joe Walnes + ThoughtWorks + + Developer Emeritus + + + + skizz + Chris Stevenson + ThoughtWorks + + Developer Emeritus + + + + jamiemc + Jamie McCrindle + Three + + Developer Emeritus + + + + mattf + Matt Foemmel + ThoughtWorks + + Developer Emeritus + + + + alextkachman + Alex Tkachman + + Developer Emeritus + + + + roshandawrani + Roshan Dawrani + + Developer Emeritus + + + + spullara + Sam Pullara + sam@sampullara.com + + Developer Emeritus + + + + kasper + Kasper Nielsen + + Developer Emeritus + + + + travis + Travis Kay + + Developer Emeritus + + + + zohar + Zohar Melamed + + Developer Emeritus + + + + jwilson + John Wilson + tug@wilson.co.uk + The Wilson Partnership + + Developer Emeritus + + + + cpoirier + Chris Poirier + cpoirier@dreaming.org + + Developer Emeritus + + + + ckl + Christiaan ten Klooster + ckl@dacelo.nl + Dacelo WebDevelopment + + Developer Emeritus + + + + goetze + Steve Goetze + goetze@dovetail.com + Dovetailed Technologies, LLC + + Developer Emeritus + + + + bran + Bing Ran + b55r@sina.com + Leadingcare + + Developer Emeritus + + + + jez + Jeremy Rayner + jeremy.rayner@gmail.com + javanicus + + Developer Emeritus + + + + jstump + John Stump + johnstump2@yahoo.com + + Developer Emeritus + + + + blackdrag + Jochen Theodorou + blackdrag@gmx.org + + Developer + + + + russel + Russel Winder + russel@winder.org.uk + Concertant LLP & It'z Interactive Ltd + + Developer + Founder of Gant + + + + phk + Pilho Kim + phkim@cluecom.co.kr + + Developer Emeritus + + + + cstein + Christian Stein + sormuras@gmx.de + CTSR.de + + Developer Emeritus + + + + mittie + Dierk Koenig + Karakun AG + + Developer + + + + paulk + Paul King + paulk@asert.com.au + OCI, Australia + + Project Manager + Developer + + + + galleon + Guillaume Alleon + guillaume.alleon@gmail.com + + Developer Emeritus + + + + user57 + Jason Dillon + jason@planet57.com + + Developer Emeritus + + + + shemnon + Danno Ferrin + + Developer Emeritus + + + + jwill + James Williams + + Developer Emeritus + + + + timyates + Tim Yates + + Developer + + + + aalmiray + Andres Almiray + aalmiray@users.sourceforge.net + + Developer + + + + mguillem + Marc Guillemot + mguillemot@yahoo.fr + + Developer Emeritus + + + + jimwhite + Jim White + jim@pagesmiths.com + IFCX.org + + Developer + + + + pniederw + Peter Niederwieser + pniederw@gmail.com + + Developer Emeritus + + + + andresteingress + Andre Steingress + + Developer + + + + hamletdrc + Hamlet D'Arcy + hamletdrc@gmail.com + + Developer Emeritus + + + + melix + Cedric Champeau + cedric.champeau@gmail.com + + Developer + + + + pascalschumacher + Pascal Schumacher + + Developer + + + + sunlan + Daniel Sun + + Developer + + + + rpopma + Remko Popma + + Developer + + + + grocher + Graeme Rocher + + Developer + + + + emilles + Eric Milles + Thomson Reuters + + Developer + + + + + + Joern Eyrich + + + Robert Kuzelj + + + Rod Cope + + + Yuri Schimke + + + James Birchfield + + + Robert Fuller + + + Sergey Udovenko + + + Hallvard Traetteberg + + + Peter Reilly + + + Brian McCallister + + + Richard Monson-Haefel + + + Brian Larson + + + Artur Biesiadowski + abies@pg.gda.pl + + + Ivan Z. Ganza + + + Larry Jacobson + + + Jake Gage + + + Arjun Nayyar + + + Masato Nagai + + + Mark Chu-Carroll + + + Mark Turansky + + + Jean-Louis Berliet + + + Graham Miller + + + Marc Palmer + + + Tugdual Grall + + + Edwin Tellman + + + Evan "Hippy" Slatis + + + Mike Dillon + + + Bernhard Huber + + + Yasuharu Nakano + + + Marc DeXeT + + + Dejan Bosanac + dejan@nighttale.net + + + Denver Dino + + + Ted Naleid + + + Ted Leung + + + Merrick Schincariol + + + Chanwit Kaewkasi + + + Stefan Matthias Aust + + + Andy Dwelly + + + Philip Milne + + + Tiago Fernandez + + + Steve Button + + + Joachim Baumann + + + Jochen Eddel+ + + + Ilinca V. Hallberg + + + Björn Westlin + + + Andrew Glover + + + Brad Long + + + John Bito + + + Jim Jagielski + + + Rodolfo Velasco + + + John Hurst + + + Merlyn Albery-Speyer + + + jeremi Joslin + + + UEHARA Junji + + + NAKANO Yasuharu + + + Dinko Srkoc + + + Raffaele Cigni + + + Alberto Vilches Raton + + + Paulo Poiati + + + Alexander Klein + + + Adam Murdoch + + + David Durham + + + Daniel Henrique Alves Lima + + + John Wagenleitner + + + Colin Harrington + + + Brian Alexander + + + Jan Weitz + + + Chris K Wensel + + + David Sutherland + + + Mattias Reichel + + + David Lee + + + Sergei Egorov + + + Hein Meling + + + Michael Baehr + + + Craig Andrews + + + Peter Ledbrook + + + Scott Stirling + + + Thibault Kruse + + + Tim Tiemens + + + Mike Spille + + + Nikolay Chugunov + + + Francesco Durbin + + + Paolo Di Tommaso + + + Rene Scheibe + + + Matias Bjarland + + + Tomasz Bujok + + + Richard Hightower + + + Andrey Bloschetsov + + + Yu Kobayashi + + + Nick Grealy + + + Vaclav Pech + + + Chuck Tassoni + + + Steven Devijver + + + Ben Manes + + + Troy Heninger + + + Andrew Eisenberg + + + Eric Milles + + + Kohsuke Kawaguchi + + + Scott Vlaminck + + + Hjalmar Ekengren + + + Rafael Luque + + + Joachim Heldmann + + + dgouyette + + + Marcin Grzejszczak + + + Pap Lőrinc + + + Guillaume Balaine + + + Santhosh Kumar T + + + Alan Green + + + Marty Saxton + + + Marcel Overdijk + + + Jonathan Carlson + + + Thomas Heller + + + John Stump + + + Ivan Ganza + + + Alex Popescu + + + Martin Kempf + + + Martin Ghados + + + Martin Stockhammer + + + Martin C. Martin + + + Alexey Verkhovsky + + + Alberto Mijares + + + Matthias Cullmann + + + Tomek Bujok + + + Stephane Landelle + + + Stephane Maldini + + + Mark Volkmann + + + Andrew Taylor + + + Vladimir Vivien + + + Vladimir Orany + + + Joe Wolf + + + Kent Inge Fagerland Simonsen + + + Tom Nichols + + + Ingo Hoffmann + + + Sergii Bondarenko + + + mgroovy + + + Dominik Przybysz + + + Jason Thomas + + + Trygve Amundsens + + + Morgan Hankins + + + Shruti Gupta + + + Ben Yu + + + Dejan Bosanac + + + Lidia Donajczyk-Lipinska + + + Peter Gromov + + + Johannes Link + + + Chris Reeves + + + Sean Timm + + + Dmitry Vyazelenko + + + + + Groovy Developer List + https://mail-archives.apache.org/mod_mbox/groovy-dev/ + + + Groovy User List + https://mail-archives.apache.org/mod_mbox/groovy-users/ + + + + scm:git:https://github.com/apache/groovy.git + scm:git:https://github.com/apache/groovy.git + https://github.com/apache/groovy.git + + + jira + https://issues.apache.org/jira/browse/GROOVY + + + + + org.apache.groovy + groovy + 4.0.22 + + + org.apache.groovy + groovy-ant + 4.0.22 + + + org.apache.groovy + groovy-astbuilder + 4.0.22 + + + org.apache.groovy + groovy-cli-commons + 4.0.22 + + + org.apache.groovy + groovy-cli-picocli + 4.0.22 + + + org.apache.groovy + groovy-console + 4.0.22 + + + org.apache.groovy + groovy-contracts + 4.0.22 + + + org.apache.groovy + groovy-datetime + 4.0.22 + + + org.apache.groovy + groovy-dateutil + 4.0.22 + + + org.apache.groovy + groovy-docgenerator + 4.0.22 + + + org.apache.groovy + groovy-ginq + 4.0.22 + + + org.apache.groovy + groovy-groovydoc + 4.0.22 + + + org.apache.groovy + groovy-groovysh + 4.0.22 + + + org.apache.groovy + groovy-jmx + 4.0.22 + + + org.apache.groovy + groovy-json + 4.0.22 + + + org.apache.groovy + groovy-jsr223 + 4.0.22 + + + org.apache.groovy + groovy-macro + 4.0.22 + + + org.apache.groovy + groovy-macro-library + 4.0.22 + + + org.apache.groovy + groovy-nio + 4.0.22 + + + org.apache.groovy + groovy-servlet + 4.0.22 + + + org.apache.groovy + groovy-sql + 4.0.22 + + + org.apache.groovy + groovy-swing + 4.0.22 + + + org.apache.groovy + groovy-templates + 4.0.22 + + + org.apache.groovy + groovy-test + 4.0.22 + + + org.apache.groovy + groovy-test-junit5 + 4.0.22 + + + org.apache.groovy + groovy-testng + 4.0.22 + + + org.apache.groovy + groovy-toml + 4.0.22 + + + org.apache.groovy + groovy-typecheckers + 4.0.22 + + + org.apache.groovy + groovy-xml + 4.0.22 + + + org.apache.groovy + groovy-yaml + 4.0.22 + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/org.apache.logging.log4j/log4j-api/2.24.1/7ebeb12c20606373005af4232cd0ecca72613dda/log4j-api-2.24.1.jar b/.gradle-user/caches/modules-2/files-2.1/org.apache.logging.log4j/log4j-api/2.24.1/7ebeb12c20606373005af4232cd0ecca72613dda/log4j-api-2.24.1.jar new file mode 100644 index 0000000..f9d5b43 Binary files /dev/null and b/.gradle-user/caches/modules-2/files-2.1/org.apache.logging.log4j/log4j-api/2.24.1/7ebeb12c20606373005af4232cd0ecca72613dda/log4j-api-2.24.1.jar differ diff --git a/.gradle-user/caches/modules-2/files-2.1/org.apache.logging.log4j/log4j-api/2.24.1/81b344b375a9580f65efb5a12333794d7d94bbe/log4j-api-2.24.1.pom b/.gradle-user/caches/modules-2/files-2.1/org.apache.logging.log4j/log4j-api/2.24.1/81b344b375a9580f65efb5a12333794d7d94bbe/log4j-api-2.24.1.pom new file mode 100644 index 0000000..98312de --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.apache.logging.log4j/log4j-api/2.24.1/81b344b375a9580f65efb5a12333794d7d94bbe/log4j-api-2.24.1.pom @@ -0,0 +1,116 @@ + + + + 4.0.0 + + org.apache.logging.log4j + log4j + 2.24.1 + ../log4j-parent + + log4j-api + 2.24.1 + Apache Log4j API + The logging API of the Log4j project. + Library and application code can log through this API. + It contains a simple built-in implementation (`SimpleLogger`) for trivial use cases. + Production applications are recommended to use Log4j API in combination with a fully-fledged implementation, such as Log4j Core. + + + Apache-2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + true + java.sql;static=true, + + java.management;static=true, + + org.jspecify;transitive=false + !sun.reflect, + + org.jspecify.*;resolution:=optional + false + org.apache.logging.log4j + + + + org.jspecify + jspecify + provided + + + org.osgi + org.osgi.core + provided + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + add-source + generate-sources + + add-source + + + + ${project.build.directory}/log4j-api-java9 + + + + + + + maven-dependency-plugin + + + unpack-classes + prepare-package + + unpack + + + + + org.apache.logging.log4j + log4j-api-java9 + ${project.version} + zip + false + + + **/*.class + **/*.java + ${project.build.directory} + false + true + + + + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/org.apache.logging.log4j/log4j-bom/2.24.1/c97ce07244367473d5337c9fe64fca0dd5b83914/log4j-bom-2.24.1.pom b/.gradle-user/caches/modules-2/files-2.1/org.apache.logging.log4j/log4j-bom/2.24.1/c97ce07244367473d5337c9fe64fca0dd5b83914/log4j-bom-2.24.1.pom new file mode 100644 index 0000000..63f584a --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.apache.logging.log4j/log4j-bom/2.24.1/c97ce07244367473d5337c9fe64fca0dd5b83914/log4j-bom-2.24.1.pom @@ -0,0 +1,362 @@ + + + + 4.0.0 + + org.apache.logging + logging-parent + 11.3.0 + + + org.apache.logging.log4j + log4j-bom + 2.24.1 + pom + Apache Log4j BOM + Apache Log4j Bill-of-Materials + https://logging.apache.org/log4j/2.x/ + 1999 + + The Apache Software Foundation + https://www.apache.org/ + + + + Apache-2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + rgoers + Ralph Goers + rgoers@apache.org + Nextiva + + PMC Member + + America/Phoenix + + + ggregory + Gary Gregory + ggregory@apache.org + https://www.garygregory.com + The Apache Software Foundation + https://www.apache.org/ + + PMC Member + + America/New_York + + + sdeboy + Scott Deboy + sdeboy@apache.org + + PMC Member + + America/Los_Angeles + + + rpopma + Remko Popma + rpopma@apache.org + + PMC Member + + Asia/Tokyo + + + nickwilliams + Nick Williams + nickwilliams@apache.org + + PMC Member + + America/Chicago + + + mattsicker + Matt Sicker + mattsicker@apache.org + Apple + + PMC Member + + America/Chicago + + + bbrouwer + Bruce Brouwer + bruce.brouwer@gmail.com + + Committer + + America/Detroit + + + rgupta + Raman Gupta + rgupta@apache.org + + Committer + + America/New York + + + mikes + Mikael Ståldal + mikes@apache.org + Spotify + + PMC Member + + Europe/Stockholm + + + ckozak + Carter Kozak + ckozak@apache.org + https://github.com/carterkozak + + PMC Member + + America/New York + + + vy + Volkan Yazıcı + vy@apache.org + + PMC Chair + + Europe/Amsterdam + + + rgrabowski + Ron Grabowski + rgrabowski@apache.org + + PMC Member + + America/New_York + + + pkarwasz + Piotr P. Karwasz + pkarwasz@apache.org + + PMC Member + + Europe/Warsaw + + + grobmeier + Christian Grobmeier + grobmeier@apache.org + + PMC Member + + Europe/Berlin + + + + + log4j-user + log4j-user-subscribe@logging.apache.org + log4j-user-unsubscribe@logging.apache.org + log4j-user@logging.apache.org + https://lists.apache.org/list.html?log4j-user@logging.apache.org + + + dev + dev-subscribe@logging.apache.org + dev-unsubscribe@logging.apache.org + dev@logging.apache.org + https://lists.apache.org/list.html?dev@logging.apache.org + + + security + security-subscribe@logging.apache.org + security-unsubscribe@logging.apache.org + security@logging.apache.org + https://lists.apache.org/list.html?security@logging.apache.org + + + + scm:git:https://github.com/apache/logging-log4j2.git + scm:git:https://github.com/apache/logging-log4j2.git + 2.x + https://github.com/apache/logging-log4j2 + + + GitHub Issues + https://github.com/apache/logging-log4j2/issues + + + GitHub Actions + https://github.com/apache/logging-log4j2/actions + + + + + org.apache.logging.log4j + log4j-1.2-api + 2.24.1 + + + org.apache.logging.log4j + log4j-api + 2.24.1 + + + org.apache.logging.log4j + log4j-api-test + 2.24.1 + + + org.apache.logging.log4j + log4j-appserver + 2.24.1 + + + org.apache.logging.log4j + log4j-cassandra + 2.24.1 + + + org.apache.logging.log4j + log4j-core + 2.24.1 + + + org.apache.logging.log4j + log4j-core-test + 2.24.1 + + + org.apache.logging.log4j + log4j-couchdb + 2.24.1 + + + org.apache.logging.log4j + log4j-docker + 2.24.1 + + + org.apache.logging.log4j + log4j-flume-ng + 2.23.1 + + + org.apache.logging.log4j + log4j-iostreams + 2.24.1 + + + org.apache.logging.log4j + log4j-jakarta-smtp + 2.24.1 + + + org.apache.logging.log4j + log4j-jakarta-web + 2.24.1 + + + org.apache.logging.log4j + log4j-jcl + 2.24.1 + + + org.apache.logging.log4j + log4j-jpa + 2.24.1 + + + org.apache.logging.log4j + log4j-jpl + 2.24.1 + + + org.apache.logging.log4j + log4j-jul + 2.24.1 + + + org.apache.logging.log4j + log4j-layout-template-json + 2.24.1 + + + org.apache.logging.log4j + log4j-mongodb4 + 2.24.1 + + + org.apache.logging.log4j + log4j-mongodb + 2.24.1 + + + org.apache.logging.log4j + log4j-slf4j2-impl + 2.24.1 + + + org.apache.logging.log4j + log4j-slf4j-impl + 2.24.1 + + + org.apache.logging.log4j + log4j-spring-boot + 2.24.1 + + + org.apache.logging.log4j + log4j-spring-cloud-config-client + 2.24.1 + + + org.apache.logging.log4j + log4j-taglib + 2.24.1 + + + org.apache.logging.log4j + log4j-to-jul + 2.24.1 + + + org.apache.logging.log4j + log4j-to-slf4j + 2.24.1 + + + org.apache.logging.log4j + log4j-web + 2.24.1 + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/org.apache.logging.log4j/log4j-core/2.24.1/223224bab554ccd1432363bc5b7623600d069618/log4j-core-2.24.1.pom b/.gradle-user/caches/modules-2/files-2.1/org.apache.logging.log4j/log4j-core/2.24.1/223224bab554ccd1432363bc5b7623600d069618/log4j-core-2.24.1.pom new file mode 100644 index 0000000..6ac8ba1 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.apache.logging.log4j/log4j-core/2.24.1/223224bab554ccd1432363bc5b7623600d069618/log4j-core-2.24.1.pom @@ -0,0 +1,248 @@ + + + + 4.0.0 + + org.apache.logging.log4j + log4j + 2.24.1 + ../log4j-parent + + log4j-core + 2.24.1 + Apache Log4j Core + A versatile, industrial-grade, and reference implementation of the Log4j API. + It bundles a rich set of components to assist various use cases: + Appenders targeting files, network sockets, databases, SMTP servers; + Layouts that can render CSV, HTML, JSON, Syslog, etc. formatted outputs; + Filters that can be configured using log event rates, regular expressions, scripts, time, etc. + It contains several extension points to introduce custom components, if needed. + + + Apache-2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + true + true + org.osgi.core;static=true;transitive=false, + + java.logging;static=true, + java.sql;static=true, + + com.fasterxml.jackson.annotation;transitive=false, + com.lmax.disruptor;transitive=false, + com.fasterxml.jackson.core;transitive=false, + com.fasterxml.jackson.databind;transitive=false, + com.fasterxml.jackson.dataformat.xml;transitive=false, + com.fasterxml.jackson.dataformat.yaml;transitive=false, + java.management;transitive=false;static=true, + java.naming;transitive=false, + org.apache.commons.csv;transitive=false, + org.fusesource.jansi;transitive=false, + org.jspecify;transitive=false, + org.zeromq.jeromq;transitive=false, + + com.conversantmedia.disruptor;substitute="disruptor";transitive=false;static=true, + + kafka.clients;substitute="kafka-clients";transitive=false;static=true, + javax.jms.api;substitute="javax.jms-api";transitive=false;static=true, + javax.mail.api;substitute="javax.mail-api";transitive=false;static=true + org.jspecify.*;resolution:=optional, + + com.conversantmedia.util.concurrent;resolution:=optional; + com.fasterxml.jackson.*;resolution:=optional, + com.lmax.disruptor.*;resolution:=optional, + javax.activation;resolution:=optional, + javax.jms;version="[1.1,3)";resolution:=optional, + javax.mail.*;version="[1.6,2)";resolution:=optional, + org.apache.commons.compress.*;resolution:=optional, + org.apache.commons.csv;resolution:=optional, + org.apache.kafka.*;resolution:=optional, + org.codehaus.stax2;resolution:=optional, + org.fusesource.jansi;resolution:=optional, + org.jctools.*;resolution:=optional, + org.zeromq;resolution:=optional, + javax.lang.model.*;resolution:=optional, + javax.tools;resolution:=optional, + + java.sql;resolution:=optional, + javax.sql;resolution:=optional, + java.util.logging;resolution:=optional, + + java.lang.management;resolution:=optional, + javax.management.*;resolution:=optional, + + javax.naming;resolution:=optional + false + ${log4j.docgen.pluginDescriptorsDir.phase1} + + + + javax.activation + javax.activation-api + provided + true + + + javax.jms + javax.jms-api + provided + true + + + javax.mail + javax.mail-api + provided + true + + + org.jspecify + jspecify + provided + + + org.osgi + org.osgi.core + provided + + + org.apache.logging.log4j + log4j-api + + + org.apache.commons + commons-compress + true + + + org.apache.commons + commons-csv + true + + + com.conversantmedia + disruptor + true + + + com.lmax + disruptor + true + + + com.fasterxml.jackson.core + jackson-core + true + + + com.fasterxml.jackson.core + jackson-databind + true + + + com.fasterxml.jackson.dataformat + jackson-dataformat-xml + true + + + com.fasterxml.jackson.dataformat + jackson-dataformat-yaml + true + + + org.fusesource.jansi + jansi + true + + + org.jctools + jctools-core + true + + + org.zeromq + jeromq + true + + + org.apache.kafka + kafka-clients + true + + + com.sun.mail + javax.mail + runtime + true + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + add-source + generate-sources + + add-source + + + + ${project.build.directory}/log4j-core-java9 + + + + + + + maven-dependency-plugin + + + unpack-classes + prepare-package + + unpack + + + + + org.apache.logging.log4j + log4j-core-java9 + ${project.version} + zip + false + + + **/*.class + **/*.java + ${project.build.directory} + false + true + + + + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/org.apache.logging.log4j/log4j-core/2.24.1/c85285146f28d8c8962384f786e2dff04172fb43/log4j-core-2.24.1.jar b/.gradle-user/caches/modules-2/files-2.1/org.apache.logging.log4j/log4j-core/2.24.1/c85285146f28d8c8962384f786e2dff04172fb43/log4j-core-2.24.1.jar new file mode 100644 index 0000000..ea8eefa Binary files /dev/null and b/.gradle-user/caches/modules-2/files-2.1/org.apache.logging.log4j/log4j-core/2.24.1/c85285146f28d8c8962384f786e2dff04172fb43/log4j-core-2.24.1.jar differ diff --git a/.gradle-user/caches/modules-2/files-2.1/org.apache.logging.log4j/log4j/2.24.1/2041494b56beb0070494e823ee65c9e6189118db/log4j-2.24.1.pom b/.gradle-user/caches/modules-2/files-2.1/org.apache.logging.log4j/log4j/2.24.1/2041494b56beb0070494e823ee65c9e6189118db/log4j-2.24.1.pom new file mode 100644 index 0000000..d132719 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.apache.logging.log4j/log4j/2.24.1/2041494b56beb0070494e823ee65c9e6189118db/log4j-2.24.1.pom @@ -0,0 +1,907 @@ + + + + 4.0.0 + + org.apache.logging.log4j + log4j-bom + 2.24.1 + + log4j + 2.24.1 + pom + Apache Log4j Parent + Apache Log4j Parent + + + Apache-2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + 2.17.2 + 3.5.12 + 1.5.6-6 + 7.0.5 + 2.35.2 + 1.7.0 + 2.12.0 + 15.4 + 0.45.0 + 2.3.3 + 2.0.3 + 9.1.0 + 3.3.4 + 1 + 4.0.1 + 2.1.3 + 2.10.0 + 1.3.4 + 3.17.0 + 1.2.17 + 1.10 + 1.17.1 + 4.13.2 + 4.0.22 + 1.3.14 + 5.15.0 + 0.2.0 + 2.0.8 + 1.2.15 + 3.9.9 + 6.0.0 + 1.2.0 + 2.2.224 + 1.27.1 + 2.2.2 + 3.8.0 + 1.6.2 + 3.11.17 + 3.5.1 + 1.37 + 1.14.9 + 6.1.3 + 33.3.0-jre + 2.0.3 + 3.0 + 3.5.0 + 2.15.0 + 2.7.18 + 2.0.1 + 4.5.14 + 2.2.4 + 9.6 + 3.26.3 + 2.4.1 + 3.4.4 + 4.13.5 + 2.0.2 + 2.17.0 + 5.3.39 + 2.0b6 + 0.9.0 + 2.40.1 + 2.7.3 + 2.2 + 4.11.0 + 1.9.1 + 2.7.15 + 4.4.16 + 2.4 + 4.13.5 + 5.10.3 + 1.11.0 + 0.6.0 + 3.11.5 + 4.2.2 + 2.1.3 + 3.21.0 + 1.6.0 + 4.0.5 + 1.7 + 2.12.0 + + + + + org.apache.logging.log4j + log4j-osgi-test + ${project.version} + + + org.apache.logging.log4j + log4j-layout-template-json-test + ${project.version} + + + org.apache.groovy + groovy-bom + ${groovy.version} + pom + import + + + com.fasterxml.jackson + jackson-bom + ${jackson-bom.version} + pom + import + + + jakarta.platform + jakarta.jakartaee-bom + ${jakartaee-bom.version} + pom + import + + + org.junit + junit-bom + ${junit-jupiter.version} + pom + import + + + org.mockito + mockito-bom + ${mockito.version} + pom + import + + + org.springframework + spring-framework-bom + ${spring-framework.version} + pom + import + + + org.apache.logging.log4j + log4j-api-java9 + ${project.version} + zip + + + org.apache.logging.log4j + log4j-core-java9 + ${project.version} + zip + + + org.apache.activemq + activemq-broker + ${activemq.version} + + + org.eclipse.angus + angus-activation + ${angus-activation.version} + + + org.assertj + assertj-core + ${assertj.version} + + + org.awaitility + awaitility + ${awaitility.version} + + + org.apache-extras.beanshell + bsh + ${bsh.version} + + + org.apache.cassandra + cassandra-all + ${cassandra.version} + + + org.slf4j + jcl-over-slf4j + + + org.slf4j + log4j-over-slf4j + + + ch.qos.logback + logback-classic + + + ch.qos.logback + logback-core + + + + + com.datastax.cassandra + cassandra-driver-core + ${cassandra-driver.version} + + + org.apache.cassandra + cassandra-thrift + ${cassandra.version} + + + org.slf4j + jcl-over-slf4j + + + org.slf4j + log4j-over-slf4j + + + + + commons-codec + commons-codec + ${commons-codec.version} + + + org.apache.commons + commons-compress + ${commons-compress.version} + + + org.apache.commons + commons-csv + ${commons-csv.version} + + + org.apache.commons + commons-dbcp2 + ${commons-dbcp2.version} + + + commons-io + commons-io + ${commons-io.version} + + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + + + commons-logging + commons-logging + ${commons-logging.version} + + + org.apache.commons + commons-pool2 + ${commons-pool2.version} + + + com.conversantmedia + disruptor + ${conversant.disruptor.version} + + + com.lmax + disruptor + ${disruptor.version} + + + org.zapodot + embedded-ldap-junit + ${embedded-ldap.version} + + + com.google.guava + guava + ${guava.version} + + + com.google.guava + guava-testlib + ${guava.version} + + + com.h2database + h2 + ${h2.version} + + + org.hamcrest + hamcrest + ${hamcrest.version} + + + org.hamcrest + hamcrest-core + ${hamcrest.version} + + + org.hamcrest + hamcrest-library + ${hamcrest.version} + + + org.hdrhistogram + HdrHistogram + ${HdrHistogram.version} + + + org.hsqldb + hsqldb + ${hsqldb.version} + jdk8 + + + org.apache.httpcomponents + httpclient + ${httpclient.version} + + + org.apache.httpcomponents + httpcore + ${httpcore.version} + + + jakarta.activation + jakarta.activation-api + ${jakarta-activation.version} + + + org.eclipse.angus + jakarta.mail + ${angus-mail.version} + + + jakarta.mail + jakarta.mail-api + ${jakarta-mail.version} + + + org.fusesource.jansi + jansi + ${jansi.version} + + + com.google.code.java-allocation-instrumenter + java-allocation-instrumenter + ${java-allocation-instrumenter.version} + + + javax.activation + javax.activation-api + ${javax-activation.version} + + + javax.inject + javax.inject + ${javax-inject.version} + + + javax.jms + javax.jms-api + ${javax-jms.version} + + + com.sun.mail + javax.mail + ${javax-mail.version} + + + javax.mail + javax.mail-api + ${javax-mail.version} + + + javax.persistence + javax.persistence-api + ${javax-persistence.version} + + + javax.servlet.jsp + javax.servlet.jsp-api + ${javax-servlet-jsp.version} + + + javax.servlet + javax.servlet-api + ${javax-servlet.version} + + + com.sun + jconsole + ${jconsole.version} + + + org.jctools + jctools-core + ${jctools.version} + + + org.zeromq + jeromq + ${jeromq.version} + + + org.jmdns + jmdns + ${jmdns.version} + + + org.openjdk.jmh + jmh-core + ${jmh.version} + + + org.openjdk.jmh + jmh-generator-annprocess + ${jmh.version} + + + net.java.dev.jna + jna + ${jna.version} + + + net.javacrumbs.json-unit + json-unit + ${json-unit.version} + + + junit + junit + ${junit.version} + + + org.junit-pioneer + junit-pioneer + ${junit-pioneer.version} + + + org.apache.kafka + kafka-clients + ${kafka.version} + + + org.lightcouch + lightcouch + ${lightcouch.version} + + + log4j + log4j + ${log4j.version} + + + co.elastic.logging + log4j2-ecs-layout + ${log4j2-ecs-layout.version} + + + ch.qos.logback + logback-classic + ${logback.version} + + + ch.qos.logback + logback-classic + ${logback.version} + test-jar + + + ch.qos.logback + logback-core + ${logback.version} + + + ch.qos.logback + logback-core + ${logback.version} + test-jar + + + org.apache.maven + maven-core + ${maven.version} + + + org.apache.maven + maven-model + ${maven.version} + + + org.openjdk.nashorn + nashorn-core + ${nashorn.version} + + + org.apache.felix + org.apache.felix.framework + ${felix.version} + + + org.eclipse.platform + org.eclipse.osgi + ${org.eclipse.osgi.version} + + + org.eclipse.persistence + org.eclipse.persistence.jpa + ${org.eclipse.persistence.version} + + + org.eclipse.persistence + jakarta.persistence + + + + + org.osgi + org.osgi.core + ${osgi.api.version} + + + oro + oro + ${oro.version} + + + org.ops4j.pax.exam + pax-exam + ${pax-exam.version} + + + org.ops4j.pax.exam + pax-exam-container-native + ${pax-exam.version} + + + org.ops4j.pax.exam + pax-exam-junit4 + ${pax-exam.version} + + + org.ops4j.pax.exam + pax-exam-link-assembly + ${pax-exam.version} + + + org.ops4j.pax.exam + pax-exam-spi + ${pax-exam.version} + + + org.codehaus.plexus + plexus-utils + ${plexus-utils.version} + + + org.springframework.boot + spring-boot + ${spring-boot.version} + + + org.springframework.boot + spring-boot-autoconfigure + ${spring-boot.version} + + + org.springframework.boot + spring-boot-starter-log4j2 + ${spring-boot.version} + + + org.springframework.boot + spring-boot-starter-test + ${spring-boot.version} + + + org.springframework.boot + spring-boot-starter-logging + + + + + org.springframework + spring-core + ${spring-framework.version} + + + org.springframework + spring-jcl + + + + + uk.org.webcompere + system-stubs-core + ${system-stubs.version} + + + uk.org.webcompere + system-stubs-jupiter + ${system-stubs.version} + + + org.apache.velocity + velocity + ${velocity.version} + + + com.github.tomakehurst + wiremock-jre8 + ${wiremock.version} + + + org.xmlunit + xmlunit-core + ${xmlunit.version} + + + org.xmlunit + xmlunit-matchers + ${xmlunit.version} + + + org.tukaani + xz + ${xz.version} + + + com.github.luben + zstd-jni + ${zstd.version} + + + + + + biz.aQute.bnd + biz.aQute.bnd.annotation + provided + + + com.google.errorprone + error_prone_annotations + ${error-prone.version} + provided + + + org.osgi + osgi.annotation + provided + + + org.osgi + org.osgi.annotation.bundle + provided + + + com.github.spotbugs + spotbugs-annotations + provided + + + + + + + io.fabric8 + docker-maven-plugin + ${docker-maven-plugin.version} + + + org.ops4j.pax.exam + exam-maven-plugin + ${exam-maven-plugin.version} + + + net.sourceforge.maven-taglib + maven-taglib-plugin + ${maven-taglib-plugin.version} + + + + + + maven-clean-plugin + + + delete-module-descriptors + process-sources + + clean + + + true + + + ${project.build.outputDirectory} + + module-info.class + META-INF/versions/** + + + + + + + + + maven-enforcer-plugin + + + ban-logging-dependencies + + enforce + + + + + + org.slf4j:jcl-over-slf4j + org.springframework:spring-jcl + org.slf4j:log4j-over-slf4j + ch.qos.reload4j:reload4j + org.slf4j:slf4j-log4j12 + org.slf4j:slf4j-reload4j + org.ops4j.pax.logging:* + ch.qos.logback:* + + + + + + + + + org.codehaus.gmavenplus + gmavenplus-plugin + + + ban-static-transitive + verify + + execute + + + false + + + + + + + + + + + + plugin-processing + + + .log4j-plugin-processing-activator + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + define-log4jDocgenDescriptorFilepath + process-resources + + bsh-property + + + + log4jDocgenDescriptorFilepath + + Properties properties = project.getProperties(); + String pluginDescriptorsDir = "true".equals(properties.getProperty("log4j.docgen.skip")) + ? properties.getProperty("log4j.docgen.pluginDescriptorsDir.skipped") + : properties.getProperty("log4j.docgen.pluginDescriptorsDir"); + String log4jDocgenDescriptorFilepath = String.format("%s/%s-plugins.xml", new Object[] { + pluginDescriptorsDir, project.getArtifactId() + }); + + + + + + maven-compiler-plugin + + + default-compile + + + default-testCompile + + + generate-plugin-descriptors + + compile + testCompile + + + + + org.apache.logging.log4j + log4j-docgen + ${log4j-docgen.version} + + + org.apache.logging.log4j + log4j-core + ${project.version} + + + + org.apache.logging.log4j.docgen.processor.DescriptorGenerator + org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor + + + -Alog4j.docgen.descriptorFilePath=${log4jDocgenDescriptorFilepath} + -Alog4j.docgen.groupId=${project.groupId} + -Alog4j.docgen.artifactId=${project.artifactId} + -Alog4j.docgen.version=${project.version} + -Alog4j.docgen.description=${project.description} + -Alog4j.docgen.typeFilter.excludePattern=${log4j.docgen.typeFilter.excludePattern} + + only + + + + + + + + ${maven.multiModuleProjectDirectory}/target/plugin-descriptors/skipped + ${log4j.docgen.pluginDescriptorsDir.phase2} + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/org.apache.logging/logging-parent/11.3.0/1cd611f1812fbb7ae78de8bbe57c2bb4129d5f2/logging-parent-11.3.0.pom b/.gradle-user/caches/modules-2/files-2.1/org.apache.logging/logging-parent/11.3.0/1cd611f1812fbb7ae78de8bbe57c2bb4129d5f2/logging-parent-11.3.0.pom new file mode 100644 index 0000000..6c7d0d2 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.apache.logging/logging-parent/11.3.0/1cd611f1812fbb7ae78de8bbe57c2bb4129d5f2/logging-parent-11.3.0.pom @@ -0,0 +1,1301 @@ + + + + 4.0.0 + + org.apache + apache + 33 + + org.apache.logging + logging-parent + 11.3.0 + pom + Apache Logging Parent + Parent project internally used in Maven-based projects of the Apache Logging Services + https://logging.apache.org/logging-parent + 1999 + + + Apache-2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + ggregory + Gary Gregory + ggregory@apache.org + https://www.garygregory.com + The Apache Software Foundation + https://www.apache.org/ + + PMC Member + + America/New_York + + + grobmeier + Christian Grobmeier + grobmeier@apache.org + + PMC Member + + Europe/Berlin + + + mattsicker + Matt Sicker + mattsicker@apache.org + Apple + + PMC Member + + America/Chicago + + + pkarwasz + Piotr P. Karwasz + pkarwasz@apache.org + + PMC Member + + Europe/Warsaw + + + vy + Volkan Yazıcı + vy@apache.org + + PMC Chair + + Europe/Amsterdam + + + + + log4j-user + log4j-user-subscribe@logging.apache.org + log4j-user-unsubscribe@logging.apache.org + log4j-user@logging.apache.org + https://lists.apache.org/list.html?log4j-user@logging.apache.org + + + dev + dev-subscribe@logging.apache.org + dev-unsubscribe@logging.apache.org + dev@logging.apache.org + https://lists.apache.org/list.html?dev@logging.apache.org + + + + scm:git:git@github.com:apache/logging-parent.git + scm:git:git@github.com:apache/logging-parent.git + https://github.com/apache/logging-parent + + + GitHub Issues + https://github.com/apache/logging-parent/issues + + + GitHub Actions + https://github.com/apache/logging-parent/actions + + + https://logging.apache.org/download.html + + + 1.1.0 + 4.8.6 + 1.13.0 + 1.6.0 + 8.1.0 + 1.0.0 + 4.0.23 + 3.0.2 + 2.0.1 + 10.5.0 + [17,18) + 2.50.0 + https://logging.apache.org/cyclonedx/vdr.xml + 8 + 1.15.0 + 7.0.0.202409031743-r + $[Bundle-SymbolicName] + 11.3.0 + 2.43.0 + false + 1.22.1 + + 2.8.1 + 1.1.0 + 3.3.0 + 8 + 7.0.0 + 7.0.0 + + $[bnd-module-name];access=0 + 3.0.0 + 2.0.0 + 1.1.2 + 0.9.0 + 0.8.12 + 7.0.0 + 2.32.0 + $[project.groupId].$[subst;$[subst;$[project.artifactId];log4j-];[^A-Za-z0-9];.] + + 3.6.0 + 3.5.1 + 3.8.1 + 4.8.6.3 + 8 + 21.7.1 + 2024-09-17T15:46:19Z + 11.0.0 + 2.5.0 + + + + + org.apache.logging + logging-parent + ${site-project.version} + pom + + + biz.aQute.bnd + biz.aQute.bnd.annotation + ${bnd.annotation.version} + + + com.github.spotbugs + spotbugs-annotations + ${spotbugs-annotations.version} + + + org.jspecify + jspecify + ${jspecify.version} + + + org.osgi + osgi.annotation + ${osgi.annotation.version} + + + org.osgi + org.osgi.annotation.bundle + ${osgi.annotation.bundle.version} + + + org.osgi + org.osgi.annotation.versioning + ${osgi.annotation.versioning.version} + + + + + + + + org.asciidoctor + asciidoctor-maven-plugin + ${asciidoctor-maven-plugin.version} + + + biz.aQute.bnd + bnd-baseline-maven-plugin + ${bnd-baseline-maven-plugin.version} + + + biz.aQute.bnd + bnd-maven-plugin + ${bnd-maven-plugin.version} + + + org.codehaus.mojo + build-helper-maven-plugin + ${build-helper-maven-plugin.version} + + + org.cyclonedx + cyclonedx-maven-plugin + ${cyclonedx-maven-plugin.version} + + + com.gradle + develocity-maven-extension + ${develocity-maven-plugin.version} + + + com.gradle + common-custom-user-data-maven-extension + ${develocity-user-data-extension.version} + + + org.codehaus.mojo + flatten-maven-plugin + ${flatten-maven-plugin.version} + + + org.codehaus.gmavenplus + gmavenplus-plugin + ${gmavenplus-plugin.version} + + + org.apache.groovy + groovy + ${groovy.version} + runtime + + + org.apache.groovy + groovy-ant + ${groovy.version} + runtime + + + + + org.jacoco + jacoco-maven-plugin + ${jacoco-maven-plugin.version} + + + org.apache.logging.log4j + log4j-changelog-maven-plugin + ${log4j-changelog-maven-plugin.version} + + + maven-artifact-plugin + ${maven-artifact-plugin.version} + + + org.simplify4u.plugins + sign-maven-plugin + ${sign-maven-plugin.version} + + + com.github.spotbugs + spotbugs-maven-plugin + ${spotbugs-maven-plugin.version} + + + com.diffplug.spotless + spotless-maven-plugin + ${spotless-maven-plugin.version} + + + org.codehaus.mojo + xml-maven-plugin + ${xml-maven-plugin.version} + + + + + + org.codehaus.mojo + flatten-maven-plugin + + + flatten-revision + process-resources + + flatten + + + true + resolveCiFriendliesOnly + + + + clean-flattened-pom + clean + + clean + + + + flatten-bom + none + + flatten + + + bom + + remove + remove + remove + remove + interpolate + keep + + + + + + + maven-clean-plugin + + + delete-module-descriptor + process-resources + + clean + + + true + + + ${project.build.outputDirectory} + + module-info.class + + + + + + + + + maven-compiler-plugin + + + default-testCompile + + false + + + + + ${maven.compiler.source} + ${maven.compiler.release} + ${maven.compiler.target} + ${project.build.sourceEncoding} + true + + -Xlint:all + -XDcompilePolicy=simple + -Xplugin:ErrorProne + + + + com.google.errorprone + error_prone_core + ${error-prone.version} + + + + + + maven-failsafe-plugin + + false + + + + maven-surefire-plugin + + false + + + + org.cyclonedx + cyclonedx-maven-plugin + + + generate-sbom + package + + makeAggregateBom + + + + + vulnerability-assertion + ${vdr.url} + + + xml + + + + + + maven-enforcer-plugin + + + enforce-upper-bound-deps + + enforce + + + + + + + + + ban-wildcard-imports + + enforce + + + + + Expand all wildcard imports + **.'*' + + + + + + + + de.skuzzle.enforcer + restrict-imports-enforcer-rule + ${restrict-imports-enforcer-rule.version} + + + + + com.github.spotbugs + spotbugs-maven-plugin + + + default-spotbugs + verify + + check + + + false + + + com.h3xstream.findsecbugs + findsecbugs-plugin + ${findsecbugs-plugin.version} + + + + + + + + org.apache.rat + apache-rat-plugin + + + verify + + check + + + + + true + + .java-version + .mvn/jvm.config + **/*.txt + src/changelog/**/*.xml + .github/ISSUE_TEMPLATE/*.md + .github/pull_request_template.md + + + + + com.diffplug.spotless + spotless-maven-plugin + + + default-spotless + verify + + check + + + + + + com.palantir.javaformat + palantir-java-format + ${palantir-java-format.version} + + + + + + /* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + + ${palantir-java-format.version} + + + + + <?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Licensed to the Apache Software Foundation (ASF) under one or more + ~ contributor license agreements. See the NOTICE file distributed with + ~ this work for additional information regarding copyright ownership. + ~ The ASF licenses this file to you under the Apache License, Version 2.0 + ~ (the "License"); you may not use this file except in compliance with + ~ the License. You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + <project + + + false + true + + + + + + src/**/*.xml + + + src/changelog/**/*.xml + + + <?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Licensed to the Apache Software Foundation (ASF) under one or more + ~ contributor license agreements. See the NOTICE file distributed with + ~ this work for additional information regarding copyright ownership. + ~ The ASF licenses this file to you under the Apache License, Version 2.0 + ~ (the "License"); you may not use this file except in compliance with + ~ the License. You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + <(!DOCTYPE|\w) + + + + + + + src/**/*.properties + + + # +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to you under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + (##|[^#]) + + + + + + + .asf.yaml + .github/**/*.yaml + .github/**/*.yml + src/**/*.yaml + src/**/*.yml + + + # +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to you under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + (##|[^#]) + + + + + UNIX + + + + org.codehaus.mojo + build-helper-maven-plugin + + + parse-version + validate + + parse-version + + + + + + biz.aQute.bnd + bnd-maven-plugin + + + generate-module-descriptors + + bnd-process + + + + + # `Bundle-DocURL` uses `project.url`. + # This is set to `${project.parent.url}${project.artifactId}` through Maven's inheritance assembly[1]. + # This eventually produces incorrect values. + # Hence, we remove them from the produced descriptor. + # + # `Bundle-SCM` uses `project.scm.url` and suffers from the same inheritance problem `Bundle-DocURL` has. + # + # [1] https://maven.apache.org/ref/3.9.4/maven-model-builder/#inheritance-assembly + # Inheritance assembly can be disabled for certain properties, e.g., `project.url`. + # Though this would necessitate changes in the root `pom.xml`s of parented projects. + # + # `Bundle-Developers` is removed, since it is nothing but noise and occupies quite some real estate. + -removeheaders: Bundle-DocURL,Bundle-SCM,Bundle-Developers + + # Create OSGi and JPMS module names based on the `groupId` and `artifactId`. + # This almost agrees with `maven-bundle-plugin`, but replaces non-alphanumeric characters + # with full stops `.`. + Bundle-SymbolicName: $[bnd-bundle-symbolicname] + -jpms-module-info: $[bnd-jpms-module-info] + + # Prevents an execution error in multi-release jars: + -fixupmessages.classes_in_wrong_dir: "Classes found in the wrong directory";restrict:=error;is:=warning + + # Convert API leakage warnings to errors + -fixupmessages.priv_refs: "private references";restrict:=warning;is:=error + + # 1. OSGI modules do not make sense in JPMS + # 2. BND has a problem detecting the name of multi-release JPMS modules + -jpms-module-info-options: \ + $[bnd-extra-module-options],\ + org.osgi.core;static=true;transitive=false,\ + org.osgi.framework;static=true;transitive=false,\ + org.apache.logging.log4j;substitute="log4j-api",\ + org.apache.logging.log4j.core;substitute="log4j-core" + + # Import all packages by default: + Import-Package: \ + $[bnd-extra-package-options],\ + * + + # Allow each project to override the `Multi-Release` header: + Multi-Release: $[bnd-multi-release] + +# Skipping to set `-jpms-multi-release` to `bnd-multi-release`. +# This would generate descriptors in `META-INF/versions/<version>` directories needed for MRJs. +# Though we decided to skip it due to following reasons: +# 1. It is only needed by a handful of files in `-java9`-suffixed modules of `logging-log4j2`. +# Hence, it is effectively insignificant. +# 2. `dependency:unpack` and `bnd:bnd-process` executions must be aligned correctly. +# See this issue for details: https://github.com/apache/logging-parent/issues/93 + # Adds certain `Implementation-*` and `Specification-*` entries to the generated `MANIFEST.MF`. + # Using these properties is known to be a bad practice: https://github.com/apache/logging-log4j2/issues/1923#issuecomment-1786818254 + # Users should use `META-INF/maven/<groupId>/<artifactId>/pom.properties` instead. + # Yet we support it due to backward compatibility reasons. + # The issue was reported to `bnd-maven-plugin` too: https://github.com/bndtools/bnd/issues/5855 + # We set these values to their Maven Archiver defaults: https://maven.apache.org/shared/maven-archiver/#class_manifest + Implementation-Title: ${project.name} + Implementation-Vendor: ${project.organization.name} + Implementation-Version: ${project.version} + Specification-Title: ${project.name} + Specification-Vendor: ${project.organization.name} + Specification-Version: ${parsedVersion.majorVersion}.${parsedVersion.minorVersion} + + # Extra configuration provided by the consumer: + ${bnd-extra-config} + + + + maven-jar-plugin + + + ${project.build.outputDirectory}/META-INF/MANIFEST.MF + + + + + biz.aQute.bnd + bnd-baseline-maven-plugin + + + check-api-compat + + baseline + + + + + false + true + + + + + + + changelog-validate + + + src/changelog + + + + + + org.codehaus.mojo + xml-maven-plugin + + + validate-changelog + validate + + validate + + + + + src/changelog + + **/*.xml + + https://logging.apache.org/xml/ns + https://logging.apache.org/xml/ns/log4j-changelog-0.xsd + true + + + + + + + + + + + changelog-release + + log4j-changelog:release@release-changelog generate-sources + + + org.apache.logging.log4j + log4j-changelog-maven-plugin + + + release-changelog + + ${project.version} + + + + + + + + + distribution + + enforcer:enforce@enforce-distribution-arguments gplus:execute@create-distribution + + + maven-enforcer-plugin + + + enforce-distribution-arguments + + enforce + + + + + attachmentFilepathPattern + You must set an `attachmentFilepathPattern` property for the regex pattern matched against the filepath relative to the main project directory for determining attachments to be included in the distribution! + + + attachmentCount + You must set an `attachmentCount` property for the number of attachments expected to be found! + + + true + + + + + + org.codehaus.gmavenplus + gmavenplus-plugin + + + create-distribution + + execute + + + + ${project.build.directory} + ${project.build.outputTimestamp} + ${attachmentCount} + ${attachmentFilepathPattern} + ${project.build.directory}/generated-site/antora/modules/ROOT/pages/_release-notes/${project.version}.adoc + + + + + + + + + + org.eclipse.jgit + org.eclipse.jgit + ${org.eclipse.jgit.version} + + + + + + + + deploy + + deploy + + + org.simplify4u.plugins + sign-maven-plugin + + + + sign + + + + + + + + true + true + true + true + true + + + + release + + + + maven-source-plugin + + + attach-sources + + jar-no-fork + + + + + + maven-enforcer-plugin + + + enforce-no-snapshots + + enforce + + + + + A release cannot have SNAPSHOT dependencies + true + + + A release cannot be a SNAPSHOT version + + + true + + + + + + + + + antora + + + src/site/antora + + + + + + org.apache.logging.log4j + log4j-changelog-maven-plugin + + + export-changelog + pre-site + + export + + + ${project.build.directory}/generated-site/antora/modules/ROOT/pages + + + + + + + + + + + + maven-antrun-plugin + + + copy-antora-yml + pre-site + + run + + + + + + + + + + + maven-resources-plugin + + + filter-antora-yml + pre-site + + copy-resources + + + ${project.build.directory}/generated-site/antora + + + ${project.build.directory}/antora-yml + true + + + + + + copy-site + pre-site + + copy-resources + + + ${project.build.directory}/generated-site + + + ${project.basedir}/src/site + + antora/antora.yml + + + + + + + + + com.github.eirslett + frontend-maven-plugin + ${frontend-maven-plugin.version} + + + install-node-and-npm + pre-site + + install-node-and-npm + + + v${node.version} + ${npm.version} + + + + install-antora + pre-site + + npm + + + + + + org.codehaus.mojo + exec-maven-plugin + ${exec-maven-plugin.version} + + + run-antora + site + + exec + + + ${project.basedir}/node/node + + --eval + require('@antora/cli')(['generate', '--playbook', 'antora-playbook.yaml', '--to-dir', 'target/site']) + + + + + + + + + true + true + + + + spotbugs-exclude + + + ${maven.multiModuleProjectDirectory}/spotbugs-exclude.xml + + + + + + com.github.spotbugs + spotbugs-maven-plugin + + ${maven.multiModuleProjectDirectory}/spotbugs-exclude.xml + + + + + + + coverage + + + + org.jacoco + jacoco-maven-plugin + + + prepare-jacoco-agent + + prepare-agent + + + + report-test-coverage + + report + + + + + + org/apache/log4j/** + org/apache/logging/** + + + **/test/** + + + + + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/org.apache.maven/maven-api-meta/4.0.0-alpha-9/280d504b8ab514865517fd8fe7bea295e7b23d51/maven-api-meta-4.0.0-alpha-9.pom b/.gradle-user/caches/modules-2/files-2.1/org.apache.maven/maven-api-meta/4.0.0-alpha-9/280d504b8ab514865517fd8fe7bea295e7b23d51/maven-api-meta-4.0.0-alpha-9.pom new file mode 100644 index 0000000..4df6602 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.apache.maven/maven-api-meta/4.0.0-alpha-9/280d504b8ab514865517fd8fe7bea295e7b23d51/maven-api-meta-4.0.0-alpha-9.pom @@ -0,0 +1,33 @@ + + + + 4.0.0 + + + org.apache.maven + maven-api + 4.0.0-alpha-9 + + + maven-api-meta + Maven 4 API :: Meta annotations + Maven 4 API - Java meta annotations. + + diff --git a/.gradle-user/caches/modules-2/files-2.1/org.apache.maven/maven-api-meta/4.0.0-alpha-9/5d7a76734ec7ccef673dab5d02ed7f8d08a7f11c/maven-api-meta-4.0.0-alpha-9.jar b/.gradle-user/caches/modules-2/files-2.1/org.apache.maven/maven-api-meta/4.0.0-alpha-9/5d7a76734ec7ccef673dab5d02ed7f8d08a7f11c/maven-api-meta-4.0.0-alpha-9.jar new file mode 100644 index 0000000..a0f520e Binary files /dev/null and b/.gradle-user/caches/modules-2/files-2.1/org.apache.maven/maven-api-meta/4.0.0-alpha-9/5d7a76734ec7ccef673dab5d02ed7f8d08a7f11c/maven-api-meta-4.0.0-alpha-9.jar differ diff --git a/.gradle-user/caches/modules-2/files-2.1/org.apache.maven/maven-api-xml/4.0.0-alpha-9/798cc54142427938ee719628bead0aa10c630726/maven-api-xml-4.0.0-alpha-9.pom b/.gradle-user/caches/modules-2/files-2.1/org.apache.maven/maven-api-xml/4.0.0-alpha-9/798cc54142427938ee719628bead0aa10c630726/maven-api-xml-4.0.0-alpha-9.pom new file mode 100644 index 0000000..7de464d --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.apache.maven/maven-api-xml/4.0.0-alpha-9/798cc54142427938ee719628bead0aa10c630726/maven-api-xml-4.0.0-alpha-9.pom @@ -0,0 +1,41 @@ + + + + 4.0.0 + + + org.apache.maven + maven-api + 4.0.0-alpha-9 + + + maven-api-xml + Maven 4 API :: XML + Maven 4 API - Immutable XML. + + + + org.apache.maven + maven-api-meta + 4.0.0-alpha-9 + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/org.apache.maven/maven-api-xml/4.0.0-alpha-9/b3c6e54002f8ec8df8c913b7ae36998ff4418d97/maven-api-xml-4.0.0-alpha-9.jar b/.gradle-user/caches/modules-2/files-2.1/org.apache.maven/maven-api-xml/4.0.0-alpha-9/b3c6e54002f8ec8df8c913b7ae36998ff4418d97/maven-api-xml-4.0.0-alpha-9.jar new file mode 100644 index 0000000..1edd9e2 Binary files /dev/null and b/.gradle-user/caches/modules-2/files-2.1/org.apache.maven/maven-api-xml/4.0.0-alpha-9/b3c6e54002f8ec8df8c913b7ae36998ff4418d97/maven-api-xml-4.0.0-alpha-9.jar differ diff --git a/.gradle-user/caches/modules-2/files-2.1/org.apache.maven/maven-api/4.0.0-alpha-9/a75a0a86f4ec1fb94ae0ec71b9577091ee48af41/maven-api-4.0.0-alpha-9.pom b/.gradle-user/caches/modules-2/files-2.1/org.apache.maven/maven-api/4.0.0-alpha-9/a75a0a86f4ec1fb94ae0ec71b9577091ee48af41/maven-api-4.0.0-alpha-9.pom new file mode 100644 index 0000000..a52b1f0 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.apache.maven/maven-api/4.0.0-alpha-9/a75a0a86f4ec1fb94ae0ec71b9577091ee48af41/maven-api-4.0.0-alpha-9.pom @@ -0,0 +1,115 @@ + + + + 4.0.0 + + + org.apache.maven + maven + 4.0.0-alpha-9 + + + maven-api + pom + Maven 4 API + A new immutable API for Maven 4 to better manage what plugins and extensions can influence. + + + maven-api-meta + maven-api-xml + maven-api-model + maven-api-plugin + maven-api-settings + maven-api-toolchain + maven-api-core + maven-api-spi + + + + api + + + + + + + org.codehaus.modello + modello-maven-plugin + + + modello-site-docs + + xdoc + xsd + + none + + + + + + + + + + reporting + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + + provisional + tf + Provisional: + + + + + + aggregate + + aggregate + + false + + + + + org.apache.maven.plugins + maven-jxr-plugin + + + aggregate + + aggregate + + false + + + + + + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/org.apache.maven/maven-bom/4.0.0-alpha-9/435b91611948c35b87a5c5e859f2c89502a4cf7e/maven-bom-4.0.0-alpha-9.pom b/.gradle-user/caches/modules-2/files-2.1/org.apache.maven/maven-bom/4.0.0-alpha-9/435b91611948c35b87a5c5e859f2c89502a4cf7e/maven-bom-4.0.0-alpha-9.pom new file mode 100644 index 0000000..408fe79 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.apache.maven/maven-bom/4.0.0-alpha-9/435b91611948c35b87a5c5e859f2c89502a4cf7e/maven-bom-4.0.0-alpha-9.pom @@ -0,0 +1,208 @@ + + + + 4.0.0 + + org.apache.maven + maven-parent + 41 + + + + maven-bom + 4.0.0-alpha-9 + pom + + Maven Dependencies BOM + Bill Of Materials for Apache Maven dependencies + https://maven.apache.org/ref/${project.version}/${project.artifactId} + + + scm:git:https://gitbox.apache.org/repos/asf/maven.git + scm:git:https://gitbox.apache.org/repos/asf/maven.git + maven-4.0.0-alpha-9 + https://github.com/apache/maven/tree/${project.scm.tag}/${project.artifactId} + + + jira + https://issues.apache.org/jira/browse/MNG + + + Jenkins + https://ci-maven.apache.org/job/Maven/job/maven-box/job/maven/ + + + + apache.website + scm:svn:https://svn.apache.org/repos/asf/maven/website/components/${maven.site.path} + + https://maven.apache.org/download.html + + + + ref/4-LATEST/${project.artifactId} + + + + + + + org.apache.maven + maven-artifact + ${project.version} + + + org.apache.maven + maven-builder-support + ${project.version} + + + org.apache.maven + maven-core + ${project.version} + + + org.apache.maven + maven-embedder + ${project.version} + + + org.apache.maven + maven-model + ${project.version} + + + org.apache.maven + maven-api-core + ${project.version} + + + org.apache.maven + maven-api-meta + ${project.version} + + + org.apache.maven + maven-api-model + ${project.version} + + + org.apache.maven + maven-api-settings + ${project.version} + + + org.apache.maven + maven-api-spi + ${project.version} + + + org.apache.maven + maven-api-toolchain + ${project.version} + + + org.apache.maven + maven-api-plugin + ${project.version} + + + org.apache.maven + maven-api-xml + ${project.version} + + + org.apache.maven + maven-model-builder + ${project.version} + + + org.apache.maven + maven-plugin-api + ${project.version} + + + org.apache.maven + maven-repository-metadata + ${project.version} + + + org.apache.maven + maven-resolver-provider + ${project.version} + + + org.apache.maven + maven-settings + ${project.version} + + + org.apache.maven + maven-settings-builder + ${project.version} + + + org.apache.maven + maven-toolchain-model + ${project.version} + + + org.apache.maven + maven-toolchain-builder + ${project.version} + + + org.apache.maven + maven-slf4j-wrapper + ${project.version} + + + org.apache.maven + maven-xml-impl + ${project.version} + + + + + + + + maven-site-plugin + + ${project.distributionManagement.site.url}/.. + + + + org.apache.rat + apache-rat-plugin + + + rat-check + none + + + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/org.apache.maven/maven-parent/41/c60098252d5841553d75a7d7382db46e6859d84d/maven-parent-41.pom b/.gradle-user/caches/modules-2/files-2.1/org.apache.maven/maven-parent/41/c60098252d5841553d75a7d7382db46e6859d84d/maven-parent-41.pom new file mode 100644 index 0000000..dc9bf71 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.apache.maven/maven-parent/41/c60098252d5841553d75a7d7382db46e6859d84d/maven-parent-41.pom @@ -0,0 +1,1593 @@ + + + + 4.0.0 + + + + org.apache + apache + 31 + + + + org.apache.maven + maven-parent + 41 + pom + + Apache Maven + Maven is a software project management and comprehension tool. Based on the concept of a project object model (POM), Maven can manage a project's build, reporting and documentation from a central piece of information. + https://maven.apache.org/ + 2002 + + + + + khmarbaise + Karl Heinz Marbaise + khmarbaise@apache.org + + PMC Chair + + +1 + + @khmarbaise + + + + aheritier + Arnaud Héritier + aheritier@apache.org + + PMC Member + + +1 + + + andham + Anders Hammar + andham@apache.org + + PMC Member + + +1 + + + baerrach + Barrie Treloar + baerrach@apache.org + + PMC Member + + Australia/Adelaide + + + bimargulies + Benson Margulies + bimargulies@apache.org + + PMC Member + + America/New_York + + + bmarwell + Benjamin Marwell + bmarwell@apache.org + ASF + + PMC Member + + Europe/Berlin + + + brianf + Brian Fox + brianf@apache.org + Sonatype + + PMC Member + + -5 + + + cstamas + Tamas Cservenak + cstamas@apache.org + + PMC Member + + +1 + + + dennisl + Dennis Lundberg + dennisl@apache.org + ASF + + PMC Member + + +1 + + + dkulp + Daniel Kulp + dkulp@apache.org + ASF + + PMC Member + + -5 + + + evenisse + Emmanuel Venisse + evenisse@apache.org + ASF + + PMC Member + + +1 + + + gboue + Guillaume Boué + gboue@apache.org + + PMC Member + + Europe/Paris + + + gnodet + Guillaume Nodet + gnodet@apache.org + Red Hat + + PMC Member + + Europe/Paris + + + henning + Henning Schmiedehausen + henning@apache.org + ASF + + PMC Member + + America/Los_Angeles + + + hboutemy + Hervé Boutemy + hboutemy@apache.org + ASF + + PMC Member + + Europe/Paris + + + ifedorenko + Igor Fedorenko + igor@ifedorenko.com + Sonatype + + PMC Member + + -5 + + + jvanzyl + Jason van Zyl + jason@maven.org + + PMC Member + + -5 + + + krosenvold + Kristian Rosenvold + krosenvold@apache.org + + PMC Member + + +1 + + + kwin + Konrad Windszus + kwin@apache.org + Cognizant Netcentric + + PMC Member + + Europe/Berlin + + + mkleint + Milos Kleint + + PMC Member + + + + mthmulders + Maarten Mulders + mthmulders@apache.org + Info Support + + PMC Member + + Europe/Amsterdam + + + olamy + Olivier Lamy + olamy@apache.org + + PMC Member + + Australia/Brisbane + + + michaelo + Michael Osipov + michaelo@apache.org + + PMC Member + + Europe/Berlin + + + rfscholte + Robert Scholte + rfscholte@apache.org + + PMC Member + + Europe/Amsterdam + + @rfscholte + + + + rgoers + Ralph Goers + rgoers@apache.org + Intuit + + PMC Member + + -8 + + + sjaranowski + Slawomir Jaranowski + sjaranowski@apache.org + + PMC Member + + Europe/Warsaw + + + stephenc + Stephen Connolly + stephenc@apache.org + + PMC Member + + 0 + + + slachiewicz + Sylwester Lachiewicz + slachiewicz@apache.org + + PMC Member + + Europe/Warsaw + + + struberg + Mark Struberg + struberg@apache.org + + PMC Member + + + + tibordigana + Tibor Digaňa + tibordigana@apache.org + + PMC Member + + Europe/Bratislava + + + vsiveton + Vincent Siveton + vsiveton@apache.org + ASF + + PMC Member + + -5 + + + wfay + Wayne Fay + wfay@apache.org + ASF + + PMC Member + + -6 + + + + + adangel + Andreas Dangel + adangel@apache.org + + Committer + + Europe/Berlin + + + bdemers + Brian Demers + bdemers@apache.org + Sonatype + + Committer + + -5 + + + bellingard + Fabrice Bellingard + + Committer + + + + bentmann + Benjamin Bentmann + bentmann@apache.org + Sonatype + + Committer + + +1 + + + chrisgwarp + Chris Graham + chrisgwarp@apache.org + + Committer + + Australia/Melbourne + + + dantran + Dan Tran + dantran@apache.org + + Committer + + -8 + + + dbradicich + Damian Bradicich + dbradicich@apache.org + Sonatype + + Committer + + -5 + + + brett + Brett Porter + brett@apache.org + ASF + + Committer + + +10 + + + dfabulich + Daniel Fabulich + dfabulich@apache.org + + Committer + + -8 + + + eolivelli + Enrico Olivelli + eolivelli@apache.org + Diennea + + Committer + + Europe/Rome + + + fgiust + Fabrizio Giustina + fgiust@apache.org + openmind + + Committer + + +1 + + + godin + Evgeny Mandrikov + godin@apache.org + SonarSource + + Committer + + +3 + + + handyande + Andrew Williams + handyande@apache.org + + Committer + + 0 + + + imod + Dominik Bartholdi + imod@apache.org + + Committer + + Europe/Zurich + + + jjensen + Jeff Jensen + + Committer + + + + ltheussl + Lukas Theussl + ltheussl@apache.org + + Committer + + +1 + + + markh + Mark Hobson + markh@apache.org + + Committer + + 0 + + + martinkanters + Martin Kanters + martinkanters@apache.org + JPoint + + Committer + + Europe/Amsterdam + + + mauro + Mauro Talevi + + Committer + + + + mfriedenhagen + Mirko Friedenhagen + mfriedenhagen@apache.org + + Committer + + +1 + + + mmoser + Manfred Moser + mmoser@apache.org + + Committer + + -8 + + + nicolas + Nicolas de Loof + + Committer + + + + oching + Maria Odea B. Ching + + Committer + + + + pgier + Paul Gier + pgier@apache.org + Red Hat + + Committer + + -6 + + + ptahchiev + Petar Tahchiev + ptahchiev@apache.org + + Committer + + +2 + + + rafale + Raphaël Piéroni + rafale@apache.org + Dexem + + Committer + + +1 + + + schulte + Christian Schulte + schulte@apache.org + + Committer + + Europe/Berlin + + + snicoll + Stephane Nicoll + snicoll@apache.org + + Committer + + +1 + + + simonetripodi + Simone Tripodi + simonetripodi@apache.org + + Committer + + +1 + + + sor + Christian Stein + sor@apache.org + + Committer + + Europe/Berlin + + + tchemit + Tony Chemit + tchemit@apache.org + CodeLutin + + Committer + + Europe/Paris + + + vmassol + Vincent Massol + vmassol@apache.org + ASF + + Committer + + +1 + + + elharo + Elliotte Rusty Harold + elharo@apache.org + + Committer + + America/New_York + + + + + agudian + Andreas Gudian + agudian@apache.org + + Emeritus + + Europe/Berlin + + + aramirez + Allan Q. Ramirez + + Emeritus + + + + bayard + Henri Yandell + + Emeritus + + + + carlos + Carlos Sanchez + carlos@apache.org + ASF + + Emeritus + + +1 + + + chrisjs + Chris Stevenson + + Emeritus + + + + dblevins + David Blevins + + Emeritus + + + + dlr + Daniel Rall + + Emeritus + + + + epunzalan + Edwin Punzalan + epunzalan@apache.org + + Emeritus + + -8 + + + felipeal + Felipe Leme + + Emeritus + + + + jdcasey + John Casey + jdcasey@apache.org + ASF + + Emeritus + + -6 + + + jmcconnell + Jesse McConnell + jmcconnell@apache.org + ASF + + Emeritus + + -6 + + + joakime + Joakim Erdfelt + joakime@apache.org + ASF + + Emeritus + + -5 + + + jruiz + Johnny Ruiz III + jruiz@apache.org + + Emeritus + + + + jstrachan + James Strachan + + Emeritus + + + + jtolentino + Ernesto Tolentino Jr. + jtolentino@apache.org + ASF + + Emeritus + + +8 + + + kenney + Kenney Westerhof + kenney@apache.org + Neonics + + Emeritus + + +1 + + + mperham + Mike Perham + mperham@gmail.com + IBM + + Emeritus + + -6 + + + ogusakov + Oleg Gusakov + + Emeritus + + + + pschneider + Patrick Schneider + pschneider@gmail.com + + Emeritus + + -6 + + + rinku + Rahul Thakur + + Emeritus + + + + shinobu + Shinobu Kuwai + + Emeritus + + + + smorgrav + Torbjorn Eikli Smorgrav + + Emeritus + + + + trygvis + Trygve Laugstol + trygvis@apache.org + ASF + + Emeritus + + +1 + + + wsmoak + Wendy Smoak + wsmoak@apache.org + + Emeritus + + -7 + + + + + + Maven User List + mailto:users-subscribe@maven.apache.org + mailto:users-unsubscribe@maven.apache.org + mailto:users@maven.apache.org + https://lists.apache.org/list.html?users@maven.apache.org + + https://mail-archives.apache.org/mod_mbox/maven-users + https://www.mail-archive.com/users@maven.apache.org/ + + + + Maven Developer List + mailto:dev-subscribe@maven.apache.org + mailto:dev-unsubscribe@maven.apache.org + mailto:dev@maven.apache.org + https://lists.apache.org/list.html?dev@maven.apache.org + + https://mail-archives.apache.org/mod_mbox/maven-dev + https://www.mail-archive.com/dev@maven.apache.org/ + + + + Maven Issues List + mailto:issues-subscribe@maven.apache.org + mailto:issues-unsubscribe@maven.apache.org + https://lists.apache.org/list.html?issues@maven.apache.org + + https://mail-archives.apache.org/mod_mbox/maven-issues/ + https://www.mail-archive.com/issues@maven.apache.org + + + + Maven Commits List + mailto:commits-subscribe@maven.apache.org + mailto:commits-unsubscribe@maven.apache.org + https://lists.apache.org/list.html?commits@maven.apache.org + + https://mail-archives.apache.org/mod_mbox/maven-commits/ + https://www.mail-archive.com/commits@maven.apache.org + + + + Maven Announcements List + mailto:announce-subscribe@maven.apache.org + mailto:announce-unsubscribe@maven.apache.org + announce@maven.apache.org + https://lists.apache.org/list.html?announce@maven.apache.org + + https://mail-archives.apache.org/mod_mbox/maven-announce/ + https://www.mail-archive.com/announce@maven.apache.org + + + + Maven Notifications List + mailto:notifications-subscribe@maven.apache.org + mailto:notifications-unsubscribe@maven.apache.org + https://lists.apache.org/list.html?notifications@maven.apache.org + + https://mail-archives.apache.org/mod_mbox/maven-notifications/ + https://www.mail-archive.com/notifications@maven.apache.org + + + + + + maven-extensions + maven-plugins + maven-shared-components + maven-skins + doxia-tools + + + + scm:git:https://gitbox.apache.org/repos/asf/maven-parent.git + scm:git:https://gitbox.apache.org/repos/asf/maven-parent.git + maven-parent-41 + https://github.com/apache/maven-parent/tree/${project.scm.tag} + + + + Jenkins + https://ci-maven.apache.org/job/Maven/job/maven-box/ + + + mail + +
notifications@maven.apache.org
+
+
+
+
+ + + apache.website + scm:svn:https://svn.apache.org/repos/asf/maven/website/components/${maven.site.path} + + + + + 8 + 1.${javaVersion} + 1.${javaVersion} + https://builds.apache.org/analysis/ + ${user.home}/maven-sites + + ../.. + true + 0.9.0.M2 + 4.0.0 + + 3.0.0 + 1.11.2 + + ParameterNumber,MethodLength,FileLength + 2023-11-08T22:48:46Z + + + + + + + org.eclipse.sisu + org.eclipse.sisu.inject + ${version.sisu-maven-plugin} + + + org.eclipse.sisu + org.eclipse.sisu.plexus + ${version.sisu-maven-plugin} + + + org.codehaus.plexus + plexus-utils + ${version.plexus-utils} + + + org.codehaus.plexus + plexus-xml + ${version.plexus-xml} + + + + + + + + + false + + apache.snapshots + Apache Snapshot Repository + https://repository.apache.org/snapshots + + + + + + + + org.eclipse.sisu + sisu-maven-plugin + ${version.sisu-maven-plugin} + + + index-project + + main-index + test-index + + + + + + org.apache.maven.plugins + maven-plugin-plugin + + + java-annotations + + + + + org.codehaus.modello + modello-maven-plugin + 2.1.2 + + + + org.apache.maven.plugins + maven-site-plugin + + + scm:svn:https://svn.apache.org/repos/asf/maven/website/components/${maven.site.path} + + + + org.apache.maven.plugins + maven-scm-publish-plugin + + ${maven.site.cache}/${maven.site.path} + apache.releases.https + true + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + config/maven_checks_nocodestyle.xml + + + src/main/java + + + src/test/java + + + + + + org.apache.maven.shared + maven-shared-resources + 5 + + + + + org.apache.maven.plugins + maven-jxr-plugin + 3.3.1 + + + org.apache.maven.plugins + maven-pmd-plugin + 3.21.2 + + ${maven.compiler.target} + + rulesets/maven.xml + + + ${project.build.directory}/generated-sources/modello + ${project.build.directory}/generated-sources/plugin + + + + + org.apache.maven.plugins + maven-release-plugin + + true + + + + org.apache.maven.plugins + maven-toolchains-plugin + 3.1.0 + + + org.codehaus.mojo + taglist-maven-plugin + 3.0.0 + + + org.apache.maven.plugins + maven-javadoc-plugin + + true + true + en + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + true + + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + true + + + + + org.apache.maven.plugins + maven-invoker-plugin + + ${invoker.streamLogsOnFailures} + + true + + + + + org.apache.maven.plugins + maven-enforcer-plugin + + + org.codehaus.mojo + extra-enforcer-rules + 1.7.0 + + + + + enforce-bytecode-version + + enforce + + + + + ${maven.compiler.target} + + + true + + + + + + com.diffplug.spotless + spotless-maven-plugin + 2.40.0 + + + + + + 2.38.0 + + + + config/maven-eclipse-importorder.txt + + + config/maven-header-plain.txt + + + + + false + + true + + + + true + + + + + org.apache.maven.shared + maven-shared-resources + 5 + + + + + + ${spotless.action} + + process-sources + + + + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + + checkstyle-check + + check + + process-sources + + + + + org.apache.maven.plugins + maven-enforcer-plugin + + + org.apache.rat + apache-rat-plugin + + + .java-version + + .repository/** + + .maven/spy.log + + dependency-reduced-pom.xml + + .asf.yaml + + + + + rat-check + + check + + + process-resources + + + + + + + + + + org.apache.maven.plugins + maven-project-info-reports-plugin + + + + index + summary + dependency-info + modules + team + scm + issue-management + mailing-lists + dependency-management + dependencies + dependency-convergence + ci-management + plugin-management + plugins + distribution-management + + + + + + + + + + java11+ + + [11,) + + + + + + com.diffplug.spotless + spotless-maven-plugin + + + + + + apache-release + + + + org.cyclonedx + cyclonedx-maven-plugin + 2.7.10 + + + + makeAggregateBom + + package + + + + + + + + format-check + + + !format + + + + check + + + + format + + + format + + + + apply + + + + + drop-legacy-dependencies + + + true + + + + + org.apache.maven.plugins + maven-enforcer-plugin + + + drop-legacy-dependencies + + enforce + + + + + + + org.codehaus.plexus:plexus-container-default + + org.sonatype.sisu:sisu-inject-bean + org.sonatype.sisu:sisu-inject-plexus + + org.sonatype.aether:* + + org.sonatype.plexus:* + + org.apache.maven:maven-plugin-api:[,3.2.5) + org.apache.maven:maven-core:[,3.2.5) + org.apache.maven:maven-compat:[,3.2.5) + + + + org.sonatype.plexus:plexus-build-api + + org.sonatype.plexus:plexus-sec-dispatcher + org.sonatype.plexus:plexus-cipher + + + + ${drop-legacy-dependencies.include} + + + + + + + + + jdk-toolchain + + + + org.apache.maven.plugins + maven-toolchains-plugin + + + + ${maven.compiler.target} + + + + + + + toolchain + + + + + + + + + quality-checks + + + quality-checks + true + + + + + + org.apache.maven.plugins + maven-pmd-plugin + + + cpd-check + + cpd-check + + verify + + + + + + + + reporting + + + + org.apache.maven.plugins + maven-project-info-reports-plugin + + + org.apache.maven.plugins + maven-surefire-report-plugin + + false + false + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + + default + + checkstyle + + + + + + org.apache.maven.plugins + maven-pmd-plugin + + + default + + cpd + pmd + + + + + + org.apache.maven.plugins + maven-jxr-plugin + + + default + + jxr + test-jxr + + + + + + + org.codehaus.mojo + taglist-maven-plugin + + + + + FIXME Work + + + fixme + ignoreCase + + + @fixme + ignoreCase + + + + + Todo Work + + + todo + ignoreCase + + + @todo + ignoreCase + + + + + Deprecated Work + + + @deprecated + ignoreCase + + + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + default + + javadoc + + + + + + + + +
diff --git a/.gradle-user/caches/modules-2/files-2.1/org.apache.maven/maven-xml-impl/4.0.0-alpha-9/1ce26ef01fb26c663073fa6dcef50bb2dbcc170a/maven-xml-impl-4.0.0-alpha-9.jar b/.gradle-user/caches/modules-2/files-2.1/org.apache.maven/maven-xml-impl/4.0.0-alpha-9/1ce26ef01fb26c663073fa6dcef50bb2dbcc170a/maven-xml-impl-4.0.0-alpha-9.jar new file mode 100644 index 0000000..fd844a0 Binary files /dev/null and b/.gradle-user/caches/modules-2/files-2.1/org.apache.maven/maven-xml-impl/4.0.0-alpha-9/1ce26ef01fb26c663073fa6dcef50bb2dbcc170a/maven-xml-impl-4.0.0-alpha-9.jar differ diff --git a/.gradle-user/caches/modules-2/files-2.1/org.apache.maven/maven-xml-impl/4.0.0-alpha-9/2f3b06e474211294a35b009179753b5ff9e3956c/maven-xml-impl-4.0.0-alpha-9.pom b/.gradle-user/caches/modules-2/files-2.1/org.apache.maven/maven-xml-impl/4.0.0-alpha-9/2f3b06e474211294a35b009179753b5ff9e3956c/maven-xml-impl-4.0.0-alpha-9.pom new file mode 100644 index 0000000..68526c5 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.apache.maven/maven-xml-impl/4.0.0-alpha-9/2f3b06e474211294a35b009179753b5ff9e3956c/maven-xml-impl-4.0.0-alpha-9.pom @@ -0,0 +1,66 @@ + + + + 4.0.0 + + org.apache.maven + maven + 4.0.0-alpha-9 + + + maven-xml-impl + Implementation of Maven API XML + Provides the implementation classes for the Maven API XML + + + + org.apache.maven + maven-api-xml + 4.0.0-alpha-9 + + + org.eclipse.sisu + org.eclipse.sisu.plexus + + + org.codehaus.plexus + plexus-utils + + + + + com.fasterxml.woodstox + woodstox-core + + + org.codehaus.plexus + plexus-xml + ${plexusXmlVersion} + provided + + + org.apache.maven + maven-xml-impl + + + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/org.apache.maven/maven/4.0.0-alpha-9/9084407bfaf8a8a500bfc8713dbac7182f72c7f/maven-4.0.0-alpha-9.pom b/.gradle-user/caches/modules-2/files-2.1/org.apache.maven/maven/4.0.0-alpha-9/9084407bfaf8a8a500bfc8713dbac7182f72c7f/maven-4.0.0-alpha-9.pom new file mode 100644 index 0000000..4620e97 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.apache.maven/maven/4.0.0-alpha-9/9084407bfaf8a8a500bfc8713dbac7182f72c7f/maven-4.0.0-alpha-9.pom @@ -0,0 +1,795 @@ + + + + 4.0.0 + + + org.apache.maven + maven-parent + + 41 + + + + maven + 4.0.0-alpha-9 + pom + + Apache Maven + Maven is a software build management and + comprehension tool. Based on the concept of a project object model: + builds, dependency management, documentation creation, site + publication, and distribution publication are all controlled from + the declarative file. Maven can be extended by plugins to utilise a + number of other development tools for reporting or the build + process. + https://maven.apache.org/ref/${project.version}/ + 2001 + + + + Stuart McCulloch + + + Christian Schulte (MNG-2199) + + + Christopher Tubbs (MNG-4226) + + + Konstantin Perikov (MNG-4565) + + + Sébastian Le Merdy (MNG-5613) + + + Mark Ingram (MNG-5639) + + + Phil Pratt-Szeliga (MNG-5645) + + + Florencia Tarditti (PR 41) + + + Anton Tanasenko + + + Joseph Walton (MNG-5297) + + + Fabiano Cipriano de Oliveira (MNG-6261) + + + Mike Mol (MNG-6665) + + + Martin Kanters + JPoint + + + Maarten Mulders + Info Support + + + Luc Klaassen (MNG-6065) + + + Wouter Aarts (MNG-6065) + + + Arturo Bernal + + + + + maven-bom + maven-plugin-api + maven-builder-support + maven-model + maven-model-builder + api + maven-xml-impl + maven-core + maven-settings + maven-settings-builder + maven-artifact + maven-resolver-provider + maven-repository-metadata + maven-slf4j-provider + maven-slf4j-wrapper + maven-embedder + maven-compat + apache-maven + + maven-toolchain-model + maven-toolchain-builder + + + + scm:git:https://gitbox.apache.org/repos/asf/maven.git + scm:git:https://gitbox.apache.org/repos/asf/maven.git + maven-4.0.0-alpha-9 + https://github.com/apache/maven/tree/${project.scm.tag} + + + jira + https://issues.apache.org/jira/browse/MNG + + + Jenkins + https://ci-maven.apache.org/job/Maven/job/maven-box/job/maven/ + + + + apache.website + scm:svn:https://svn.apache.org/repos/asf/maven/website/components/${maven.site.path} + + https://maven.apache.org/download.html + + + + 8 + true + 3.8.7 + + apache-maven + Maven + Apache Maven + ref/4-LATEST + 2023-12-08T15:04:02Z + + 9.6 + 1.14.9 + 2.0 + 2.6.0 + 1.5.0 + 2.11.0 + 6.0.0 + 32.0.1-jre + 1.0.1 + 2.2 + 2.0.1 + 2.4.1 + 1.3.2 + 5.10.1 + 1.3 + 1.2.11 + 5.7.0 + 1.26 + 1.0.0 + 4.0.1 + 2.0.0-alpha-3 + 2.0 + 0.9.0.M2 + 1.7.36 + 4.2.1 + 3.5.3 + 6.5.1 + 2.6.4 + + + + + + + + + + org.apache.maven + maven-bom + ${project.version} + pom + import + + + org.apache.maven + maven-compat + ${project.version} + + + org.apache.maven + maven-slf4j-provider + ${project.version} + + + + org.codehaus.plexus + plexus-xml + ${plexusXmlVersion} + + + com.google.inject + guice + ${guiceVersion} + classes + + + com.google.guava + guava + + + + + + com.google.guava + guava + ${guavaVersion} + + + com.google.code.findbugs + jsr305 + + + com.google.errorprone + error_prone_annotations + + + com.google.guava + failureaccess + + + com.google.guava + listenablefuture + + + com.google.j2objc + j2objc-annotations + + + org.checkerframework + checker-qual + + + + + + com.google.guava + failureaccess + ${guavafailureaccessVersion} + + + org.eclipse.sisu + org.eclipse.sisu.plexus + ${sisuVersion} + + + + javax.enterprise + cdi-api + + + + org.eclipse.sisu + org.eclipse.sisu.inject + + + + + org.eclipse.sisu + org.eclipse.sisu.inject + ${sisuVersion} + no_asm + + + jakarta.inject + jakarta.inject-api + ${jakartaInjectApiVersion} + + + org.ow2.asm + asm + ${asmVersion} + + + javax.inject + javax.inject + 1 + + + javax.annotation + javax.annotation-api + ${javaxAnnotationApiVersion} + + + org.codehaus.plexus + plexus-classworlds + ${classWorldsVersion} + + + org.codehaus.plexus + plexus-interpolation + ${plexusInterpolationVersion} + + + org.fusesource.jansi + jansi + ${jansiVersion} + + + org.slf4j + slf4j-api + ${slf4jVersion} + + + org.slf4j + slf4j-simple + ${slf4jVersion} + true + + + ch.qos.logback + logback-classic + ${logbackClassicVersion} + true + + + + org.apache.maven.wagon + wagon-provider-api + ${wagonVersion} + + + org.apache.maven.wagon + wagon-file + ${wagonVersion} + + + org.apache.maven.wagon + wagon-http + ${wagonVersion} + + + + org.apache.maven.resolver + maven-resolver-api + ${resolverVersion} + + + org.apache.maven.resolver + maven-resolver-spi + ${resolverVersion} + + + org.apache.maven.resolver + maven-resolver-impl + ${resolverVersion} + + + org.apache.maven.resolver + maven-resolver-util + ${resolverVersion} + + + org.apache.maven.resolver + maven-resolver-connector-basic + ${resolverVersion} + + + org.apache.maven.resolver + maven-resolver-transport-file + ${resolverVersion} + + + org.apache.maven.resolver + maven-resolver-transport-apache + ${resolverVersion} + + + org.apache.maven.resolver + maven-resolver-transport-jdk + ${resolverVersion} + + + org.apache.maven.resolver + maven-resolver-transport-wagon + ${resolverVersion} + + + + commons-cli + commons-cli + ${commonsCliVersion} + + + commons-io + commons-io + ${commonsIoVersion} + + + commons-jxpath + commons-jxpath + ${jxpathVersion} + + + org.codehaus.plexus + plexus-sec-dispatcher + ${securityDispatcherVersion} + + + org.codehaus.plexus + plexus-cipher + ${cipherVersion} + + + com.fasterxml.woodstox + woodstox-core + ${woodstoxVersion} + + + org.codehaus.woodstox + stax2-api + ${stax2ApiVersion} + + + org.xmlunit + xmlunit-assertj + ${xmlunitVersion} + test + + + org.xmlunit + xmlunit-core + ${xmlunitVersion} + test + + + org.xmlunit + xmlunit-matchers + ${xmlunitVersion} + test + + + org.hamcrest + hamcrest-core + ${hamcrestVersion} + test + + + org.hamcrest + hamcrest-library + ${hamcrestVersion} + test + + + org.codehaus.plexus + plexus-testing + ${plexusTestingVersion} + test + + + org.junit + junit-bom + ${junitVersion} + pom + import + + + org.mockito + mockito-bom + ${mockitoVersion} + pom + import + + + net.bytebuddy + byte-buddy + ${byteBuddyVersion} + + + + + + + + + org.junit.jupiter + junit-jupiter-api + test + + + org.hamcrest + hamcrest-core + test + + + + + + + + + + com.diffplug.spotless + spotless-maven-plugin + 2.40.0 + + + + + + 2.38.0 + + + + config/maven-eclipse-importorder.txt + + + config/maven-header-plain.txt + + + + + false + + true + + + + true + + + + + org.apache.maven.plugins + maven-release-plugin + + true + + + + org.apache.maven.plugins + maven-surefire-plugin + + -Xmx256m + + true + + + + + org.codehaus.modello + modello-maven-plugin + + + modello-site-docs + + xdoc + xsd + + pre-site + + + + + + com.github.siom79.japicmp + japicmp-maven-plugin + 0.17.2 + + + + cmp + + verify + + + + ${maven.baseline} + true + true + + true + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 3.4.0 + + + org.codehaus.mojo + buildnumber-maven-plugin + 3.2.0 + + + + + + org.apache.maven.plugins + maven-doap-plugin + 1.2 + + + The mission of the Apache Maven project is to create and maintain software + libraries that provide a widely-used project build tool, targeting mainly Java + development. Apache Maven promotes the use of dependencies via a + standardized coordinate system, binary plugins, and a standard build + lifecycle. + + + + + org.apache.rat + apache-rat-plugin + + + rat-check + false + + + **/.gitattributes + src/test/resources*/** + src/test/projects/** + src/test/remote-repo/** + **/*.odg + .asf.yaml + + src/main/appended-resources/licenses/EPL-1.0.txt + src/main/appended-resources/licenses/unrecognized-aopalliance-1.0.txt + src/main/appended-resources/licenses/unrecognized-javax.annotation-api-1.3.2.txt + + + + + + + org.apache.maven.plugins + maven-enforcer-plugin + + + ensure-no-sonatype-cipher-and-sec-dispatcher + + enforce + + validate + + + + + org.sonatype.plexus:plexus-sec-dispatcher + org.sonatype.plexus:plexus-cipher + + ensure no more org.sonatype.plexus:plexus-cipher and org.sonatype.plexus:plexus-sec-dispatcher. + + + true + + + + enforce-bytecode-version + + enforce + + + + + [11,) + + + ${maven.compiler.target} + + test + + + + true + + + + + + + + + + apache-release + + + + org.apache.maven.plugins + maven-assembly-plugin + + + source-release-assembly + + + true + + + + + + + + + reporting + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + + provisional + tf + Provisional: + + + + + + aggregate + + aggregate + + false + + + + + org.apache.maven.plugins + maven-jxr-plugin + + + aggregate + + aggregate + + false + + + + + + + + maven-repo-local + + + maven.repo.local + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + + + maven.repo.local + ${maven.repo.local} + + + + + + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/org.apache/apache/31/9009cbdad2b69835f2df9265794c8ab50cf4dce1/apache-31.pom b/.gradle-user/caches/modules-2/files-2.1/org.apache/apache/31/9009cbdad2b69835f2df9265794c8ab50cf4dce1/apache-31.pom new file mode 100644 index 0000000..8e9c6df --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.apache/apache/31/9009cbdad2b69835f2df9265794c8ab50cf4dce1/apache-31.pom @@ -0,0 +1,567 @@ + + + + + + 4.0.0 + + + org.apache + apache + 31 + pom + + The Apache Software Foundation + + The Apache Software Foundation provides support for the Apache community of open-source software projects. + The Apache projects are characterized by a collaborative, consensus based development process, an open and + pragmatic software license, and a desire to create high quality software that leads the way in its field. + We consider ourselves not simply a group of projects sharing a server, but rather a community of developers + and users. + + https://www.apache.org/ + + The Apache Software Foundation + https://www.apache.org/ + + + + Apache-2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + + Apache Announce List + announce-subscribe@apache.org + announce-unsubscribe@apache.org + announce@apache.org + https://mail-archives.apache.org/mod_mbox/www-announce/ + + + + + scm:git:https://gitbox.apache.org/repos/asf/maven-apache-parent.git + scm:git:https://gitbox.apache.org/repos/asf/maven-apache-parent.git + https://github.com/apache/maven-apache-parent/tree/${project.scm.tag} + apache-31 + + + + + apache.releases.https + ${distMgmtReleasesName} + ${distMgmtReleasesUrl} + + + apache.snapshots.https + ${distMgmtSnapshotsName} + ${distMgmtSnapshotsUrl} + + + + + Apache Release Distribution Repository + https://repository.apache.org/service/local/staging/deploy/maven2 + Apache Development Snapshot Repository + https://repository.apache.org/content/repositories/snapshots + https://www.apache.org/images/asf_logo_wide_2016.png + UTF-8 + UTF-8 + source-release + true + 3.6.3 + 1.8 + ${maven.compiler.target} + 1.7 + 3.2.2 + 3.10.2 + posix + + 1.11.2 + 2023-11-08T22:14:21Z + + 0.15 + 1.5 + 1.11 + 3.1.0 + 3.6.0 + 3.3.2 + 3.3.1 + 3.11.0 + 3.6.1 + 3.1.1 + 3.3.0 + 3.4.1 + 3.1.0 + 3.4.0 + 3.1.1 + 3.6.0 + 3.3.0 + 3.6.2 + ${maven.plugin.tools.version} + 3.4.5 + 3.0.1 + 3.1.0 + 3.3.1 + 2.0.1 + 3.2.1 + 3.5.1 + 3.12.1 + 3.3.0 + ${surefire.version} + 3.4.0 + + + + + + org.apache.maven.plugin-tools + maven-plugin-annotations + ${version.maven-plugin-tools} + + + + + + + apache.snapshots + Apache Snapshot Repository + https://repository.apache.org/snapshots + + false + + + + + + apache.snapshots + Apache Snapshot Repository + https://repository.apache.org/snapshots + + false + + + + + + + + + + org.apache.maven.plugins + maven-antrun-plugin + ${version.maven-antrun-plugin} + + + org.apache.maven.plugins + maven-assembly-plugin + ${version.maven-assembly-plugin} + + + org.apache.maven.plugins + maven-clean-plugin + ${version.maven-clean-plugin} + + + org.apache.maven.plugins + maven-checkstyle-plugin + ${version.maven-checkstyle-plugin} + + + org.apache.maven.plugins + maven-compiler-plugin + ${version.maven-compiler-plugin} + + + org.apache.maven.plugins + maven-dependency-plugin + ${version.maven-dependency-plugin} + + + org.apache.maven.plugins + maven-deploy-plugin + ${version.maven-deploy-plugin} + + + org.apache.maven.plugins + maven-ear-plugin + ${version.maven-ear-plugin} + + + org.apache.maven.plugins + maven-enforcer-plugin + ${version.maven-enforcer-plugin} + + + org.apache.maven.plugins + maven-failsafe-plugin + ${version.maven-surefire} + + + org.apache.maven.plugins + maven-gpg-plugin + ${version.maven-gpg-plugin} + + + --digest-algo=SHA512 + + + + + org.apache.maven.plugins + maven-help-plugin + ${version.maven-help-plugin} + + + org.apache.maven.plugins + maven-install-plugin + ${version.maven-install-plugin} + + + org.apache.maven.plugins + maven-invoker-plugin + ${version.maven-invoker-plugin} + + + org.apache.maven.plugins + maven-jar-plugin + ${version.maven-jar-plugin} + + + + true + true + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${version.maven-javadoc-plugin} + + true + + + + org.apache.maven.plugins + maven-plugin-plugin + ${version.maven-plugin-tools} + + + org.apache.maven.plugins + maven-plugin-report-plugin + ${version.maven-plugin-tools} + + + org.apache.maven.plugins + maven-project-info-reports-plugin + ${version.maven-project-info-reports-plugin} + + + org.eclipse.m2e:lifecycle-mapping + + + + + + org.apache.maven.plugins + maven-release-plugin + ${version.maven-release-plugin} + + false + deploy + apache-release + + + + + org.apache.maven.plugins + maven-remote-resources-plugin + ${version.maven-remote-resources-plugin} + + + org.apache.maven.plugins + maven-resources-plugin + ${version.maven-resources-plugin} + + + org.apache.maven.plugins + maven-scm-plugin + ${version.maven-scm-plugin} + + + org.apache.maven.plugins + maven-scm-publish-plugin + ${version.maven-scm-publish-plugin} + + + org.apache.maven.plugins + maven-site-plugin + ${version.maven-site-plugin} + + + org.apache.maven.plugins + maven-source-plugin + ${version.maven-source-plugin} + + + org.apache.maven.plugins + maven-surefire-plugin + ${version.maven-surefire} + + + org.apache.maven.plugins + maven-surefire-report-plugin + ${version.maven-surefire} + + + org.apache.maven.plugins + maven-war-plugin + ${version.maven-war-plugin} + + + org.apache.maven.plugins + maven-shade-plugin + ${version.maven-shade-plugin} + + + org.apache.rat + apache-rat-plugin + ${version.apache-rat-plugin} + + + + + + + org.apache.maven.plugins + maven-remote-resources-plugin + + + process-resource-bundles + + process + + + + org.apache.apache.resources:apache-jar-resource-bundle:${version.apache-resource-bundles} + + + + + + + org.apache.maven.plugins + maven-enforcer-plugin + + + enforce-maven-version + + enforce + + + + + ${minimalMavenBuildVersion} + + + + + + enforce-java-version + + enforce + + + + + ${minimalJavaBuildVersion} + + + + + + + + org.apache.maven.plugins + maven-site-plugin + + + attach-descriptor + + attach-descriptor + + + + + + + + + + + apache-release + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + org.apache.apache.resources + apache-source-release-assembly-descriptor + ${version.apache-resource-bundles} + + + + + source-release-assembly + package + + single + + + true + + ${sourceReleaseAssemblyDescriptor} + + ${assembly.tarLongFileMode} + + + + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar-no-fork + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + attach-javadocs + + jar + + + + + + + net.nicoulaj.maven.plugins + checksum-maven-plugin + ${version.checksum-maven-plugin} + + + source-release-checksum + + artifacts + + + post-integration-test + + + SHA-512 + + + source-release + true + false + + true + + + + + + + org.apache.maven.plugins + maven-gpg-plugin + + + sign-release-artifacts + + sign + + + + + + + + + + only-eclipse + + + m2e.version + + + + + + + + org.eclipse.m2e + lifecycle-mapping + 1.0.0 + + + + + + + org.apache.maven.plugins + maven-remote-resources-plugin + [0,) + + process + + + + + + + + + + + + + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/org.apache/apache/33/f7b7b5a9e84395f17d7e6a136e5bfc4b9973566d/apache-33.pom b/.gradle-user/caches/modules-2/files-2.1/org.apache/apache/33/f7b7b5a9e84395f17d7e6a136e5bfc4b9973566d/apache-33.pom new file mode 100644 index 0000000..b03121d --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.apache/apache/33/f7b7b5a9e84395f17d7e6a136e5bfc4b9973566d/apache-33.pom @@ -0,0 +1,582 @@ + + + + + + 4.0.0 + + + org.apache + apache + 33 + pom + + The Apache Software Foundation + + The Apache Software Foundation provides support for the Apache community of open-source software projects. + The Apache projects are characterized by a collaborative, consensus based development process, an open and + pragmatic software license, and a desire to create high quality software that leads the way in its field. + We consider ourselves not simply a group of projects sharing a server, but rather a community of developers + and users. + + https://www.apache.org/ + + The Apache Software Foundation + https://www.apache.org/ + + + + Apache-2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + + Apache Announce List + announce-subscribe@apache.org + announce-unsubscribe@apache.org + announce@apache.org + https://mail-archives.apache.org/mod_mbox/www-announce/ + + + + + docs + + + + scm:git:https://gitbox.apache.org/repos/asf/maven-apache-parent.git + scm:git:https://gitbox.apache.org/repos/asf/maven-apache-parent.git + https://github.com/apache/maven-apache-parent/tree/${project.scm.tag} + apache-33 + + + + + ${distMgmtReleasesId} + ${distMgmtReleasesName} + ${distMgmtReleasesUrl} + + + ${distMgmtSnapshotsId} + ${distMgmtSnapshotsName} + ${distMgmtSnapshotsUrl} + + + + + apache.releases.https + Apache Release Distribution Repository + https://repository.apache.org/service/local/staging/deploy/maven2 + apache.snapshots.https + Apache Development Snapshot Repository + https://repository.apache.org/content/repositories/snapshots + https://www.apache.org/images/asf_logo_wide_2016.png + UTF-8 + UTF-8 + source-release + true + 3.6.3 + 1.8 + ${maven.compiler.target} + 7 + 3.3.0 + posix + + 2024-07-04T18:52:46Z + + 0.16.1 + 1.5 + 1.11 + 3.1.0 + 3.7.1 + 3.4.0 + 3.4.0 + 3.13.0 + 3.7.1 + 3.1.2 + 3.3.0 + 3.5.0 + 1.12.0 + 3.2.4 + 3.4.1 + 3.1.2 + 3.7.0 + 3.4.2 + 3.7.0 + 3.13.1 + 3.6.1 + 3.1.0 + 3.2.0 + 3.3.1 + 2.1.0 + 3.3.0 + 3.6.0 + 3.12.1 + 3.3.1 + ${surefire.version} + 3.4.0 + + + + + + org.apache.maven.plugin-tools + maven-plugin-annotations + ${version.maven-plugin-tools} + + + + + + + apache.snapshots + Apache Snapshot Repository + https://repository.apache.org/snapshots + + false + + + + + + apache.snapshots + Apache Snapshot Repository + https://repository.apache.org/snapshots + + false + + + + + + + + + + org.apache.maven.plugins + maven-antrun-plugin + ${version.maven-antrun-plugin} + + + org.apache.maven.plugins + maven-assembly-plugin + ${version.maven-assembly-plugin} + + + org.apache.maven.plugins + maven-clean-plugin + ${version.maven-clean-plugin} + + + org.apache.maven.plugins + maven-checkstyle-plugin + ${version.maven-checkstyle-plugin} + + + org.apache.maven.plugins + maven-compiler-plugin + ${version.maven-compiler-plugin} + + + org.apache.maven.plugins + maven-dependency-plugin + ${version.maven-dependency-plugin} + + + org.apache.maven.plugins + maven-deploy-plugin + ${version.maven-deploy-plugin} + + + org.apache.maven.plugins + maven-ear-plugin + ${version.maven-ear-plugin} + + + org.apache.maven.plugins + maven-enforcer-plugin + ${version.maven-enforcer-plugin} + + + org.apache.maven.plugins + maven-failsafe-plugin + ${version.maven-surefire} + + + org.apache.maven.plugins + maven-gpg-plugin + ${version.maven-gpg-plugin} + + + --digest-algo=SHA512 + + + + + org.apache.maven.plugins + maven-help-plugin + ${version.maven-help-plugin} + + + org.apache.maven.plugins + maven-install-plugin + ${version.maven-install-plugin} + + + org.apache.maven.plugins + maven-invoker-plugin + ${version.maven-invoker-plugin} + + + org.apache.maven.plugins + maven-jar-plugin + ${version.maven-jar-plugin} + + + + true + true + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${version.maven-javadoc-plugin} + + true + + + + org.apache.maven.plugins + maven-plugin-plugin + ${version.maven-plugin-tools} + + + org.apache.maven.plugins + maven-plugin-report-plugin + ${version.maven-plugin-tools} + + + org.apache.maven.plugins + maven-project-info-reports-plugin + ${version.maven-project-info-reports-plugin} + + + org.eclipse.m2e:lifecycle-mapping + + + + + + org.apache.maven.plugins + maven-release-plugin + ${version.maven-release-plugin} + + true + false + deploy + apache-release + + + + + org.apache.maven.plugins + maven-remote-resources-plugin + ${version.maven-remote-resources-plugin} + + + org.apache.maven.plugins + maven-resources-plugin + ${version.maven-resources-plugin} + + + org.apache.maven.plugins + maven-scm-plugin + ${version.maven-scm-plugin} + + + org.apache.maven.plugins + maven-scm-publish-plugin + ${version.maven-scm-publish-plugin} + + + org.apache.maven.plugins + maven-site-plugin + ${version.maven-site-plugin} + + + org.apache.maven.plugins + maven-source-plugin + ${version.maven-source-plugin} + + + org.apache.maven.plugins + maven-surefire-plugin + ${version.maven-surefire} + + + org.apache.maven.plugins + maven-surefire-report-plugin + ${version.maven-surefire} + + + org.apache.maven.plugins + maven-war-plugin + ${version.maven-war-plugin} + + + org.apache.maven.plugins + maven-shade-plugin + ${version.maven-shade-plugin} + + + org.apache.rat + apache-rat-plugin + ${version.apache-rat-plugin} + + + + + + + org.apache.maven.plugins + maven-remote-resources-plugin + + + process-resource-bundles + + process + + + + org.apache.apache.resources:apache-jar-resource-bundle:${version.apache-resource-bundles} + + + + + + + org.apache.maven.plugins + maven-enforcer-plugin + + + enforce-maven-version + + enforce + + + + + ${minimalMavenBuildVersion} + + + + + + enforce-java-version + + enforce + + + + + ${minimalJavaBuildVersion} + + + + + + + + + + org.apache.maven.plugins + maven-site-plugin + false + + true + + + + + + + + + apache-release + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + org.apache.apache.resources + apache-source-release-assembly-descriptor + ${version.apache-resource-bundles} + + + + + source-release-assembly + package + + single + + + true + + ${sourceReleaseAssemblyDescriptor} + + ${assembly.tarLongFileMode} + + + + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar-no-fork + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + attach-javadocs + + jar + + + + + + + net.nicoulaj.maven.plugins + checksum-maven-plugin + ${version.checksum-maven-plugin} + + + source-release-checksum + + artifacts + + + post-integration-test + + + SHA-512 + + + source-release + true + false + + true + + + + + + + org.apache.maven.plugins + maven-gpg-plugin + + + sign-release-artifacts + + sign + + + + + + + + + + jdk9+ + + + [9,) + + + + ${maven.compiler.target} + + + + only-eclipse + + + m2e.version + + + + + + + + org.eclipse.m2e + lifecycle-mapping + 1.0.0 + + + + + + + org.apache.maven.plugins + maven-remote-resources-plugin + [0,) + + process + + + + + + + + + + + + + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/org.checkerframework/checker-qual/3.12.0/7f3b31c801fe87a77142f4fdd07bd4cb6f28cc9b/checker-qual-3.12.0.module b/.gradle-user/caches/modules-2/files-2.1/org.checkerframework/checker-qual/3.12.0/7f3b31c801fe87a77142f4fdd07bd4cb6f28cc9b/checker-qual-3.12.0.module new file mode 100644 index 0000000..32164a0 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.checkerframework/checker-qual/3.12.0/7f3b31c801fe87a77142f4fdd07bd4cb6f28cc9b/checker-qual-3.12.0.module @@ -0,0 +1,101 @@ +{ + "formatVersion": "1.1", + "component": { + "group": "org.checkerframework", + "module": "checker-qual", + "version": "3.12.0", + "attributes": { + "org.gradle.status": "release" + } + }, + "createdBy": { + "gradle": { + "version": "6.6.1", + "buildId": "smklfgl3h5et3hv6dg43gj3eoq" + } + }, + "variants": [ + { + "name": "apiElements", + "attributes": { + "org.gradle.category": "library", + "org.gradle.dependency.bundling": "external", + "org.gradle.jvm.version": 8, + "org.gradle.libraryelements": "jar", + "org.gradle.usage": "java-api" + }, + "files": [ + { + "name": "checker-qual-3.12.0.jar", + "url": "checker-qual-3.12.0.jar", + "size": 208835, + "sha512": "ff20c424e130c31c30b4f4f5b4374f8f98f94ddae2b123f3c213f147be6b3de57854ee5651b02dd97d352c1c1df2a8bfeef73d5307a71372f46a6002eab24d78", + "sha256": "ff10785ac2a357ec5de9c293cb982a2cbb605c0309ea4cc1cb9b9bc6dbe7f3cb", + "sha1": "d5692f0526415fcc6de94bb5bfbd3afd9dd3b3e5", + "md5": "ab1ae0e2f2f63601597a5a96fca8a54f" + } + ] + }, + { + "name": "runtimeElements", + "attributes": { + "org.gradle.category": "library", + "org.gradle.dependency.bundling": "external", + "org.gradle.jvm.version": 8, + "org.gradle.libraryelements": "jar", + "org.gradle.usage": "java-runtime" + }, + "files": [ + { + "name": "checker-qual-3.12.0.jar", + "url": "checker-qual-3.12.0.jar", + "size": 208835, + "sha512": "ff20c424e130c31c30b4f4f5b4374f8f98f94ddae2b123f3c213f147be6b3de57854ee5651b02dd97d352c1c1df2a8bfeef73d5307a71372f46a6002eab24d78", + "sha256": "ff10785ac2a357ec5de9c293cb982a2cbb605c0309ea4cc1cb9b9bc6dbe7f3cb", + "sha1": "d5692f0526415fcc6de94bb5bfbd3afd9dd3b3e5", + "md5": "ab1ae0e2f2f63601597a5a96fca8a54f" + } + ] + }, + { + "name": "javadocElements", + "attributes": { + "org.gradle.category": "documentation", + "org.gradle.dependency.bundling": "external", + "org.gradle.docstype": "javadoc", + "org.gradle.usage": "java-runtime" + }, + "files": [ + { + "name": "checker-qual-3.12.0-javadoc.jar", + "url": "checker-qual-3.12.0-javadoc.jar", + "size": 900991, + "sha512": "86b792d35ea092e69527e68c9c28d3ad09b9227f18922a3109f4acdbc8190014446660bf604a77c3abf5f64c0e5d764b7245f645f02c0f95a398e0351feaa786", + "sha256": "760ed10dff3a7fdf617e2591949e7831995a959a132572a63529c6562800aa89", + "sha1": "fd7626f12ccbe6f5557a00cd13c7d399789723cf", + "md5": "eb6316611d758839017a97930ab4c02f" + } + ] + }, + { + "name": "sourcesElements", + "attributes": { + "org.gradle.category": "documentation", + "org.gradle.dependency.bundling": "external", + "org.gradle.docstype": "sources", + "org.gradle.usage": "java-runtime" + }, + "files": [ + { + "name": "checker-qual-3.12.0-sources.jar", + "url": "checker-qual-3.12.0-sources.jar", + "size": 237067, + "sha512": "fd004718c3230332f468602787ef99b6089df20f78df18d12ffcb20145b0c37f2e01a03212661403eeb7c74e9c221c328980148d01df364f23680aa4d0bcbb0e", + "sha256": "fd99a45195ed893803624d1030387056a96601013f5e61ccabd79abb4ddfa876", + "sha1": "10dacb8b36398debceca36cd0db5f3316967f80e", + "md5": "ccde79e4218681aef564a5ec2f87cd60" + } + ] + } + ] +} diff --git a/.gradle-user/caches/modules-2/files-2.1/org.checkerframework/checker-qual/3.12.0/d5692f0526415fcc6de94bb5bfbd3afd9dd3b3e5/checker-qual-3.12.0.jar b/.gradle-user/caches/modules-2/files-2.1/org.checkerframework/checker-qual/3.12.0/d5692f0526415fcc6de94bb5bfbd3afd9dd3b3e5/checker-qual-3.12.0.jar new file mode 100644 index 0000000..e9eed80 Binary files /dev/null and b/.gradle-user/caches/modules-2/files-2.1/org.checkerframework/checker-qual/3.12.0/d5692f0526415fcc6de94bb5bfbd3afd9dd3b3e5/checker-qual-3.12.0.jar differ diff --git a/.gradle-user/caches/modules-2/files-2.1/org.checkerframework/checker-qual/3.12.0/fb8dca6f40fcb30f7b89de269940bf3316fb9845/checker-qual-3.12.0.pom b/.gradle-user/caches/modules-2/files-2.1/org.checkerframework/checker-qual/3.12.0/fb8dca6f40fcb30f7b89de269940bf3316fb9845/checker-qual-3.12.0.pom new file mode 100644 index 0000000..baf6fcc --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.checkerframework/checker-qual/3.12.0/fb8dca6f40fcb30f7b89de269940bf3316fb9845/checker-qual-3.12.0.pom @@ -0,0 +1,47 @@ + + + + + + + + 4.0.0 + org.checkerframework + checker-qual + 3.12.0 + Checker Qual + checker-qual contains annotations (type qualifiers) that a programmer +writes to specify Java code for type-checking by the Checker Framework. + + https://checkerframework.org + + + The MIT License + http://opensource.org/licenses/MIT + repo + + + + + mernst + Michael Ernst + mernst@cs.washington.edu + https://homes.cs.washington.edu/~mernst/ + University of Washington + https://www.cs.washington.edu/ + + + smillst + Suzanne Millstein + smillst@cs.washington.edu + University of Washington + https://www.cs.washington.edu/ + + + + scm:git:git://github.com/typetools/checker-framework.git + scm:git:ssh://git@github.com/typetools/checker-framework.git + https://github.com/typetools/checker-framework.git + + diff --git a/.gradle-user/caches/modules-2/files-2.1/org.codehaus.plexus/plexus-utils/4.0.2/90bdd43cc00d6fc5509e53bf09268e33708c5e8b/plexus-utils-4.0.2.pom b/.gradle-user/caches/modules-2/files-2.1/org.codehaus.plexus/plexus-utils/4.0.2/90bdd43cc00d6fc5509e53bf09268e33708c5e8b/plexus-utils-4.0.2.pom new file mode 100644 index 0000000..17a69f9 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.codehaus.plexus/plexus-utils/4.0.2/90bdd43cc00d6fc5509e53bf09268e33708c5e8b/plexus-utils-4.0.2.pom @@ -0,0 +1,443 @@ + + + 4.0.0 + org.codehaus.plexus + plexus-utils + 4.0.2 + Plexus Common Utilities + A collection of various utility classes to ease working with strings, files, command lines and + more. + https://codehaus-plexus.github.io/plexus-utils/ + 2001 + + Codehaus Plexus + https://codehaus-plexus.github.io/ + + + + Apache License, Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + jvanzyl + Jason van Zyl + jason@maven.org + + Developer + Release Manager + + + + kaz + Pete Kazmier + + + + Developer + + + + jtaylor + James Taylor + james@jamestaylor.org + + + Developer + + + + dandiep + Dan Diephouse + dan@envoisolutions.com + Envoi solutions + + Developer + + + + kasper + Kasper Nielsen + apache@kav.dk + + + Developer + + + + bwalding + Ben Walding + bwalding@codehaus.org + Walding Consulting Services + + Developer + + + + mhw + Mark Wilkinson + mhw@kremvax.net + + Developer + + + + michal + Michal Maczka + mmaczka@interia.pl + + Developer + + + + evenisse + Emmanuel Venisse + evenisse@codehaus.org + + Developer + + + + trygvis + Trygve Laugstøl + trygvis@codehaus.org + + Developer + + + + kenney + Kenney Westerhof + kenney@codehaus.org + + Developer + + + + carlos + Carlos Sanchez + carlos@codehaus.org + + Developer + + + + brett + Brett Porter + brett@codehaus.org + + Developer + + + + jdcasey + John Casey + jdcasey@codehaus.org + + Developer + + + + handyande + Andrew Williams + andy@handyande.co.uk + + Developer + + + + rahul + Rahul Thakur + rahul.thakur.xdev@gmail.com + + Developer + + + + joakime + Joakim Erdfelt + joakim@erdfelt.com + + Developer + + + + olamy + Olivier Lamy + olamy@codehaus.org + + Developer + + + + hboutemy + Hervé Boutemy + hboutemy@apache.org + + Developer + + + + oleg + Oleg Gusakov + olegy@codehaus.org + + Developer + + + + vsiveton + Vincent Siveton + vsiveton@codehaus.org + + Developer + + + + krosenvold + Kristian Rosenvold + krosenvold@apache.org + + Developer + + + + agudian + Andreas Gudian + agudian@apache.org + + Developer + + + + khmarbaise + Karl Heinz Marbaise + khmarbaise@apache.org + + Developer + + + + michael-o + Michael Osipov + 1983-01-06@gmx.net + + Developer + + + + belingueres + Gabriel Belingueres + belingueres@gmail.com + + Developer + + + + kwin + Konrad Windszus + kwin@apache.org + + Developer + + + + sjaranowski + Slawomir Jaranowski + sjaranowski@apache.org + + Developer + + + + slachiewicz + Sylwester Lachiewicz + slachiewicz@apache.org + ASF + + Developer + + + + gnodet + Guillaume Nodet + gnodet@apache.org + ASF + + Developer + + + + + + Plexus and MojoHaus Development List + mojohaus-dev+subscribe@googlegroups.com + mojohaus-dev+unsubscribe@googlegroups.com + mojohaus-dev@googlegroups.com + https://groups.google.com/forum/#!forum/mojohaus-dev + + + + scm:git:https://github.com/codehaus-plexus/plexus-utils.git + scm:git:https://github.com/codehaus-plexus/plexus-utils.git + plexus-utils-4.0.2 + https://github.com/codehaus-plexus/plexus-utils/tree/plexus-utils-4.0.2/ + + + github + https://github.com/codehaus-plexus/plexus-utils/issues + + + + plexus-releases + Plexus Release Repository + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + + plexus-snapshots + Plexus Snapshot Repository + https://oss.sonatype.org/content/repositories/plexus-snapshots + + + github:gh-pages + scm:git:https://github.com/codehaus-plexus/plexus-utils.git + + + + + + org.apache.maven.plugin-tools + maven-plugin-annotations + 3.13.0 + provided + + + org.junit.jupiter + junit-jupiter + 5.10.2 + + + org.junit.jupiter + junit-jupiter-api + 5.10.2 + + + org.junit.jupiter + junit-jupiter-engine + 5.10.2 + + + org.junit.jupiter + junit-jupiter-migrationsupport + 5.10.2 + + + org.junit.jupiter + junit-jupiter-params + 5.10.2 + + + org.junit.platform + junit-platform-commons + 1.10.2 + + + org.junit.platform + junit-platform-console + 1.10.2 + + + org.junit.platform + junit-platform-engine + 1.10.2 + + + org.junit.platform + junit-platform-jfr + 1.10.2 + + + org.junit.platform + junit-platform-launcher + 1.10.2 + + + org.junit.platform + junit-platform-reporting + 1.10.2 + + + org.junit.platform + junit-platform-runner + 1.10.2 + + + org.junit.platform + junit-platform-suite + 1.10.2 + + + org.junit.platform + junit-platform-suite-api + 1.10.2 + + + org.junit.platform + junit-platform-suite-commons + 1.10.2 + + + org.junit.platform + junit-platform-suite-engine + 1.10.2 + + + org.junit.platform + junit-platform-testkit + 1.10.2 + + + org.junit.vintage + junit-vintage-engine + 5.10.2 + + + + + + org.codehaus.plexus + plexus-xml + 3.0.1 + compile + true + + + org.junit.jupiter + junit-jupiter-api + 5.10.2 + test + + + + + jdk9+ + + [9,) + + + + jdk10+ + + [10,) + + + + jdk11+ + + [11,) + + + + \ No newline at end of file diff --git a/.gradle-user/caches/modules-2/files-2.1/org.codehaus.plexus/plexus-utils/4.0.2/9526a9548b302572f23337fcc217fb4cc713b9c3/plexus-utils-4.0.2.jar b/.gradle-user/caches/modules-2/files-2.1/org.codehaus.plexus/plexus-utils/4.0.2/9526a9548b302572f23337fcc217fb4cc713b9c3/plexus-utils-4.0.2.jar new file mode 100644 index 0000000..c53f30e Binary files /dev/null and b/.gradle-user/caches/modules-2/files-2.1/org.codehaus.plexus/plexus-utils/4.0.2/9526a9548b302572f23337fcc217fb4cc713b9c3/plexus-utils-4.0.2.jar differ diff --git a/.gradle-user/caches/modules-2/files-2.1/org.codehaus.plexus/plexus-xml/4.0.4/81419c08701143a41034b410b208dc45fc7cd476/plexus-xml-4.0.4.jar b/.gradle-user/caches/modules-2/files-2.1/org.codehaus.plexus/plexus-xml/4.0.4/81419c08701143a41034b410b208dc45fc7cd476/plexus-xml-4.0.4.jar new file mode 100644 index 0000000..b7da838 Binary files /dev/null and b/.gradle-user/caches/modules-2/files-2.1/org.codehaus.plexus/plexus-xml/4.0.4/81419c08701143a41034b410b208dc45fc7cd476/plexus-xml-4.0.4.jar differ diff --git a/.gradle-user/caches/modules-2/files-2.1/org.codehaus.plexus/plexus-xml/4.0.4/d87fe69f61c18c8b498f0b905478efe8071acb8c/plexus-xml-4.0.4.pom b/.gradle-user/caches/modules-2/files-2.1/org.codehaus.plexus/plexus-xml/4.0.4/d87fe69f61c18c8b498f0b905478efe8071acb8c/plexus-xml-4.0.4.pom new file mode 100644 index 0000000..cbcddc5 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.codehaus.plexus/plexus-xml/4.0.4/d87fe69f61c18c8b498f0b905478efe8071acb8c/plexus-xml-4.0.4.pom @@ -0,0 +1,121 @@ + + + + 4.0.0 + + + org.codehaus.plexus + plexus + 18 + + + plexus-xml + 4.0.4 + + Plexus XML Utilities + A collection of various utility classes to ease working with XML. + https://codehaus-plexus.github.io/plexus-xml/ + + + scm:git:https://github.com/codehaus-plexus/plexus-xml.git + ${project.scm.connection} + plexus-xml-4.0.4 + https://github.com/codehaus-plexus/plexus-xml/tree/${project.scm.tag}/ + + + github + https://github.com/codehaus-plexus/plexus-xml/issues + + + + github:gh-pages + ${project.scm.developerConnection} + + + + + 2024-05-21T21:02:09Z + + + + + org.apache.maven + maven-xml-impl + 4.0.0-alpha-9 + + + org.eclipse.sisu + org.eclipse.sisu.plexus + + + + + org.openjdk.jmh + jmh-core + 1.37 + test + + + org.openjdk.jmh + jmh-generator-annprocess + 1.37 + test + + + org.junit.jupiter + junit-jupiter + test + + + org.codehaus.plexus + plexus-utils + 4.0.1 + test + + + + + + + org.apache.maven.plugins + maven-scm-publish-plugin + + ${project.reporting.outputDirectory} + + + + + scm-publish + + + publish-scm + + site-deploy + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + true + + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/org.codehaus.plexus/plexus/18/6dcf47484abcaaa8288f528ccbde76171eb3c155/plexus-18.pom b/.gradle-user/caches/modules-2/files-2.1/org.codehaus.plexus/plexus/18/6dcf47484abcaaa8288f528ccbde76171eb3c155/plexus-18.pom new file mode 100644 index 0000000..0794351 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.codehaus.plexus/plexus/18/6dcf47484abcaaa8288f528ccbde76171eb3c155/plexus-18.pom @@ -0,0 +1,894 @@ + + + + 4.0.0 + + org.codehaus.plexus + plexus + 18 + pom + + Plexus + The Plexus project provides a full software stack for creating and executing software projects. + https://codehaus-plexus.github.io/plexus-pom/ + 2001 + + Codehaus Plexus + https://codehaus-plexus.github.io/ + + + + Apache License, Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + + jvanzyl + Jason van Zyl + jason@maven.org + + Developer + Release Manager + + + + kaz + Pete Kazmier + + + + Developer + + + + jtaylor + James Taylor + james@jamestaylor.org + + + Developer + + + + dandiep + Dan Diephouse + dan@envoisolutions.com + Envoi solutions + + Developer + + + + kasper + Kasper Nielsen + apache@kav.dk + + + Developer + + + + bwalding + Ben Walding + bwalding@codehaus.org + Walding Consulting Services + + Developer + + + + mhw + Mark Wilkinson + mhw@kremvax.net + + Developer + + + + michal + Michal Maczka + mmaczka@interia.pl + + Developer + + + + evenisse + Emmanuel Venisse + evenisse@codehaus.org + + Developer + + + + trygvis + Trygve Laugstøl + trygvis@codehaus.org + + Developer + + + + kenney + Kenney Westerhof + kenney@codehaus.org + + Developer + + + + carlos + Carlos Sanchez + carlos@codehaus.org + + Developer + + + + brett + Brett Porter + brett@codehaus.org + + Developer + + + + jdcasey + John Casey + jdcasey@codehaus.org + + Developer + + + + handyande + Andrew Williams + andy@handyande.co.uk + + Developer + + + + rahul + Rahul Thakur + rahul.thakur.xdev@gmail.com + + Developer + + + + joakime + Joakim Erdfelt + joakim@erdfelt.com + + Developer + + + + olamy + Olivier Lamy + olamy@codehaus.org + + Developer + + + + hboutemy + Hervé Boutemy + hboutemy@apache.org + + Developer + + + + oleg + Oleg Gusakov + olegy@codehaus.org + + Developer + + + + vsiveton + Vincent Siveton + vsiveton@codehaus.org + + Developer + + + + krosenvold + Kristian Rosenvold + krosenvold@apache.org + + Developer + + + + agudian + Andreas Gudian + agudian@apache.org + + Developer + + + + khmarbaise + Karl Heinz Marbaise + khmarbaise@apache.org + + Developer + + + + michael-o + Michael Osipov + 1983-01-06@gmx.net + + Developer + + + + belingueres + Gabriel Belingueres + belingueres@gmail.com + + Developer + + + + kwin + Konrad Windszus + kwin@apache.org + + Developer + + + + sjaranowski + Slawomir Jaranowski + sjaranowski@apache.org + + Developer + + + + slachiewicz + Sylwester Lachiewicz + slachiewicz@apache.org + ASF + + Developer + + + + gnodet + Guillaume Nodet + gnodet@apache.org + ASF + + Developer + + + + + + + Plexus and MojoHaus Development List + mojohaus-dev+subscribe@googlegroups.com + mojohaus-dev+unsubscribe@googlegroups.com + mojohaus-dev@googlegroups.com + https://groups.google.com/forum/#!forum/mojohaus-dev + + + + + scm:git:https://github.com/codehaus-plexus/plexus-pom.git + ${project.scm.connection} + plexus-18 + https://github.com/codehaus-plexus/plexus-pom/tree/${project.scm.tag}/ + + + + github + https://github.com/codehaus-plexus/plexus-pom/issues + + + + + plexus-releases + Plexus Release Repository + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + + plexus-snapshots + Plexus Snapshot Repository + ${plexusDistMgmtSnapshotsUrl} + + + + github:gh-pages + ${project.scm.developerConnection} + + + + + 8 + 3.2.5 + ${javaVersion} + ${javaVersion} + + none + true + UTF-8 + https://oss.sonatype.org/content/repositories/plexus-snapshots + 2024-05-21T19:07:45Z + true + 2.43.0 + 3.13.0 + 1.12.0 + 3.2.5 + 5.10.2 + check + 0.9.0.M2 + true + + + + + + org.apache.maven.plugin-tools + maven-plugin-annotations + ${mavenPluginToolsVersion} + provided + + + org.junit + junit-bom + ${junit5Version} + pom + import + + + + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + 3.7.1 + + + org.apache.maven.plugins + maven-checkstyle-plugin + 3.3.1 + + config/maven_checks.xml + + https://raw.githubusercontent.com/codehaus-plexus/plexus-pom/plexus-11/src/main/resources/config/plexus-header.txt + + + + + org.apache.maven.shared + maven-shared-resources + 5 + + + + + org.apache.maven.plugins + maven-clean-plugin + 3.3.2 + + + org.apache.maven.plugins + maven-compiler-plugin + 3.13.0 + + ${maven.compiler.proc} + ${maven.compiler.showDeprecation} + + + + org.apache.maven.plugins + maven-deploy-plugin + 3.1.2 + + + org.apache.maven.plugins + maven-enforcer-plugin + 3.4.1 + + + org.apache.maven.plugins + maven-gpg-plugin + 3.2.4 + + + org.apache.maven.plugins + maven-install-plugin + 3.1.2 + + + org.apache.maven.plugins + maven-jar-plugin + 3.4.1 + + + + true + true + + + + + + org.apache.maven.plugins + maven-invoker-plugin + 3.6.1 + + ${invoker.streamLogsOnFailures} + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.6.3 + + true + en + + true + + + + org.apache.maven.plugins + maven-jxr-plugin + 3.3.2 + + + org.apache.maven.plugins + maven-plugin-plugin + ${mavenPluginToolsVersion} + + + default-descriptor + process-classes + + ./apidocs/ + + + + generate-helpmojo + + helpmojo + + + + + + org.apache.maven.plugins + maven-plugin-report-plugin + ${mavenPluginToolsVersion} + + + org.apache.maven.plugins + maven-pmd-plugin + 3.22.0 + + ${maven.compiler.source} + + rulesets/maven.xml + + + ${project.build.directory}/generated-sources/modello + ${project.build.directory}/generated-sources/plugin + + + + + org.apache.maven.plugins + maven-project-info-reports-plugin + 3.5.0 + + + org.apache.maven.plugins + maven-release-plugin + 3.0.1 + + deploy + plexus-release + + + + org.apache.maven.plugins + maven-resources-plugin + 3.3.1 + + + org.apache.maven.plugins + maven-scm-publish-plugin + 3.2.1 + + + ${project.scm.developerConnection} + gh-pages + + + + org.apache.maven.plugins + maven-site-plugin + 3.12.1 + + + true + + + + org.apache.maven.plugins + maven-source-plugin + 3.3.1 + + + org.apache.maven.plugins + maven-surefire-plugin + ${mavenSurefireVersion} + + + org.apache.maven.plugins + maven-surefire-report-plugin + ${mavenSurefireVersion} + + + org.apache.maven.plugins + maven-failsafe-plugin + ${mavenSurefireVersion} + + + org.codehaus.mojo + taglist-maven-plugin + 3.0.0 + + + org.eclipse.sisu + sisu-maven-plugin + ${sisuMavenPluginVersion} + + + generate-index + + main-index + test-index + + + + + + com.diffplug.spotless + spotless-maven-plugin + ${spotless-maven-plugin.version} + + + + + + + + javax,java,,\# + + + + + false + + true + + + + true + + + + + spotless-check + + ${spotless.action} + + process-sources + + + + + + + + org.apache.maven.plugins + maven-enforcer-plugin + + + org.codehaus.mojo + extra-enforcer-rules + 1.8.0 + + + + + enforce-maven-and-java-bytecode + + enforce + + + + + ${minimalMavenBuildVersion} + This project requires at least Maven ${minimalMavenBuildVersion} + + + ${maven.compiler.target} + + + + + + + + maven-site-plugin + + + attach-descriptor + + attach-descriptor + + false + + + + + + + + + + org.apache.maven.plugins + maven-project-info-reports-plugin + + + + index + summary + dependency-info + modules + licenses + team + scm + issue-management + mailing-lists + dependency-management + dependencies + dependency-convergence + ci-management + plugin-management + plugins + distribution-management + + + + + + + + + + reporting + + + + org.apache.maven.plugins + maven-project-info-reports-plugin + + + org.apache.maven.plugins + maven-surefire-report-plugin + + false + false + + + + org.apache.maven.plugins + maven-pmd-plugin + + true + + + + default + + cpd + pmd + + + + + + org.codehaus.mojo + taglist-maven-plugin + + + org.apache.maven.plugins + maven-jxr-plugin + + + default + + jxr + test-jxr + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + default + + javadoc + + + + + + + + + plexus-release + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + org.apache.apache.resources + apache-source-release-assembly-descriptor + 1.5 + + + + + source-release-assembly + + single + + package + + true + + source-release + + posix + + + + + + org.apache.maven.plugins + maven-gpg-plugin + + ${gpg.passphrase} + + + + sign-artifacts + + sign + + + + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar-no-fork + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + attach-javadocs + + jar + + + + + + + + + + java11+ + + [11,) + + + + ${javaVersion} + + config/maven_checks_nocodestyle.xml + + + + + + + com.diffplug.spotless + spotless-maven-plugin + + + org.apache.maven.plugins + maven-checkstyle-plugin + + ${checkstyle.spotless.config} + + + + + + + format-check + + + !format + + + + check + + + + format + + + format + + + + apply + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/org.codehaus.woodstox/stax2-api/4.2.1/52c4497300ff75147fade804f05351ded9e9eec/stax2-api-4.2.1.pom b/.gradle-user/caches/modules-2/files-2.1/org.codehaus.woodstox/stax2-api/4.2.1/52c4497300ff75147fade804f05351ded9e9eec/stax2-api-4.2.1.pom new file mode 100644 index 0000000..c96e0b9 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.codehaus.woodstox/stax2-api/4.2.1/52c4497300ff75147fade804f05351ded9e9eec/stax2-api-4.2.1.pom @@ -0,0 +1,192 @@ + + + 4.0.0 + + com.fasterxml + oss-parent + 38 + + org.codehaus.woodstox + stax2-api + Stax2 API + 4.2.1 + bundle + tax2 API is an extension to basic Stax 1.0 API that adds significant new functionality, such as full-featured bi-direction validation interface and high-performance Typed Access API. + + http://github.com/FasterXML/stax2-api + + fasterxml.com + http://fasterxml.com + + + + tatu + Tatu Saloranta + tatu@fasterxml.com + + + + + The BSD License + http://www.opensource.org/licenses/bsd-license.php + repo + + + + scm:git:git@github.com:FasterXML/stax2-api.git + scm:git:git@github.com:FasterXML/stax2-api.git + http://github.com/FasterXML/stax2-api + stax2-api-4.2.1 + + + + + 1.6 + 1.6 + + + org.codehaus.stax2 + + + + + + org.apache.maven.plugins + maven-release-plugin + + forked-path + + + + org.apache.maven.plugins + maven-javadoc-plugin + + 1.6 + 1.6 + UTF-8 + + https://docs.oracle.com/javase/8/docs/api/ + + + + + attach-javadocs + verify + + jar + + + + + + + org.apache.felix + maven-bundle-plugin + true + + + ${jdk.module.name} + ${project.artifactId} + fasterml.com + +javax.xml.namespace +,javax.xml.stream +,javax.xml.stream.events +,javax.xml.stream.util +,javax.xml.transform +,javax.xml.transform.dom +,org.w3c.dom + + + + + +org.codehaus.stax2 +,org.codehaus.stax2.evt +,org.codehaus.stax2.io +,org.codehaus.stax2.osgi +,org.codehaus.stax2.ri +,org.codehaus.stax2.ri.dom +,org.codehaus.stax2.ri.evt +,org.codehaus.stax2.ri.typed +,org.codehaus.stax2.typed +,org.codehaus.stax2.util +,org.codehaus.stax2.validation + + + + + + + org.moditect + moditect-maven-plugin + + + add-module-infos + package + + add-module-info + + + true + + src/moditect/module-info.java + + + + + + + + + + + moditect + + + 1.9 + 1.9 + 1.9 + 4.1.0 + + + + + org.moditect + moditect-maven-plugin + + + generate-module-info + generate-sources + + generate-module-info + + + + + + ${project.groupId} + ${project.artifactId} + + ${project.version} + + + + + + + + + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/org.codehaus.woodstox/stax2-api/4.2.1/a3f7325c52240418c2ba257b103c3c550e140c83/stax2-api-4.2.1.jar b/.gradle-user/caches/modules-2/files-2.1/org.codehaus.woodstox/stax2-api/4.2.1/a3f7325c52240418c2ba257b103c3c550e140c83/stax2-api-4.2.1.jar new file mode 100644 index 0000000..28c6a08 Binary files /dev/null and b/.gradle-user/caches/modules-2/files-2.1/org.codehaus.woodstox/stax2-api/4.2.1/a3f7325c52240418c2ba257b103c3c550e140c83/stax2-api-4.2.1.jar differ diff --git a/.gradle-user/caches/modules-2/files-2.1/org.eclipse.ee4j/project/1.0.7/b0f6c4bc691a0b694a377edc9bc4777871647253/project-1.0.7.pom b/.gradle-user/caches/modules-2/files-2.1/org.eclipse.ee4j/project/1.0.7/b0f6c4bc691a0b694a377edc9bc4777871647253/project-1.0.7.pom new file mode 100644 index 0000000..0ecdc4a --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.eclipse.ee4j/project/1.0.7/b0f6c4bc691a0b694a377edc9bc4777871647253/project-1.0.7.pom @@ -0,0 +1,332 @@ + + + + + 4.0.0 + org.eclipse.ee4j + project + 1.0.7 + pom + + EE4J Project + https://projects.eclipse.org/projects/ee4j + + Eclipse Enterprise for Java (EE4J) is an open source initiative to create standard APIs, + implementations of those APIs, and technology compatibility kits for Java runtimes + that enable development, deployment, and management of server-side and cloud-native applications. + + + + Eclipse Foundation + https://www.eclipse.org + + 2017 + + + + eclipseee4j + Eclipse EE4J Developers + Eclipse Foundation + ee4j-pmc@eclipse.org + + + + + + Eclipse Public License v. 2.0 + https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt + repo + + + GNU General Public License, version 2 with the GNU Classpath Exception + https://www.gnu.org/software/classpath/license.html + repo + + + + + GitHub Issues + https://github.com/eclipse-ee4j/ee4j/issues + + + + scm:git:git@github.com:eclipse-ee4j/ee4j.git + scm:git:git@github.com:eclipse-ee4j/ee4j.git + https://github.com/eclipse-ee4j/ee4j + + + + + Community discussions + jakarta.ee-community@eclipse.org + https://accounts.eclipse.org/mailing-list/jakarta.ee-community + https://accounts.eclipse.org/mailing-list/jakarta.ee-community + https://dev.eclipse.org/mhonarc/lists/jakarta.ee-community/ + + http://dev.eclipse.org/mhonarc/lists/jakarta.ee-community/maillist.rss + + + + PMC discussions + ee4j-pmc@eclipse.org + https://accounts.eclipse.org/mailing-list/ee4j-pmc + https://accounts.eclipse.org/mailing-list/ee4j-pmc + https://dev.eclipse.org/mhonarc/lists/ee4j-pmc/ + + http://dev.eclipse.org/mhonarc/lists/ee4j-pmc/maillist.rss + + + + + + https://jakarta.oss.sonatype.org/ + ${sonatypeOssDistMgmtNexusUrl}content/repositories/snapshots/ + ${sonatypeOssDistMgmtNexusUrl}content/repositories/staging/ + ${sonatypeOssDistMgmtNexusUrl}service/local/staging/deploy/maven2/ + UTF-8 + + + + + + + ossrh + Sonatype Nexus Snapshots + ${sonatypeOssDistMgmtSnapshotsUrl} + + + ossrh + Sonatype Nexus Releases + ${sonatypeOssDistMgmtReleasesUrl} + + + + + + + + org.apache.maven.plugins + maven-release-plugin + 2.5.3 + + forked-path + false + -Poss-release ${release.arguments} + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.8 + + ossrh + ${sonatypeOssDistMgmtNexusUrl} + false + + ${maven.deploy.skip} + + + + org.apache.maven.plugins + maven-enforcer-plugin + 3.0.0-M3 + + + org.apache.maven.plugins + maven-source-plugin + 3.2.1 + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.2.0 + + + org.apache.maven.plugins + maven-gpg-plugin + + 1.6 + + + + + + + + + oss-release + + + + org.apache.maven.plugins + maven-enforcer-plugin + + + enforce-maven + + enforce + + + + + [3.0.4,) + Maven 3.0 through 3.0.3 inclusive does not pass + correct settings.xml to Maven Release Plugin. + + + + + + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar-no-fork + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + attach-javadocs + + jar + + + + + + org.apache.maven.plugins + maven-gpg-plugin + + + --pinentry-mode + loopback + + + + + sign-artifacts + verify + + sign + + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + true + + + + + + + + snapshots + + false + + + + sonatype-nexus-snapshots + Sonatype Nexus Snapshots + ${sonatypeOssDistMgmtSnapshotsUrl} + + false + + + true + + + + + + sonatype-nexus-snapshots + Sonatype Nexus Snapshots + ${sonatypeOssDistMgmtSnapshotsUrl} + + false + + + true + + + + + + + + staging + + false + + + + sonatype-nexus-staging + Sonatype Nexus Staging + ${sonatypeOssDistMgmtStagingUrl} + + true + + + false + + + + + + sonatype-nexus-staging + Sonatype Nexus Staging + ${sonatypeOssDistMgmtStagingUrl} + + true + + + false + + + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/org.jdom/jdom2/2.0.6.1/172940c5c8e5198f95111b14aa4de1cf99528073/jdom2-2.0.6.1.pom b/.gradle-user/caches/modules-2/files-2.1/org.jdom/jdom2/2.0.6.1/172940c5c8e5198f95111b14aa4de1cf99528073/jdom2-2.0.6.1.pom new file mode 100644 index 0000000..d09bdb5 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.jdom/jdom2/2.0.6.1/172940c5c8e5198f95111b14aa4de1cf99528073/jdom2-2.0.6.1.pom @@ -0,0 +1,140 @@ + + 4.0.0 + org.jdom + jdom2 + jar + + JDOM + 2.0.6.1 + + + A complete, Java-based solution for accessing, manipulating, + and outputting XML data + + http://www.jdom.org + + + JDOM + http://www.jdom.org + + + + + JDOM-interest Mailing List + jdom-interest@jdom.org + http://jdom.markmail.org/ + + + + + + Similar to Apache License but with the acknowledgment clause removed + https://raw.github.com/hunterhacker/jdom/master/LICENSE.txt + repo + . + + 4. Products derived from this software may not be called "JDOM", nor + may "JDOM" appear in their name, without prior written permission + from the JDOM Project Management . + + In addition, we request (but do not require) that you include in the + end-user documentation provided with the redistribution and/or in the + software itself an acknowledgement equivalent to the following: + "This product includes software developed by the + JDOM Project (http://www.jdom.org/)." + Alternatively, the acknowledgment may be graphical using the logos + available at http://www.jdom.org/images/logos. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + This software consists of voluntary contributions made by many + individuals on behalf of the JDOM Project and was originally + created by Jason Hunter and + Brett McLaughlin . For more information + on the JDOM Project, please see . + + */ + + + + ]]> + + + + + git@github.com:/hunterhacker/jdom + scm:git:git@github.com:hunterhacker/jdom + scm:git:git@github.com:hunterhacker/jdom + + + + + hunterhacker + Jason Hunter + jhunter@servlets.com + + + rolfl + Rolf Lear + jdom@tuis.net + + + + + + jaxen + jaxen + 1.2.0 + true + + + xerces + xercesImpl + 2.11.0 + true + + + xalan + xalan + 2.7.2 + true + + + + + + 1.5 + + \ No newline at end of file diff --git a/.gradle-user/caches/modules-2/files-2.1/org.jdom/jdom2/2.0.6.1/dc15dff8f701b227ee523eeb7a17f77c10eafe2f/jdom2-2.0.6.1.jar b/.gradle-user/caches/modules-2/files-2.1/org.jdom/jdom2/2.0.6.1/dc15dff8f701b227ee523eeb7a17f77c10eafe2f/jdom2-2.0.6.1.jar new file mode 100644 index 0000000..da95839 Binary files /dev/null and b/.gradle-user/caches/modules-2/files-2.1/org.jdom/jdom2/2.0.6.1/dc15dff8f701b227ee523eeb7a17f77c10eafe2f/jdom2-2.0.6.1.jar differ diff --git a/.gradle-user/caches/modules-2/files-2.1/org.junit/junit-bom/5.10.1/1b577334c47deb59a29dc31e5211499d0eb3c17b/junit-bom-5.10.1.module b/.gradle-user/caches/modules-2/files-2.1/org.junit/junit-bom/5.10.1/1b577334c47deb59a29dc31e5211499d0eb3c17b/junit-bom-5.10.1.module new file mode 100644 index 0000000..07f4aa0 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.junit/junit-bom/5.10.1/1b577334c47deb59a29dc31e5211499d0eb3c17b/junit-bom-5.10.1.module @@ -0,0 +1,288 @@ +{ + "formatVersion": "1.1", + "component": { + "group": "org.junit", + "module": "junit-bom", + "version": "5.10.1", + "attributes": { + "org.gradle.status": "release" + } + }, + "createdBy": { + "gradle": { + "version": "8.2.1" + } + }, + "variants": [ + { + "name": "apiElements", + "attributes": { + "org.gradle.category": "platform", + "org.gradle.usage": "java-api" + }, + "dependencyConstraints": [ + { + "group": "org.junit.jupiter", + "module": "junit-jupiter", + "version": { + "requires": "5.10.1" + } + }, + { + "group": "org.junit.jupiter", + "module": "junit-jupiter-api", + "version": { + "requires": "5.10.1" + } + }, + { + "group": "org.junit.jupiter", + "module": "junit-jupiter-engine", + "version": { + "requires": "5.10.1" + } + }, + { + "group": "org.junit.jupiter", + "module": "junit-jupiter-migrationsupport", + "version": { + "requires": "5.10.1" + } + }, + { + "group": "org.junit.jupiter", + "module": "junit-jupiter-params", + "version": { + "requires": "5.10.1" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-commons", + "version": { + "requires": "1.10.1" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-console", + "version": { + "requires": "1.10.1" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-engine", + "version": { + "requires": "1.10.1" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-jfr", + "version": { + "requires": "1.10.1" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-launcher", + "version": { + "requires": "1.10.1" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-reporting", + "version": { + "requires": "1.10.1" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-runner", + "version": { + "requires": "1.10.1" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-suite", + "version": { + "requires": "1.10.1" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-suite-api", + "version": { + "requires": "1.10.1" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-suite-commons", + "version": { + "requires": "1.10.1" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-suite-engine", + "version": { + "requires": "1.10.1" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-testkit", + "version": { + "requires": "1.10.1" + } + }, + { + "group": "org.junit.vintage", + "module": "junit-vintage-engine", + "version": { + "requires": "5.10.1" + } + } + ] + }, + { + "name": "runtimeElements", + "attributes": { + "org.gradle.category": "platform", + "org.gradle.usage": "java-runtime" + }, + "dependencyConstraints": [ + { + "group": "org.junit.jupiter", + "module": "junit-jupiter", + "version": { + "requires": "5.10.1" + } + }, + { + "group": "org.junit.jupiter", + "module": "junit-jupiter-api", + "version": { + "requires": "5.10.1" + } + }, + { + "group": "org.junit.jupiter", + "module": "junit-jupiter-engine", + "version": { + "requires": "5.10.1" + } + }, + { + "group": "org.junit.jupiter", + "module": "junit-jupiter-migrationsupport", + "version": { + "requires": "5.10.1" + } + }, + { + "group": "org.junit.jupiter", + "module": "junit-jupiter-params", + "version": { + "requires": "5.10.1" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-commons", + "version": { + "requires": "1.10.1" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-console", + "version": { + "requires": "1.10.1" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-engine", + "version": { + "requires": "1.10.1" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-jfr", + "version": { + "requires": "1.10.1" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-launcher", + "version": { + "requires": "1.10.1" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-reporting", + "version": { + "requires": "1.10.1" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-runner", + "version": { + "requires": "1.10.1" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-suite", + "version": { + "requires": "1.10.1" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-suite-api", + "version": { + "requires": "1.10.1" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-suite-commons", + "version": { + "requires": "1.10.1" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-suite-engine", + "version": { + "requires": "1.10.1" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-testkit", + "version": { + "requires": "1.10.1" + } + }, + { + "group": "org.junit.vintage", + "module": "junit-vintage-engine", + "version": { + "requires": "5.10.1" + } + } + ] + } + ] +} diff --git a/.gradle-user/caches/modules-2/files-2.1/org.junit/junit-bom/5.10.1/41a86ea51227739a5b7ca3430ae88ce44a64a42a/junit-bom-5.10.1.pom b/.gradle-user/caches/modules-2/files-2.1/org.junit/junit-bom/5.10.1/41a86ea51227739a5b7ca3430ae88ce44a64a42a/junit-bom-5.10.1.pom new file mode 100644 index 0000000..40f6957 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.junit/junit-bom/5.10.1/41a86ea51227739a5b7ca3430ae88ce44a64a42a/junit-bom-5.10.1.pom @@ -0,0 +1,159 @@ + + + + + + + + 4.0.0 + org.junit + junit-bom + 5.10.1 + pom + JUnit 5 (Bill of Materials) + This Bill of Materials POM can be used to ease dependency management when referencing multiple JUnit artifacts using Gradle or Maven. + https://junit.org/junit5/ + + + Eclipse Public License v2.0 + https://www.eclipse.org/legal/epl-v20.html + + + + + bechte + Stefan Bechtold + stefan.bechtold@me.com + + + jlink + Johannes Link + business@johanneslink.net + + + marcphilipp + Marc Philipp + mail@marcphilipp.de + + + mmerdes + Matthias Merdes + matthias.merdes@heidelpay.com + + + sbrannen + Sam Brannen + sam@sambrannen.com + + + sormuras + Christian Stein + sormuras@gmail.com + + + juliette-derancourt + Juliette de Rancourt + derancourt.juliette@gmail.com + + + + scm:git:git://github.com/junit-team/junit5.git + scm:git:git://github.com/junit-team/junit5.git + https://github.com/junit-team/junit5 + + + + + org.junit.jupiter + junit-jupiter + 5.10.1 + + + org.junit.jupiter + junit-jupiter-api + 5.10.1 + + + org.junit.jupiter + junit-jupiter-engine + 5.10.1 + + + org.junit.jupiter + junit-jupiter-migrationsupport + 5.10.1 + + + org.junit.jupiter + junit-jupiter-params + 5.10.1 + + + org.junit.platform + junit-platform-commons + 1.10.1 + + + org.junit.platform + junit-platform-console + 1.10.1 + + + org.junit.platform + junit-platform-engine + 1.10.1 + + + org.junit.platform + junit-platform-jfr + 1.10.1 + + + org.junit.platform + junit-platform-launcher + 1.10.1 + + + org.junit.platform + junit-platform-reporting + 1.10.1 + + + org.junit.platform + junit-platform-runner + 1.10.1 + + + org.junit.platform + junit-platform-suite + 1.10.1 + + + org.junit.platform + junit-platform-suite-api + 1.10.1 + + + org.junit.platform + junit-platform-suite-commons + 1.10.1 + + + org.junit.platform + junit-platform-suite-engine + 1.10.1 + + + org.junit.platform + junit-platform-testkit + 1.10.1 + + + org.junit.vintage + junit-vintage-engine + 5.10.1 + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/org.junit/junit-bom/5.10.2/b25ed98a5bd08cdda60e569cf22822a760e76019/junit-bom-5.10.2.pom b/.gradle-user/caches/modules-2/files-2.1/org.junit/junit-bom/5.10.2/b25ed98a5bd08cdda60e569cf22822a760e76019/junit-bom-5.10.2.pom new file mode 100644 index 0000000..92e6e60 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.junit/junit-bom/5.10.2/b25ed98a5bd08cdda60e569cf22822a760e76019/junit-bom-5.10.2.pom @@ -0,0 +1,159 @@ + + + + + + + + 4.0.0 + org.junit + junit-bom + 5.10.2 + pom + JUnit 5 (Bill of Materials) + This Bill of Materials POM can be used to ease dependency management when referencing multiple JUnit artifacts using Gradle or Maven. + https://junit.org/junit5/ + + + Eclipse Public License v2.0 + https://www.eclipse.org/legal/epl-v20.html + + + + + bechte + Stefan Bechtold + stefan.bechtold@me.com + + + jlink + Johannes Link + business@johanneslink.net + + + marcphilipp + Marc Philipp + mail@marcphilipp.de + + + mmerdes + Matthias Merdes + matthias.merdes@heidelpay.com + + + sbrannen + Sam Brannen + sam@sambrannen.com + + + sormuras + Christian Stein + sormuras@gmail.com + + + juliette-derancourt + Juliette de Rancourt + derancourt.juliette@gmail.com + + + + scm:git:git://github.com/junit-team/junit5.git + scm:git:git://github.com/junit-team/junit5.git + https://github.com/junit-team/junit5 + + + + + org.junit.jupiter + junit-jupiter + 5.10.2 + + + org.junit.jupiter + junit-jupiter-api + 5.10.2 + + + org.junit.jupiter + junit-jupiter-engine + 5.10.2 + + + org.junit.jupiter + junit-jupiter-migrationsupport + 5.10.2 + + + org.junit.jupiter + junit-jupiter-params + 5.10.2 + + + org.junit.platform + junit-platform-commons + 1.10.2 + + + org.junit.platform + junit-platform-console + 1.10.2 + + + org.junit.platform + junit-platform-engine + 1.10.2 + + + org.junit.platform + junit-platform-jfr + 1.10.2 + + + org.junit.platform + junit-platform-launcher + 1.10.2 + + + org.junit.platform + junit-platform-reporting + 1.10.2 + + + org.junit.platform + junit-platform-runner + 1.10.2 + + + org.junit.platform + junit-platform-suite + 1.10.2 + + + org.junit.platform + junit-platform-suite-api + 1.10.2 + + + org.junit.platform + junit-platform-suite-commons + 1.10.2 + + + org.junit.platform + junit-platform-suite-engine + 1.10.2 + + + org.junit.platform + junit-platform-testkit + 1.10.2 + + + org.junit.vintage + junit-vintage-engine + 5.10.2 + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/org.junit/junit-bom/5.10.2/ce536748a853ae6ac09e7815fce0678a96cff778/junit-bom-5.10.2.module b/.gradle-user/caches/modules-2/files-2.1/org.junit/junit-bom/5.10.2/ce536748a853ae6ac09e7815fce0678a96cff778/junit-bom-5.10.2.module new file mode 100644 index 0000000..52ac6c7 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.junit/junit-bom/5.10.2/ce536748a853ae6ac09e7815fce0678a96cff778/junit-bom-5.10.2.module @@ -0,0 +1,288 @@ +{ + "formatVersion": "1.1", + "component": { + "group": "org.junit", + "module": "junit-bom", + "version": "5.10.2", + "attributes": { + "org.gradle.status": "release" + } + }, + "createdBy": { + "gradle": { + "version": "8.2.1" + } + }, + "variants": [ + { + "name": "apiElements", + "attributes": { + "org.gradle.category": "platform", + "org.gradle.usage": "java-api" + }, + "dependencyConstraints": [ + { + "group": "org.junit.jupiter", + "module": "junit-jupiter", + "version": { + "requires": "5.10.2" + } + }, + { + "group": "org.junit.jupiter", + "module": "junit-jupiter-api", + "version": { + "requires": "5.10.2" + } + }, + { + "group": "org.junit.jupiter", + "module": "junit-jupiter-engine", + "version": { + "requires": "5.10.2" + } + }, + { + "group": "org.junit.jupiter", + "module": "junit-jupiter-migrationsupport", + "version": { + "requires": "5.10.2" + } + }, + { + "group": "org.junit.jupiter", + "module": "junit-jupiter-params", + "version": { + "requires": "5.10.2" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-commons", + "version": { + "requires": "1.10.2" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-console", + "version": { + "requires": "1.10.2" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-engine", + "version": { + "requires": "1.10.2" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-jfr", + "version": { + "requires": "1.10.2" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-launcher", + "version": { + "requires": "1.10.2" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-reporting", + "version": { + "requires": "1.10.2" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-runner", + "version": { + "requires": "1.10.2" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-suite", + "version": { + "requires": "1.10.2" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-suite-api", + "version": { + "requires": "1.10.2" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-suite-commons", + "version": { + "requires": "1.10.2" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-suite-engine", + "version": { + "requires": "1.10.2" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-testkit", + "version": { + "requires": "1.10.2" + } + }, + { + "group": "org.junit.vintage", + "module": "junit-vintage-engine", + "version": { + "requires": "5.10.2" + } + } + ] + }, + { + "name": "runtimeElements", + "attributes": { + "org.gradle.category": "platform", + "org.gradle.usage": "java-runtime" + }, + "dependencyConstraints": [ + { + "group": "org.junit.jupiter", + "module": "junit-jupiter", + "version": { + "requires": "5.10.2" + } + }, + { + "group": "org.junit.jupiter", + "module": "junit-jupiter-api", + "version": { + "requires": "5.10.2" + } + }, + { + "group": "org.junit.jupiter", + "module": "junit-jupiter-engine", + "version": { + "requires": "5.10.2" + } + }, + { + "group": "org.junit.jupiter", + "module": "junit-jupiter-migrationsupport", + "version": { + "requires": "5.10.2" + } + }, + { + "group": "org.junit.jupiter", + "module": "junit-jupiter-params", + "version": { + "requires": "5.10.2" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-commons", + "version": { + "requires": "1.10.2" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-console", + "version": { + "requires": "1.10.2" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-engine", + "version": { + "requires": "1.10.2" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-jfr", + "version": { + "requires": "1.10.2" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-launcher", + "version": { + "requires": "1.10.2" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-reporting", + "version": { + "requires": "1.10.2" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-runner", + "version": { + "requires": "1.10.2" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-suite", + "version": { + "requires": "1.10.2" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-suite-api", + "version": { + "requires": "1.10.2" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-suite-commons", + "version": { + "requires": "1.10.2" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-suite-engine", + "version": { + "requires": "1.10.2" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-testkit", + "version": { + "requires": "1.10.2" + } + }, + { + "group": "org.junit.vintage", + "module": "junit-vintage-engine", + "version": { + "requires": "5.10.2" + } + } + ] + } + ] +} diff --git a/.gradle-user/caches/modules-2/files-2.1/org.junit/junit-bom/5.10.3/316c7ec3b39b3820c4557166a3179590ff2c3402/junit-bom-5.10.3.module b/.gradle-user/caches/modules-2/files-2.1/org.junit/junit-bom/5.10.3/316c7ec3b39b3820c4557166a3179590ff2c3402/junit-bom-5.10.3.module new file mode 100644 index 0000000..bc0ea44 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.junit/junit-bom/5.10.3/316c7ec3b39b3820c4557166a3179590ff2c3402/junit-bom-5.10.3.module @@ -0,0 +1,288 @@ +{ + "formatVersion": "1.1", + "component": { + "group": "org.junit", + "module": "junit-bom", + "version": "5.10.3", + "attributes": { + "org.gradle.status": "release" + } + }, + "createdBy": { + "gradle": { + "version": "8.2.1" + } + }, + "variants": [ + { + "name": "apiElements", + "attributes": { + "org.gradle.category": "platform", + "org.gradle.usage": "java-api" + }, + "dependencyConstraints": [ + { + "group": "org.junit.jupiter", + "module": "junit-jupiter", + "version": { + "requires": "5.10.3" + } + }, + { + "group": "org.junit.jupiter", + "module": "junit-jupiter-api", + "version": { + "requires": "5.10.3" + } + }, + { + "group": "org.junit.jupiter", + "module": "junit-jupiter-engine", + "version": { + "requires": "5.10.3" + } + }, + { + "group": "org.junit.jupiter", + "module": "junit-jupiter-migrationsupport", + "version": { + "requires": "5.10.3" + } + }, + { + "group": "org.junit.jupiter", + "module": "junit-jupiter-params", + "version": { + "requires": "5.10.3" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-commons", + "version": { + "requires": "1.10.3" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-console", + "version": { + "requires": "1.10.3" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-engine", + "version": { + "requires": "1.10.3" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-jfr", + "version": { + "requires": "1.10.3" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-launcher", + "version": { + "requires": "1.10.3" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-reporting", + "version": { + "requires": "1.10.3" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-runner", + "version": { + "requires": "1.10.3" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-suite", + "version": { + "requires": "1.10.3" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-suite-api", + "version": { + "requires": "1.10.3" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-suite-commons", + "version": { + "requires": "1.10.3" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-suite-engine", + "version": { + "requires": "1.10.3" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-testkit", + "version": { + "requires": "1.10.3" + } + }, + { + "group": "org.junit.vintage", + "module": "junit-vintage-engine", + "version": { + "requires": "5.10.3" + } + } + ] + }, + { + "name": "runtimeElements", + "attributes": { + "org.gradle.category": "platform", + "org.gradle.usage": "java-runtime" + }, + "dependencyConstraints": [ + { + "group": "org.junit.jupiter", + "module": "junit-jupiter", + "version": { + "requires": "5.10.3" + } + }, + { + "group": "org.junit.jupiter", + "module": "junit-jupiter-api", + "version": { + "requires": "5.10.3" + } + }, + { + "group": "org.junit.jupiter", + "module": "junit-jupiter-engine", + "version": { + "requires": "5.10.3" + } + }, + { + "group": "org.junit.jupiter", + "module": "junit-jupiter-migrationsupport", + "version": { + "requires": "5.10.3" + } + }, + { + "group": "org.junit.jupiter", + "module": "junit-jupiter-params", + "version": { + "requires": "5.10.3" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-commons", + "version": { + "requires": "1.10.3" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-console", + "version": { + "requires": "1.10.3" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-engine", + "version": { + "requires": "1.10.3" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-jfr", + "version": { + "requires": "1.10.3" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-launcher", + "version": { + "requires": "1.10.3" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-reporting", + "version": { + "requires": "1.10.3" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-runner", + "version": { + "requires": "1.10.3" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-suite", + "version": { + "requires": "1.10.3" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-suite-api", + "version": { + "requires": "1.10.3" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-suite-commons", + "version": { + "requires": "1.10.3" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-suite-engine", + "version": { + "requires": "1.10.3" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-testkit", + "version": { + "requires": "1.10.3" + } + }, + { + "group": "org.junit.vintage", + "module": "junit-vintage-engine", + "version": { + "requires": "5.10.3" + } + } + ] + } + ] +} diff --git a/.gradle-user/caches/modules-2/files-2.1/org.junit/junit-bom/5.10.3/fe8295327d9e5cb3bf1641493dd1485bc714b1e4/junit-bom-5.10.3.pom b/.gradle-user/caches/modules-2/files-2.1/org.junit/junit-bom/5.10.3/fe8295327d9e5cb3bf1641493dd1485bc714b1e4/junit-bom-5.10.3.pom new file mode 100644 index 0000000..60a7276 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.junit/junit-bom/5.10.3/fe8295327d9e5cb3bf1641493dd1485bc714b1e4/junit-bom-5.10.3.pom @@ -0,0 +1,159 @@ + + + + + + + + 4.0.0 + org.junit + junit-bom + 5.10.3 + pom + JUnit 5 (Bill of Materials) + This Bill of Materials POM can be used to ease dependency management when referencing multiple JUnit artifacts using Gradle or Maven. + https://junit.org/junit5/ + + + Eclipse Public License v2.0 + https://www.eclipse.org/legal/epl-v20.html + + + + + bechte + Stefan Bechtold + stefan.bechtold@me.com + + + jlink + Johannes Link + business@johanneslink.net + + + marcphilipp + Marc Philipp + mail@marcphilipp.de + + + mmerdes + Matthias Merdes + matthias.merdes@heidelpay.com + + + sbrannen + Sam Brannen + sam@sambrannen.com + + + sormuras + Christian Stein + sormuras@gmail.com + + + juliette-derancourt + Juliette de Rancourt + derancourt.juliette@gmail.com + + + + scm:git:git://github.com/junit-team/junit5.git + scm:git:git://github.com/junit-team/junit5.git + https://github.com/junit-team/junit5 + + + + + org.junit.jupiter + junit-jupiter + 5.10.3 + + + org.junit.jupiter + junit-jupiter-api + 5.10.3 + + + org.junit.jupiter + junit-jupiter-engine + 5.10.3 + + + org.junit.jupiter + junit-jupiter-migrationsupport + 5.10.3 + + + org.junit.jupiter + junit-jupiter-params + 5.10.3 + + + org.junit.platform + junit-platform-commons + 1.10.3 + + + org.junit.platform + junit-platform-console + 1.10.3 + + + org.junit.platform + junit-platform-engine + 1.10.3 + + + org.junit.platform + junit-platform-jfr + 1.10.3 + + + org.junit.platform + junit-platform-launcher + 1.10.3 + + + org.junit.platform + junit-platform-reporting + 1.10.3 + + + org.junit.platform + junit-platform-runner + 1.10.3 + + + org.junit.platform + junit-platform-suite + 1.10.3 + + + org.junit.platform + junit-platform-suite-api + 1.10.3 + + + org.junit.platform + junit-platform-suite-commons + 1.10.3 + + + org.junit.platform + junit-platform-suite-engine + 1.10.3 + + + org.junit.platform + junit-platform-testkit + 1.10.3 + + + org.junit.vintage + junit-vintage-engine + 5.10.3 + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/org.junit/junit-bom/5.11.0/a4a8a67d5348d748a6345d6f1d08846fb2780ed9/junit-bom-5.11.0.pom b/.gradle-user/caches/modules-2/files-2.1/org.junit/junit-bom/5.11.0/a4a8a67d5348d748a6345d6f1d08846fb2780ed9/junit-bom-5.11.0.pom new file mode 100644 index 0000000..db386f4 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.junit/junit-bom/5.11.0/a4a8a67d5348d748a6345d6f1d08846fb2780ed9/junit-bom-5.11.0.pom @@ -0,0 +1,159 @@ + + + + + + + + 4.0.0 + org.junit + junit-bom + 5.11.0 + pom + JUnit 5 (Bill of Materials) + This Bill of Materials POM can be used to ease dependency management when referencing multiple JUnit artifacts using Gradle or Maven. + https://junit.org/junit5/ + + + Eclipse Public License v2.0 + https://www.eclipse.org/legal/epl-v20.html + + + + + bechte + Stefan Bechtold + stefan.bechtold@me.com + + + jlink + Johannes Link + business@johanneslink.net + + + marcphilipp + Marc Philipp + mail@marcphilipp.de + + + mmerdes + Matthias Merdes + matthias.merdes@heidelpay.com + + + sbrannen + Sam Brannen + sam@sambrannen.com + + + sormuras + Christian Stein + sormuras@gmail.com + + + juliette-derancourt + Juliette de Rancourt + derancourt.juliette@gmail.com + + + + scm:git:git://github.com/junit-team/junit5.git + scm:git:git://github.com/junit-team/junit5.git + https://github.com/junit-team/junit5 + + + + + org.junit.jupiter + junit-jupiter + 5.11.0 + + + org.junit.jupiter + junit-jupiter-api + 5.11.0 + + + org.junit.jupiter + junit-jupiter-engine + 5.11.0 + + + org.junit.jupiter + junit-jupiter-migrationsupport + 5.11.0 + + + org.junit.jupiter + junit-jupiter-params + 5.11.0 + + + org.junit.platform + junit-platform-commons + 1.11.0 + + + org.junit.platform + junit-platform-console + 1.11.0 + + + org.junit.platform + junit-platform-engine + 1.11.0 + + + org.junit.platform + junit-platform-jfr + 1.11.0 + + + org.junit.platform + junit-platform-launcher + 1.11.0 + + + org.junit.platform + junit-platform-reporting + 1.11.0 + + + org.junit.platform + junit-platform-runner + 1.11.0 + + + org.junit.platform + junit-platform-suite + 1.11.0 + + + org.junit.platform + junit-platform-suite-api + 1.11.0 + + + org.junit.platform + junit-platform-suite-commons + 1.11.0 + + + org.junit.platform + junit-platform-suite-engine + 1.11.0 + + + org.junit.platform + junit-platform-testkit + 1.11.0 + + + org.junit.vintage + junit-vintage-engine + 5.11.0 + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/org.junit/junit-bom/5.11.0/d0302ab22149450fd7698262515751337f70a3a6/junit-bom-5.11.0.module b/.gradle-user/caches/modules-2/files-2.1/org.junit/junit-bom/5.11.0/d0302ab22149450fd7698262515751337f70a3a6/junit-bom-5.11.0.module new file mode 100644 index 0000000..a7b15c8 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.junit/junit-bom/5.11.0/d0302ab22149450fd7698262515751337f70a3a6/junit-bom-5.11.0.module @@ -0,0 +1,288 @@ +{ + "formatVersion": "1.1", + "component": { + "group": "org.junit", + "module": "junit-bom", + "version": "5.11.0", + "attributes": { + "org.gradle.status": "release" + } + }, + "createdBy": { + "gradle": { + "version": "8.9" + } + }, + "variants": [ + { + "name": "apiElements", + "attributes": { + "org.gradle.category": "platform", + "org.gradle.usage": "java-api" + }, + "dependencyConstraints": [ + { + "group": "org.junit.jupiter", + "module": "junit-jupiter", + "version": { + "requires": "5.11.0" + } + }, + { + "group": "org.junit.jupiter", + "module": "junit-jupiter-api", + "version": { + "requires": "5.11.0" + } + }, + { + "group": "org.junit.jupiter", + "module": "junit-jupiter-engine", + "version": { + "requires": "5.11.0" + } + }, + { + "group": "org.junit.jupiter", + "module": "junit-jupiter-migrationsupport", + "version": { + "requires": "5.11.0" + } + }, + { + "group": "org.junit.jupiter", + "module": "junit-jupiter-params", + "version": { + "requires": "5.11.0" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-commons", + "version": { + "requires": "1.11.0" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-console", + "version": { + "requires": "1.11.0" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-engine", + "version": { + "requires": "1.11.0" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-jfr", + "version": { + "requires": "1.11.0" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-launcher", + "version": { + "requires": "1.11.0" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-reporting", + "version": { + "requires": "1.11.0" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-runner", + "version": { + "requires": "1.11.0" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-suite", + "version": { + "requires": "1.11.0" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-suite-api", + "version": { + "requires": "1.11.0" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-suite-commons", + "version": { + "requires": "1.11.0" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-suite-engine", + "version": { + "requires": "1.11.0" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-testkit", + "version": { + "requires": "1.11.0" + } + }, + { + "group": "org.junit.vintage", + "module": "junit-vintage-engine", + "version": { + "requires": "5.11.0" + } + } + ] + }, + { + "name": "runtimeElements", + "attributes": { + "org.gradle.category": "platform", + "org.gradle.usage": "java-runtime" + }, + "dependencyConstraints": [ + { + "group": "org.junit.jupiter", + "module": "junit-jupiter", + "version": { + "requires": "5.11.0" + } + }, + { + "group": "org.junit.jupiter", + "module": "junit-jupiter-api", + "version": { + "requires": "5.11.0" + } + }, + { + "group": "org.junit.jupiter", + "module": "junit-jupiter-engine", + "version": { + "requires": "5.11.0" + } + }, + { + "group": "org.junit.jupiter", + "module": "junit-jupiter-migrationsupport", + "version": { + "requires": "5.11.0" + } + }, + { + "group": "org.junit.jupiter", + "module": "junit-jupiter-params", + "version": { + "requires": "5.11.0" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-commons", + "version": { + "requires": "1.11.0" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-console", + "version": { + "requires": "1.11.0" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-engine", + "version": { + "requires": "1.11.0" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-jfr", + "version": { + "requires": "1.11.0" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-launcher", + "version": { + "requires": "1.11.0" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-reporting", + "version": { + "requires": "1.11.0" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-runner", + "version": { + "requires": "1.11.0" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-suite", + "version": { + "requires": "1.11.0" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-suite-api", + "version": { + "requires": "1.11.0" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-suite-commons", + "version": { + "requires": "1.11.0" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-suite-engine", + "version": { + "requires": "1.11.0" + } + }, + { + "group": "org.junit.platform", + "module": "junit-platform-testkit", + "version": { + "requires": "1.11.0" + } + }, + { + "group": "org.junit.vintage", + "module": "junit-vintage-engine", + "version": { + "requires": "5.11.0" + } + } + ] + } + ] +} diff --git a/.gradle-user/caches/modules-2/files-2.1/org.mockito/mockito-bom/4.11.0/1c271051b650e8dd5ae2c9726ee5953887030d/mockito-bom-4.11.0.pom b/.gradle-user/caches/modules-2/files-2.1/org.mockito/mockito-bom/4.11.0/1c271051b650e8dd5ae2c9726ee5953887030d/mockito-bom-4.11.0.pom new file mode 100644 index 0000000..e042288 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.mockito/mockito-bom/4.11.0/1c271051b650e8dd5ae2c9726ee5953887030d/mockito-bom-4.11.0.pom @@ -0,0 +1,103 @@ + + + 4.0.0 + org.mockito + mockito-bom + 4.11.0 + pom + mockito-bom + Mockito Bill of Materials (BOM) + https://github.com/mockito/mockito + + + The MIT License + https://github.com/mockito/mockito/blob/main/LICENSE + repo + + + + + mockitoguy + Szczepan Faber + https://github.com/mockitoguy + + Core developer + + + + bric3 + Brice Dutheil + https://github.com/bric3 + + Core developer + + + + raphw + Rafael Winterhalter + https://github.com/raphw + + Core developer + + + + TimvdLippe + Tim van der Lippe + https://github.com/TimvdLippe + + Core developer + + + + + https://github.com/mockito/mockito.git + + + GitHub issues + https://github.com/mockito/mockito/issues + + + GH Actions + https://github.com/mockito/mockito/actions + + + + + org.mockito + mockito-core + 4.11.0 + + + org.mockito + mockito-android + 4.11.0 + + + org.mockito + mockito-errorprone + 4.11.0 + + + org.mockito + mockito-inline + 4.11.0 + + + org.mockito + mockito-junit-jupiter + 4.11.0 + + + org.mockito + mockito-proxy + 4.11.0 + + + org.mockito + mockito-subclass + 4.11.0 + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/org.mockito/mockito-bom/5.7.0/c4c2dc5e4b502a505a31fc4038a606dab7be4616/mockito-bom-5.7.0.pom b/.gradle-user/caches/modules-2/files-2.1/org.mockito/mockito-bom/5.7.0/c4c2dc5e4b502a505a31fc4038a606dab7be4616/mockito-bom-5.7.0.pom new file mode 100644 index 0000000..3b7536a --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.mockito/mockito-bom/5.7.0/c4c2dc5e4b502a505a31fc4038a606dab7be4616/mockito-bom-5.7.0.pom @@ -0,0 +1,98 @@ + + + 4.0.0 + org.mockito + mockito-bom + 5.7.0 + pom + mockito-bom + Mockito Bill of Materials (BOM) + https://github.com/mockito/mockito + + + MIT + https://opensource.org/licenses/MIT + repo + + + + + mockitoguy + Szczepan Faber + https://github.com/mockitoguy + + Core developer + + + + bric3 + Brice Dutheil + https://github.com/bric3 + + Core developer + + + + raphw + Rafael Winterhalter + https://github.com/raphw + + Core developer + + + + TimvdLippe + Tim van der Lippe + https://github.com/TimvdLippe + + Core developer + + + + + https://github.com/mockito/mockito.git + + + GitHub issues + https://github.com/mockito/mockito/issues + + + GH Actions + https://github.com/mockito/mockito/actions + + + + + org.mockito + mockito-core + 5.7.0 + + + org.mockito + mockito-android + 5.7.0 + + + org.mockito + mockito-errorprone + 5.7.0 + + + org.mockito + mockito-junit-jupiter + 5.7.0 + + + org.mockito + mockito-proxy + 5.7.0 + + + org.mockito + mockito-subclass + 5.7.0 + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/org.ow2.asm/asm-commons/9.7.1/1efae0cd5d2599b35cba54897887351b3a087080/asm-commons-9.7.1.pom b/.gradle-user/caches/modules-2/files-2.1/org.ow2.asm/asm-commons/9.7.1/1efae0cd5d2599b35cba54897887351b3a087080/asm-commons-9.7.1.pom new file mode 100644 index 0000000..27a9234 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.ow2.asm/asm-commons/9.7.1/1efae0cd5d2599b35cba54897887351b3a087080/asm-commons-9.7.1.pom @@ -0,0 +1,89 @@ + + + 4.0.0 + org.ow2.asm + asm-commons + 9.7.1 + asm-commons + Usefull class adapters based on ASM, a very small and fast Java bytecode manipulation framework + http://asm.ow2.io/ + 2000 + + OW2 + http://www.ow2.org/ + + + + BSD-3-Clause + https://asm.ow2.io/license.html + + + + + ebruneton + Eric Bruneton + ebruneton@free.fr + + Creator + Java Developer + + + + eu + Eugene Kuleshov + eu@javatx.org + + Java Developer + + + + forax + Remi Forax + forax@univ-mlv.fr + + Java Developer + + + + + + ASM Users List + https://mail.ow2.org/wws/subscribe/asm + asm@objectweb.org + https://mail.ow2.org/wws/arc/asm/ + + + ASM Team List + https://mail.ow2.org/wws/subscribe/asm-team + asm-team@objectweb.org + https://mail.ow2.org/wws/arc/asm-team/ + + + + scm:git:https://gitlab.ow2.org/asm/asm/ + scm:git:https://gitlab.ow2.org/asm/asm/ + https://gitlab.ow2.org/asm/asm/ + + + https://gitlab.ow2.org/asm/asm/issues + + + + org.ow2.asm + asm + 9.7.1 + compile + + + org.ow2.asm + asm-tree + 9.7.1 + compile + + + + org.ow2 + ow2 + 1.5.1 + + diff --git a/.gradle-user/caches/modules-2/files-2.1/org.ow2.asm/asm-commons/9.7.1/406c6a2225cfe1819f102a161e54cc16a5c24f75/asm-commons-9.7.1.jar b/.gradle-user/caches/modules-2/files-2.1/org.ow2.asm/asm-commons/9.7.1/406c6a2225cfe1819f102a161e54cc16a5c24f75/asm-commons-9.7.1.jar new file mode 100644 index 0000000..4175f17 Binary files /dev/null and b/.gradle-user/caches/modules-2/files-2.1/org.ow2.asm/asm-commons/9.7.1/406c6a2225cfe1819f102a161e54cc16a5c24f75/asm-commons-9.7.1.jar differ diff --git a/.gradle-user/caches/modules-2/files-2.1/org.ow2.asm/asm-tree/9.7.1/3a53139787663b139de76b627fca0084ab60d32c/asm-tree-9.7.1.jar b/.gradle-user/caches/modules-2/files-2.1/org.ow2.asm/asm-tree/9.7.1/3a53139787663b139de76b627fca0084ab60d32c/asm-tree-9.7.1.jar new file mode 100644 index 0000000..a1004da Binary files /dev/null and b/.gradle-user/caches/modules-2/files-2.1/org.ow2.asm/asm-tree/9.7.1/3a53139787663b139de76b627fca0084ab60d32c/asm-tree-9.7.1.jar differ diff --git a/.gradle-user/caches/modules-2/files-2.1/org.ow2.asm/asm-tree/9.7.1/acf4a9c488ab0ca8974ef5623b1665361c74255c/asm-tree-9.7.1.pom b/.gradle-user/caches/modules-2/files-2.1/org.ow2.asm/asm-tree/9.7.1/acf4a9c488ab0ca8974ef5623b1665361c74255c/asm-tree-9.7.1.pom new file mode 100644 index 0000000..b3257be --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.ow2.asm/asm-tree/9.7.1/acf4a9c488ab0ca8974ef5623b1665361c74255c/asm-tree-9.7.1.pom @@ -0,0 +1,83 @@ + + + 4.0.0 + org.ow2.asm + asm-tree + 9.7.1 + asm-tree + Tree API of ASM, a very small and fast Java bytecode manipulation framework + http://asm.ow2.io/ + 2000 + + OW2 + http://www.ow2.org/ + + + + BSD-3-Clause + https://asm.ow2.io/license.html + + + + + ebruneton + Eric Bruneton + ebruneton@free.fr + + Creator + Java Developer + + + + eu + Eugene Kuleshov + eu@javatx.org + + Java Developer + + + + forax + Remi Forax + forax@univ-mlv.fr + + Java Developer + + + + + + ASM Users List + https://mail.ow2.org/wws/subscribe/asm + asm@objectweb.org + https://mail.ow2.org/wws/arc/asm/ + + + ASM Team List + https://mail.ow2.org/wws/subscribe/asm-team + asm-team@objectweb.org + https://mail.ow2.org/wws/arc/asm-team/ + + + + scm:git:https://gitlab.ow2.org/asm/asm/ + scm:git:https://gitlab.ow2.org/asm/asm/ + https://gitlab.ow2.org/asm/asm/ + + + https://gitlab.ow2.org/asm/asm/issues + + + + org.ow2.asm + asm + 9.7.1 + compile + + + + org.ow2 + ow2 + 1.5.1 + + diff --git a/.gradle-user/caches/modules-2/files-2.1/org.ow2.asm/asm/9.7.1/381a4b6892969305d88ee13c53e88eabff82d382/asm-9.7.1.pom b/.gradle-user/caches/modules-2/files-2.1/org.ow2.asm/asm/9.7.1/381a4b6892969305d88ee13c53e88eabff82d382/asm-9.7.1.pom new file mode 100644 index 0000000..103a5ce --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.ow2.asm/asm/9.7.1/381a4b6892969305d88ee13c53e88eabff82d382/asm-9.7.1.pom @@ -0,0 +1,75 @@ + + + 4.0.0 + org.ow2.asm + asm + 9.7.1 + asm + ASM, a very small and fast Java bytecode manipulation framework + http://asm.ow2.io/ + 2000 + + OW2 + http://www.ow2.org/ + + + + BSD-3-Clause + https://asm.ow2.io/license.html + + + + + ebruneton + Eric Bruneton + ebruneton@free.fr + + Creator + Java Developer + + + + eu + Eugene Kuleshov + eu@javatx.org + + Java Developer + + + + forax + Remi Forax + forax@univ-mlv.fr + + Java Developer + + + + + + ASM Users List + https://mail.ow2.org/wws/subscribe/asm + asm@objectweb.org + https://mail.ow2.org/wws/arc/asm/ + + + ASM Team List + https://mail.ow2.org/wws/subscribe/asm-team + asm-team@objectweb.org + https://mail.ow2.org/wws/arc/asm-team/ + + + + scm:git:https://gitlab.ow2.org/asm/asm/ + scm:git:https://gitlab.ow2.org/asm/asm/ + https://gitlab.ow2.org/asm/asm/ + + + https://gitlab.ow2.org/asm/asm/issues + + + org.ow2 + ow2 + 1.5.1 + + diff --git a/.gradle-user/caches/modules-2/files-2.1/org.ow2.asm/asm/9.7.1/f0ed132a49244b042cd0e15702ab9f2ce3cc8436/asm-9.7.1.jar b/.gradle-user/caches/modules-2/files-2.1/org.ow2.asm/asm/9.7.1/f0ed132a49244b042cd0e15702ab9f2ce3cc8436/asm-9.7.1.jar new file mode 100644 index 0000000..fe3d001 Binary files /dev/null and b/.gradle-user/caches/modules-2/files-2.1/org.ow2.asm/asm/9.7.1/f0ed132a49244b042cd0e15702ab9f2ce3cc8436/asm-9.7.1.jar differ diff --git a/.gradle-user/caches/modules-2/files-2.1/org.ow2/ow2/1.5.1/bda66fa5f1b68fa7d2de3d569bdc8508b2af82d4/ow2-1.5.1.pom b/.gradle-user/caches/modules-2/files-2.1/org.ow2/ow2/1.5.1/bda66fa5f1b68fa7d2de3d569bdc8508b2af82d4/ow2-1.5.1.pom new file mode 100644 index 0000000..49837b7 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.ow2/ow2/1.5.1/bda66fa5f1b68fa7d2de3d569bdc8508b2af82d4/ow2-1.5.1.pom @@ -0,0 +1,309 @@ + + + + 4.0.0 + + org.ow2 + ow2 + 1.5.1 + pom + + OW2 Consortium + + The OW2 Consortium is an open source community committed to making available to everyone + the best and most reliable middleware technology, including generic enterprise applications + and cloud computing technologies. The mission of the OW2 Consortium is to + i) develop open source code for middleware, generic enterprise applications and cloud computing and + ii) to foster a vibrant community and business ecosystem. + + + + + + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + + OW2 Consortium + http://www.ow2.org + + + + http://www.ow2.org + + + + + sauthieg + Guillaume Sauthier + guillaume.sauthier@ow2.org + + + + + + + http://www.ow2.org/xwiki/bin/download/NewsEvents/MarketingResources/ow2_logo_small_transp.png + + + UTF-8 + + + https://repository.ow2.org/nexus/content/repositories/snapshots + https://repository.ow2.org/nexus/service/local/staging/deploy/maven2 + source-release + ow2-release + 1.0.1 + + + 2.3 + 1.4 + 2.8.1 + 2.1.2 + 2.3.2 + + + + + scm:git:git@gitlab.ow2.org:ow2-lifecycle/ow2-parent-pom.git + scm:git:git@gitlab.ow2.org:ow2-lifecycle/ow2-parent-pom.git + https://gitlab.ow2.org/ow2-lifecycle/ow2-parent-pom/ + 1.5.1 + + + + + + + + + + ow2.release + OW2 Maven Releases Repository + ${ow2DistMgmtReleasesUrl} + + + + + ow2.snapshot + OW2 Maven Snapshots Repository + ${ow2DistMgmtSnapshotsUrl} + + + + + + + + + + + + ow2-plugin-snapshot + OW2 Snapshot Plugin Repository + https://repository.ow2.org/nexus/content/repositories/snapshots + + false + + + + + + + + + + + ow2-snapshot + OW2 Snapshot Repository + https://repository.ow2.org/nexus/content/repositories/snapshots + + false + + + + + + + + + + org.apache.maven.plugins + maven-enforcer-plugin + 1.0-beta-1 + + + enforce-maven + + enforce + + + + + (,2.1.0),(2.1.0,2.2.0),(2.2.0,) + Maven 2.1.0 and 2.2.0 produce incorrect GPG signatures and checksums respectively. + + + + + + + + + + + + + org.apache.maven.plugins + maven-release-plugin + ${maven-release-plugin.version} + + forked-path + + + false + + ${ow2ReleaseProfiles} + + + + + + + + + + + ow2-release + + + + + + + org.apache.maven.plugins + maven-source-plugin + ${maven-source-plugin.version} + + + + attach-sources + + jar-no-fork + + + + + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${maven-javadoc-plugin.version} + + + + attach-javadocs + + jar + + + + + + + + + + org.apache.maven.plugins + maven-gpg-plugin + ${maven-gpg-plugin.version} + + + sign-artifacts + verify + + + sign + + + + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + ${maven-assembly-plugin.version} + + + source-release-assembly + package + + single + + + + true + + ${ow2SourceAssemblyDescriptorRef} + + + gnu + + + + + + org.ow2 + maven-source-assemblies + ${maven-source-assemblies.version} + + + + + + + + + + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/org.sonatype.oss/oss-parent/7/46b8a785b60a2767095b8611613b58577e96d4c9/oss-parent-7.pom b/.gradle-user/caches/modules-2/files-2.1/org.sonatype.oss/oss-parent/7/46b8a785b60a2767095b8611613b58577e96d4c9/oss-parent-7.pom new file mode 100644 index 0000000..3963952 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.sonatype.oss/oss-parent/7/46b8a785b60a2767095b8611613b58577e96d4c9/oss-parent-7.pom @@ -0,0 +1,155 @@ + + + + 4.0.0 + + org.sonatype.oss + oss-parent + 7 + pom + + Sonatype OSS Parent + http://nexus.sonatype.org/oss-repository-hosting.html + Sonatype helps open source projects to set up Maven repositories on https://oss.sonatype.org/ + + + scm:svn:http://svn.sonatype.org/spice/tags/oss-parent-7 + scm:svn:https://svn.sonatype.org/spice/tags/oss-parent-7 + http://svn.sonatype.org/spice/tags/oss-parent-7 + + + + + sonatype-nexus-snapshots + Sonatype Nexus Snapshots + https://oss.sonatype.org/content/repositories/snapshots + + false + + + true + + + + + + + + sonatype-nexus-snapshots + Sonatype Nexus Snapshots + ${sonatypeOssDistMgmtSnapshotsUrl} + + + sonatype-nexus-staging + Nexus Release Repository + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + + + + + + org.apache.maven.plugins + maven-enforcer-plugin + 1.0 + + + enforce-maven + + enforce + + + + + (,2.1.0),(2.1.0,2.2.0),(2.2.0,) + Maven 2.1.0 and 2.2.0 produce incorrect GPG signatures and checksums respectively. + + + + + + + + + + + org.apache.maven.plugins + maven-release-plugin + 2.1 + + forked-path + false + -Psonatype-oss-release + + + + + + + + UTF-8 + https://oss.sonatype.org/content/repositories/snapshots/ + + + + + sonatype-oss-release + + + + org.apache.maven.plugins + maven-source-plugin + 2.1.2 + + + attach-sources + + jar-no-fork + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.7 + + + attach-javadocs + + jar + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.1 + + + sign-artifacts + verify + + sign + + + + + + + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/org.sonatype.oss/oss-parent/9/e5cdc4d23b86d79c436f16fed20853284e868f65/oss-parent-9.pom b/.gradle-user/caches/modules-2/files-2.1/org.sonatype.oss/oss-parent/9/e5cdc4d23b86d79c436f16fed20853284e868f65/oss-parent-9.pom new file mode 100644 index 0000000..cc10b98 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.sonatype.oss/oss-parent/9/e5cdc4d23b86d79c436f16fed20853284e868f65/oss-parent-9.pom @@ -0,0 +1,156 @@ + + + + 4.0.0 + + org.sonatype.oss + oss-parent + 9 + pom + + Sonatype OSS Parent + http://nexus.sonatype.org/oss-repository-hosting.html + Sonatype helps open source projects to set up Maven repositories on https://oss.sonatype.org/ + + + scm:svn:http://svn.sonatype.org/spice/trunk/oss/oss-parenti-9 + scm:svn:https://svn.sonatype.org/spice/trunk/oss/oss-parent-9 + http://svn.sonatype.org/spice/trunk/oss/oss-parent-9 + + + + + sonatype-nexus-snapshots + Sonatype Nexus Snapshots + https://oss.sonatype.org/content/repositories/snapshots + + false + + + true + + + + + + + + sonatype-nexus-snapshots + Sonatype Nexus Snapshots + ${sonatypeOssDistMgmtSnapshotsUrl} + + + sonatype-nexus-staging + Nexus Release Repository + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + + + + + + org.apache.maven.plugins + maven-enforcer-plugin + 1.2 + + + enforce-maven + + enforce + + + + + (,2.1.0),(2.1.0,2.2.0),(2.2.0,) + Maven 2.1.0 and 2.2.0 produce incorrect GPG signatures and checksums respectively. + + + + + + + + + + + org.apache.maven.plugins + maven-release-plugin + 2.1 + + forked-path + false + ${arguments} -Psonatype-oss-release + + + + + + + + UTF-8 + https://oss.sonatype.org/content/repositories/snapshots/ + + + + + + sonatype-oss-release + + + + org.apache.maven.plugins + maven-source-plugin + 2.1.2 + + + attach-sources + + jar-no-fork + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.7 + + + attach-javadocs + + jar + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.1 + + + sign-artifacts + verify + + sign + + + + + + + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/org.springframework/spring-framework-bom/5.3.39/2af3c8b0a5c42c87c784c84eb50ab3bed4d99b4b/spring-framework-bom-5.3.39.module b/.gradle-user/caches/modules-2/files-2.1/org.springframework/spring-framework-bom/5.3.39/2af3c8b0a5c42c87c784c84eb50ab3bed4d99b4b/spring-framework-bom-5.3.39.module new file mode 100644 index 0000000..dae4d50 --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.springframework/spring-framework-bom/5.3.39/2af3c8b0a5c42c87c784c84eb50ab3bed4d99b4b/spring-framework-bom-5.3.39.module @@ -0,0 +1,344 @@ +{ + "formatVersion": "1.1", + "component": { + "group": "org.springframework", + "module": "spring-framework-bom", + "version": "5.3.39", + "attributes": { + "org.gradle.status": "release" + } + }, + "createdBy": { + "gradle": { + "version": "7.5.1" + } + }, + "variants": [ + { + "name": "apiElements", + "attributes": { + "org.gradle.category": "platform", + "org.gradle.usage": "java-api" + }, + "dependencyConstraints": [ + { + "group": "org.springframework", + "module": "spring-aop", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-aspects", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-beans", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-context", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-context-indexer", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-context-support", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-core", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-expression", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-instrument", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-jcl", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-jdbc", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-jms", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-messaging", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-orm", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-oxm", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-r2dbc", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-test", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-tx", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-web", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-webflux", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-webmvc", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-websocket", + "version": { + "requires": "5.3.39" + } + } + ] + }, + { + "name": "runtimeElements", + "attributes": { + "org.gradle.category": "platform", + "org.gradle.usage": "java-runtime" + }, + "dependencyConstraints": [ + { + "group": "org.springframework", + "module": "spring-aop", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-aspects", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-beans", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-context", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-context-indexer", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-context-support", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-core", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-expression", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-instrument", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-jcl", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-jdbc", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-jms", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-messaging", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-orm", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-oxm", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-r2dbc", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-test", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-tx", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-web", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-webflux", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-webmvc", + "version": { + "requires": "5.3.39" + } + }, + { + "group": "org.springframework", + "module": "spring-websocket", + "version": { + "requires": "5.3.39" + } + } + ] + } + ] +} diff --git a/.gradle-user/caches/modules-2/files-2.1/org.springframework/spring-framework-bom/5.3.39/51d5e26004c5cd98c1d0bd562e0579f18e6552e8/spring-framework-bom-5.3.39.pom b/.gradle-user/caches/modules-2/files-2.1/org.springframework/spring-framework-bom/5.3.39/51d5e26004c5cd98c1d0bd562e0579f18e6552e8/spring-framework-bom-5.3.39.pom new file mode 100644 index 0000000..31b965a --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.springframework/spring-framework-bom/5.3.39/51d5e26004c5cd98c1d0bd562e0579f18e6552e8/spring-framework-bom-5.3.39.pom @@ -0,0 +1,157 @@ + + + + + + + + 4.0.0 + org.springframework + spring-framework-bom + 5.3.39 + pom + Spring Framework (Bill of Materials) + Spring Framework (Bill of Materials) + https://github.com/spring-projects/spring-framework + + Spring IO + https://spring.io/projects/spring-framework + + + + Apache License, Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0 + repo + + + + + jhoeller + Juergen Hoeller + jhoeller@pivotal.io + + + + scm:git:git://github.com/spring-projects/spring-framework + scm:git:git://github.com/spring-projects/spring-framework + https://github.com/spring-projects/spring-framework + + + GitHub + https://github.com/spring-projects/spring-framework/issues + + + + + org.springframework + spring-aop + 5.3.39 + + + org.springframework + spring-aspects + 5.3.39 + + + org.springframework + spring-beans + 5.3.39 + + + org.springframework + spring-context + 5.3.39 + + + org.springframework + spring-context-indexer + 5.3.39 + + + org.springframework + spring-context-support + 5.3.39 + + + org.springframework + spring-core + 5.3.39 + + + org.springframework + spring-expression + 5.3.39 + + + org.springframework + spring-instrument + 5.3.39 + + + org.springframework + spring-jcl + 5.3.39 + + + org.springframework + spring-jdbc + 5.3.39 + + + org.springframework + spring-jms + 5.3.39 + + + org.springframework + spring-messaging + 5.3.39 + + + org.springframework + spring-orm + 5.3.39 + + + org.springframework + spring-oxm + 5.3.39 + + + org.springframework + spring-r2dbc + 5.3.39 + + + org.springframework + spring-test + 5.3.39 + + + org.springframework + spring-tx + 5.3.39 + + + org.springframework + spring-web + 5.3.39 + + + org.springframework + spring-webflux + 5.3.39 + + + org.springframework + spring-webmvc + 5.3.39 + + + org.springframework + spring-websocket + 5.3.39 + + + + diff --git a/.gradle-user/caches/modules-2/files-2.1/org.vafer/jdependency/2.12/a380760266ea2c5bb405474a4cf222257fa86161/jdependency-2.12.pom b/.gradle-user/caches/modules-2/files-2.1/org.vafer/jdependency/2.12/a380760266ea2c5bb405474a4cf222257fa86161/jdependency-2.12.pom new file mode 100644 index 0000000..ddab3de --- /dev/null +++ b/.gradle-user/caches/modules-2/files-2.1/org.vafer/jdependency/2.12/a380760266ea2c5bb405474a4cf222257fa86161/jdependency-2.12.pom @@ -0,0 +1,413 @@ + + + 4.0.0 + org.vafer + jdependency + jdependency + 2.12 + This project provides an API to analyse class dependencies + http://github.com/tcurdt/jdependency + + + tcurdt + Torsten Curdt + tcurdt@apache.org + + Lead Developer + + +1 + + + krosenvold + Kristian Rosenvold + krosenvold@apache.org + + + + + Niels Basjes + nielsbasjes@apache.org + + + + + Apache License, Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + scm:git:git@github.com:tcurdt/jdependency.git + scm:git:git@github.com:tcurdt/jdependency.git + http://github.com/tcurdt/jdependency + + + + + + maven-enforcer-plugin + 3.5.0 + + + maven-clean-plugin + 3.4.0 + + + maven-resources-plugin + 3.3.1 + + + maven-jar-plugin + 3.4.2 + + + maven-install-plugin + 3.1.3 + + + maven-deploy-plugin + 3.1.3 + + + maven-compiler-plugin + 3.13.0 + + + maven-release-plugin + 3.1.1 + + + maven-antrun-plugin + 3.1.0 + + + maven-surefire-plugin + 3.5.2 + + + org.jacoco + jacoco-maven-plugin + 0.8.12 + + + maven-shade-plugin + 3.6.0 + + + maven-site-plugin + 3.21.0 + + + maven-javadoc-plugin + 3.11.2 + + ${maven.compiler.source} + none + true + + + + maven-project-info-reports-plugin + 3.8.0 + + + maven-surefire-report-plugin + 3.5.2 + + + maven-pmd-plugin + 3.26.0 + + + maven-jxr-plugin + 3.6.0 + + + org.codehaus.mojo + taglist-maven-plugin + 3.2.1 + + + maven-gpg-plugin + 3.2.7 + + + + + + maven-compiler-plugin + + ${maven.compiler.source} + ${maven.compiler.target} + ${maven.compiler.release} + ${project.build.sourceEncoding} + + + + maven-release-plugin + + + maven-shade-plugin + + + package + + shade + + + true + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + + + commons-io:commons-io + org.ow2.asm:asm + org.ow2.asm:asm-analysis + org.ow2.asm:asm-commons + org.ow2.asm:asm-util + org.ow2.asm:asm-tree + + + + + org.apache.commons + org.vafer.jdeb.shaded.commons + + + org.ow2.asm + org.vafer.jdeb.shaded.ow2.asm + + + org.objectweb.asm + org.vafer.jdeb.shaded.objectweb.asm + + + + + + + + maven-surefire-plugin + + + **/*TestCase.java + + + **/Abstract* + + false + ${test.workingDirectory} + + + + org.jacoco + jacoco-maven-plugin + + + agent + + prepare-agent + + + + report + + report + + + + + + maven-enforcer-plugin + + + enforce-maven + + enforce + + + + + [${maven.version},4.0.0) + + + + + + + + maven-antrun-plugin + + + prepare-fs-test-input + process-test-resources + + run + + + + + + + + + + + + + + + + + + + + + + release + + + + maven-source-plugin + 3.3.1 + + + attach-sources + + jar-no-fork + + + + + + maven-javadoc-plugin + 3.11.2 + + + attach-javadocs + + jar + + + + + + maven-gpg-plugin + 3.2.7 + + + sign-artifacts + verify + + sign + + + + + + --pinentry-mode + loopback + + + + + + + + + + junit + junit + 4.13.2 + test + + + hamcrest-core + org.hamcrest + + + + + + true + ${project.build.directory}/site + + + maven-site-plugin + + + maven-javadoc-plugin + + + maven-project-info-reports-plugin + + + + team + dependencies + licenses + scm + + + + + + maven-surefire-report-plugin + + + maven-pmd-plugin + + + maven-jxr-plugin + + + org.codehaus.mojo + taglist-maven-plugin + + + FIXME + TODO + @todo + @deprecated + + true + + + + org.jacoco + jacoco-maven-plugin + + + + report + + + + + + + + + ossrh + https://oss.sonatype.org/service/local/staging/deploy/maven2 + + + + 11 + 3.9.6 + 11 + UTF-8 + 11 + ${project.build.directory}/test-working-directory + 9.7.1 + UTF-8 + + diff --git a/.gradle-user/caches/modules-2/files-2.1/org.vafer/jdependency/2.12/cf3396ee09c7b683f7925d9f84ae0dae0275680/jdependency-2.12.jar b/.gradle-user/caches/modules-2/files-2.1/org.vafer/jdependency/2.12/cf3396ee09c7b683f7925d9f84ae0dae0275680/jdependency-2.12.jar new file mode 100644 index 0000000..54a2199 Binary files /dev/null and b/.gradle-user/caches/modules-2/files-2.1/org.vafer/jdependency/2.12/cf3396ee09c7b683f7925d9f84ae0dae0275680/jdependency-2.12.jar differ diff --git a/.gradle-user/caches/modules-2/gc.properties b/.gradle-user/caches/modules-2/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.android.tools.smali/smali-baksmali/3.0.9/d4e342018b23d58be902a60e67105aa1/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.android.tools.smali/smali-baksmali/3.0.9/d4e342018b23d58be902a60e67105aa1/descriptor.bin new file mode 100644 index 0000000..8d5cf7e Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.android.tools.smali/smali-baksmali/3.0.9/d4e342018b23d58be902a60e67105aa1/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.android.tools.smali/smali-dexlib2/3.0.9/d4e342018b23d58be902a60e67105aa1/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.android.tools.smali/smali-dexlib2/3.0.9/d4e342018b23d58be902a60e67105aa1/descriptor.bin new file mode 100644 index 0000000..b3a096f Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.android.tools.smali/smali-dexlib2/3.0.9/d4e342018b23d58be902a60e67105aa1/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.android.tools.smali/smali-util/3.0.9/d4e342018b23d58be902a60e67105aa1/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.android.tools.smali/smali-util/3.0.9/d4e342018b23d58be902a60e67105aa1/descriptor.bin new file mode 100644 index 0000000..7f33bae Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.android.tools.smali/smali-util/3.0.9/d4e342018b23d58be902a60e67105aa1/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.beust/jcommander/1.64/26c913274550a0b2221f47a0fe2d2358/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.beust/jcommander/1.64/26c913274550a0b2221f47a0fe2d2358/descriptor.bin new file mode 100644 index 0000000..eedee84 Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.beust/jcommander/1.64/26c913274550a0b2221f47a0fe2d2358/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.fasterxml.jackson/jackson-bom/2.17.2/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.fasterxml.jackson/jackson-bom/2.17.2/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..1bb99c7 Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.fasterxml.jackson/jackson-bom/2.17.2/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.fasterxml.jackson/jackson-parent/2.17/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.fasterxml.jackson/jackson-parent/2.17/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..7ed3b67 Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.fasterxml.jackson/jackson-parent/2.17/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.fasterxml.woodstox/woodstox-core/6.5.1/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.fasterxml.woodstox/woodstox-core/6.5.1/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..f519c92 Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.fasterxml.woodstox/woodstox-core/6.5.1/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.fasterxml/oss-parent/38/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.fasterxml/oss-parent/38/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..cc37059 Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.fasterxml/oss-parent/38/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.fasterxml/oss-parent/50/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.fasterxml/oss-parent/50/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..6b5bd90 Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.fasterxml/oss-parent/50/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.fasterxml/oss-parent/58/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.fasterxml/oss-parent/58/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..439ad6f Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.fasterxml/oss-parent/58/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.google.code.findbugs/jsr305/3.0.2/26c913274550a0b2221f47a0fe2d2358/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.google.code.findbugs/jsr305/3.0.2/26c913274550a0b2221f47a0fe2d2358/descriptor.bin new file mode 100644 index 0000000..c32fbae Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.google.code.findbugs/jsr305/3.0.2/26c913274550a0b2221f47a0fe2d2358/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.google.errorprone/error_prone_annotations/2.11.0/26c913274550a0b2221f47a0fe2d2358/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.google.errorprone/error_prone_annotations/2.11.0/26c913274550a0b2221f47a0fe2d2358/descriptor.bin new file mode 100644 index 0000000..fbbf30b Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.google.errorprone/error_prone_annotations/2.11.0/26c913274550a0b2221f47a0fe2d2358/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.google.errorprone/error_prone_parent/2.11.0/26c913274550a0b2221f47a0fe2d2358/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.google.errorprone/error_prone_parent/2.11.0/26c913274550a0b2221f47a0fe2d2358/descriptor.bin new file mode 100644 index 0000000..a0e8b77 Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.google.errorprone/error_prone_parent/2.11.0/26c913274550a0b2221f47a0fe2d2358/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.google.guava/failureaccess/1.0.1/26c913274550a0b2221f47a0fe2d2358/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.google.guava/failureaccess/1.0.1/26c913274550a0b2221f47a0fe2d2358/descriptor.bin new file mode 100644 index 0000000..f097258 Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.google.guava/failureaccess/1.0.1/26c913274550a0b2221f47a0fe2d2358/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.google.guava/guava-parent/26.0-android/26c913274550a0b2221f47a0fe2d2358/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.google.guava/guava-parent/26.0-android/26c913274550a0b2221f47a0fe2d2358/descriptor.bin new file mode 100644 index 0000000..f52b115 Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.google.guava/guava-parent/26.0-android/26c913274550a0b2221f47a0fe2d2358/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.google.guava/guava-parent/31.1-android/26c913274550a0b2221f47a0fe2d2358/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.google.guava/guava-parent/31.1-android/26c913274550a0b2221f47a0fe2d2358/descriptor.bin new file mode 100644 index 0000000..57992ce Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.google.guava/guava-parent/31.1-android/26c913274550a0b2221f47a0fe2d2358/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.google.guava/guava/31.1-android/26c913274550a0b2221f47a0fe2d2358/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.google.guava/guava/31.1-android/26c913274550a0b2221f47a0fe2d2358/descriptor.bin new file mode 100644 index 0000000..80c89df Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.google.guava/guava/31.1-android/26c913274550a0b2221f47a0fe2d2358/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.google.guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/26c913274550a0b2221f47a0fe2d2358/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.google.guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/26c913274550a0b2221f47a0fe2d2358/descriptor.bin new file mode 100644 index 0000000..c63c74d Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.google.guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/26c913274550a0b2221f47a0fe2d2358/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.google.j2objc/j2objc-annotations/1.3/26c913274550a0b2221f47a0fe2d2358/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.google.j2objc/j2objc-annotations/1.3/26c913274550a0b2221f47a0fe2d2358/descriptor.bin new file mode 100644 index 0000000..fd690ba Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.google.j2objc/j2objc-annotations/1.3/26c913274550a0b2221f47a0fe2d2358/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.gradleup.shadow/com.gradleup.shadow.gradle.plugin/8.3.6/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.gradleup.shadow/com.gradleup.shadow.gradle.plugin/8.3.6/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..d29ef81 Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.gradleup.shadow/com.gradleup.shadow.gradle.plugin/8.3.6/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.gradleup.shadow/shadow-gradle-plugin/8.3.6/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.gradleup.shadow/shadow-gradle-plugin/8.3.6/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..bfbd8de Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/com.gradleup.shadow/shadow-gradle-plugin/8.3.6/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/commons-io/commons-io/2.17.0/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/commons-io/commons-io/2.17.0/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..6f119d8 Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/commons-io/commons-io/2.17.0/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/jakarta.platform/jakarta.jakartaee-bom/9.1.0/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/jakarta.platform/jakarta.jakartaee-bom/9.1.0/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..1bf60fc Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/jakarta.platform/jakarta.jakartaee-bom/9.1.0/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/jakarta.platform/jakartaee-api-parent/9.1.0/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/jakarta.platform/jakartaee-api-parent/9.1.0/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..1548d0e Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/jakarta.platform/jakartaee-api-parent/9.1.0/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.ant/ant-launcher/1.10.15/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.ant/ant-launcher/1.10.15/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..56db7db Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.ant/ant-launcher/1.10.15/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.ant/ant-parent/1.10.15/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.ant/ant-parent/1.10.15/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..16b8449 Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.ant/ant-parent/1.10.15/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.ant/ant/1.10.15/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.ant/ant/1.10.15/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..2e4927d Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.ant/ant/1.10.15/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.commons/commons-parent/74/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.commons/commons-parent/74/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..a215c65 Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.commons/commons-parent/74/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.groovy/groovy-bom/4.0.22/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.groovy/groovy-bom/4.0.22/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..45e8cc5 Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.groovy/groovy-bom/4.0.22/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.logging.log4j/log4j-api/2.24.1/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.logging.log4j/log4j-api/2.24.1/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..7541b40 Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.logging.log4j/log4j-api/2.24.1/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.logging.log4j/log4j-bom/2.24.1/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.logging.log4j/log4j-bom/2.24.1/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..0e26b44 Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.logging.log4j/log4j-bom/2.24.1/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.logging.log4j/log4j-core/2.24.1/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.logging.log4j/log4j-core/2.24.1/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..8b13dd3 Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.logging.log4j/log4j-core/2.24.1/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.logging.log4j/log4j/2.24.1/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.logging.log4j/log4j/2.24.1/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..3e35857 Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.logging.log4j/log4j/2.24.1/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.logging/logging-parent/11.3.0/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.logging/logging-parent/11.3.0/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..06297c2 Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.logging/logging-parent/11.3.0/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.maven/maven-api-meta/4.0.0-alpha-9/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.maven/maven-api-meta/4.0.0-alpha-9/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..3a39cda Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.maven/maven-api-meta/4.0.0-alpha-9/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.maven/maven-api-xml/4.0.0-alpha-9/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.maven/maven-api-xml/4.0.0-alpha-9/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..e0f7d1d Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.maven/maven-api-xml/4.0.0-alpha-9/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.maven/maven-api/4.0.0-alpha-9/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.maven/maven-api/4.0.0-alpha-9/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..ae3a3a4 Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.maven/maven-api/4.0.0-alpha-9/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.maven/maven-bom/4.0.0-alpha-9/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.maven/maven-bom/4.0.0-alpha-9/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..a71bb9c Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.maven/maven-bom/4.0.0-alpha-9/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.maven/maven-parent/41/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.maven/maven-parent/41/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..a8882a0 Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.maven/maven-parent/41/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.maven/maven-xml-impl/4.0.0-alpha-9/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.maven/maven-xml-impl/4.0.0-alpha-9/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..e24ab95 Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.maven/maven-xml-impl/4.0.0-alpha-9/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.maven/maven/4.0.0-alpha-9/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.maven/maven/4.0.0-alpha-9/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..c80b85a Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache.maven/maven/4.0.0-alpha-9/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache/apache/31/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache/apache/31/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..cb289a2 Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache/apache/31/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache/apache/33/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache/apache/33/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..1a070a4 Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.apache/apache/33/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.checkerframework/checker-qual/3.12.0/26c913274550a0b2221f47a0fe2d2358/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.checkerframework/checker-qual/3.12.0/26c913274550a0b2221f47a0fe2d2358/descriptor.bin new file mode 100644 index 0000000..6a9e58a Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.checkerframework/checker-qual/3.12.0/26c913274550a0b2221f47a0fe2d2358/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.codehaus.plexus/plexus-utils/4.0.2/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.codehaus.plexus/plexus-utils/4.0.2/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..8108fe7 Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.codehaus.plexus/plexus-utils/4.0.2/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.codehaus.plexus/plexus-xml/4.0.4/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.codehaus.plexus/plexus-xml/4.0.4/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..0e9e5f4 Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.codehaus.plexus/plexus-xml/4.0.4/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.codehaus.plexus/plexus/18/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.codehaus.plexus/plexus/18/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..5ad8213 Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.codehaus.plexus/plexus/18/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.codehaus.woodstox/stax2-api/4.2.1/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.codehaus.woodstox/stax2-api/4.2.1/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..be4ed6d Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.codehaus.woodstox/stax2-api/4.2.1/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.eclipse.ee4j/project/1.0.7/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.eclipse.ee4j/project/1.0.7/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..910434a Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.eclipse.ee4j/project/1.0.7/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.jdom/jdom2/2.0.6.1/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.jdom/jdom2/2.0.6.1/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..f49f70a Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.jdom/jdom2/2.0.6.1/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.junit/junit-bom/5.10.1/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.junit/junit-bom/5.10.1/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..38f5ce2 Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.junit/junit-bom/5.10.1/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.junit/junit-bom/5.10.2/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.junit/junit-bom/5.10.2/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..3305dba Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.junit/junit-bom/5.10.2/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.junit/junit-bom/5.10.3/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.junit/junit-bom/5.10.3/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..4cc90a4 Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.junit/junit-bom/5.10.3/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.junit/junit-bom/5.11.0/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.junit/junit-bom/5.11.0/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..9ae2c12 Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.junit/junit-bom/5.11.0/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.mockito/mockito-bom/4.11.0/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.mockito/mockito-bom/4.11.0/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..7b7328d Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.mockito/mockito-bom/4.11.0/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.mockito/mockito-bom/5.7.0/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.mockito/mockito-bom/5.7.0/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..cf510bc Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.mockito/mockito-bom/5.7.0/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.ow2.asm/asm-commons/9.7.1/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.ow2.asm/asm-commons/9.7.1/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..560e024 Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.ow2.asm/asm-commons/9.7.1/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.ow2.asm/asm-tree/9.7.1/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.ow2.asm/asm-tree/9.7.1/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..d9ac474 Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.ow2.asm/asm-tree/9.7.1/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.ow2.asm/asm/9.7.1/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.ow2.asm/asm/9.7.1/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..0ac8dc2 Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.ow2.asm/asm/9.7.1/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.ow2/ow2/1.5.1/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.ow2/ow2/1.5.1/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..086f046 Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.ow2/ow2/1.5.1/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.sonatype.oss/oss-parent/7/26c913274550a0b2221f47a0fe2d2358/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.sonatype.oss/oss-parent/7/26c913274550a0b2221f47a0fe2d2358/descriptor.bin new file mode 100644 index 0000000..0deca58 Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.sonatype.oss/oss-parent/7/26c913274550a0b2221f47a0fe2d2358/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.sonatype.oss/oss-parent/9/26c913274550a0b2221f47a0fe2d2358/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.sonatype.oss/oss-parent/9/26c913274550a0b2221f47a0fe2d2358/descriptor.bin new file mode 100644 index 0000000..940de23 Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.sonatype.oss/oss-parent/9/26c913274550a0b2221f47a0fe2d2358/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.springframework/spring-framework-bom/5.3.39/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.springframework/spring-framework-bom/5.3.39/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..925db2e Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.springframework/spring-framework-bom/5.3.39/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.vafer/jdependency/2.12/2f8748e965ecb2135dad092e9ef808de/descriptor.bin b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.vafer/jdependency/2.12/2f8748e965ecb2135dad092e9ef808de/descriptor.bin new file mode 100644 index 0000000..21a943f Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/descriptors/org.vafer/jdependency/2.12/2f8748e965ecb2135dad092e9ef808de/descriptor.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/module-artifact.bin b/.gradle-user/caches/modules-2/metadata-2.107/module-artifact.bin new file mode 100644 index 0000000..ab5ec33 Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/module-artifact.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/module-metadata.bin b/.gradle-user/caches/modules-2/metadata-2.107/module-metadata.bin new file mode 100644 index 0000000..d9dff49 Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/module-metadata.bin differ diff --git a/.gradle-user/caches/modules-2/metadata-2.107/resource-at-url.bin b/.gradle-user/caches/modules-2/metadata-2.107/resource-at-url.bin new file mode 100644 index 0000000..0ab913b Binary files /dev/null and b/.gradle-user/caches/modules-2/metadata-2.107/resource-at-url.bin differ diff --git a/.gradle-user/caches/modules-2/modules-2.lock b/.gradle-user/caches/modules-2/modules-2.lock new file mode 100644 index 0000000..06f77e7 Binary files /dev/null and b/.gradle-user/caches/modules-2/modules-2.lock differ diff --git a/.gradle-user/daemon/9.7.1/daemon-50736.out.log b/.gradle-user/daemon/9.7.1/daemon-50736.out.log new file mode 100644 index 0000000..aa9f67e --- /dev/null +++ b/.gradle-user/daemon/9.7.1/daemon-50736.out.log @@ -0,0 +1,178 @@ +2026-10-16T08:22:41.670-0400 [DEBUG] [org.gradle.launcher.daemon.bootstrap.DaemonMain] Assuming the daemon was started with following jvm opts: [-XX:MaxMetaspaceSize=384m, -XX:+HeapDumpOnOutOfMemoryError, -Xms256m, -Xmx512m, -Dfile.encoding=UTF-8, -Duser.country, -Duser.language=en, -Duser.variant] +2026-10-16T08:22:41.759-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding IP addresses for network interface tailscale0 +2026-10-16T08:22:41.759-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Is this a loopback interface? false +2026-10-16T08:22:41.759-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding remote address /fe80:0:0:0:8d15:7fb2:299f:dced%tailscale0 +2026-10-16T08:22:41.760-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding IP addresses for network interface wlp98s0 +2026-10-16T08:22:41.760-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Is this a loopback interface? false +2026-10-16T08:22:41.760-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding remote address /fe80:0:0:0:6f3f:89e6:b585:4167%wlp98s0 +2026-10-16T08:22:41.760-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding remote address /192.168.27.163 +2026-10-16T08:22:41.760-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding IP addresses for network interface lo +2026-10-16T08:22:41.761-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Is this a loopback interface? true +2026-10-16T08:22:41.761-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding loopback address /0:0:0:0:0:0:0:1%lo +2026-10-16T08:22:41.761-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding loopback address /127.0.0.1 +2026-10-16T08:22:41.790-0400 [INFO] [org.gradle.launcher.daemon.server.Daemon] start() called on daemon - DefaultDaemonContext[uid=45996304-57e5-44c9-8c85-f994c9d3b80d,javaHome=/var/home/hellings/.sdkman/candidates/java/21.0.8-tem,javaVersion=21,javaVendor=Eclipse Adoptium,daemonRegistryDir=/var/home/hellings/Documents/mistring/.gradle-user/daemon,pid=50736,idleTimeout=120000,priority=NORMAL,applyInstrumentationAgent=true,nativeServicesMode=ENABLED,daemonOpts=-XX:MaxMetaspaceSize=384m,-XX:+HeapDumpOnOutOfMemoryError,-Xms256m,-Xmx512m,-Dfile.encoding=UTF-8,-Duser.country,-Duser.language=en,-Duser.variant] +2026-10-16T08:22:41.796-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.TcpIncomingConnector] Listening on [476548f3-7f40-44df-bec3-b73f5c9e6eab port:42397, addresses:[localhost/127.0.0.1]]. +2026-10-16T08:22:41.802-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] Daemon starting at: Fri Oct 16 08:22:41 EDT 2026, with address: [476548f3-7f40-44df-bec3-b73f5c9e6eab port:42397, addresses:[localhost/127.0.0.1]] +2026-10-16T08:22:41.802-0400 [INFO] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Advertising the daemon address to the clients: [476548f3-7f40-44df-bec3-b73f5c9e6eab port:42397, addresses:[localhost/127.0.0.1]] +2026-10-16T08:22:41.803-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Advertised daemon context: DefaultDaemonContext[uid=45996304-57e5-44c9-8c85-f994c9d3b80d,javaHome=/var/home/hellings/.sdkman/candidates/java/21.0.8-tem,javaVersion=21,javaVendor=Eclipse Adoptium,daemonRegistryDir=/var/home/hellings/Documents/mistring/.gradle-user/daemon,pid=50736,idleTimeout=120000,priority=NORMAL,applyInstrumentationAgent=true,nativeServicesMode=ENABLED,daemonOpts=-XX:MaxMetaspaceSize=384m,-XX:+HeapDumpOnOutOfMemoryError,-Xms256m,-Xmx512m,-Dfile.encoding=UTF-8,-Duser.country,-Duser.language=en,-Duser.variant] +2026-10-16T08:22:41.803-0400 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Storing daemon address: [476548f3-7f40-44df-bec3-b73f5c9e6eab port:42397, addresses:[localhost/127.0.0.1]], context: DefaultDaemonContext[uid=45996304-57e5-44c9-8c85-f994c9d3b80d,javaHome=/var/home/hellings/.sdkman/candidates/java/21.0.8-tem,javaVersion=21,javaVendor=Eclipse Adoptium,daemonRegistryDir=/var/home/hellings/Documents/mistring/.gradle-user/daemon,pid=50736,idleTimeout=120000,priority=NORMAL,applyInstrumentationAgent=true,nativeServicesMode=ENABLED,daemonOpts=-XX:MaxMetaspaceSize=384m,-XX:+HeapDumpOnOutOfMemoryError,-Xms256m,-Xmx512m,-Dfile.encoding=UTF-8,-Duser.country,-Duser.language=en,-Duser.variant] +2026-10-16T08:22:41.809-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire exclusive lock on daemon addresses registry. +2026-10-16T08:22:41.819-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired on daemon addresses registry. +2026-10-16T08:22:41.821-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on daemon addresses registry. +2026-10-16T08:22:41.822-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire exclusive lock on daemon addresses registry. +2026-10-16T08:22:41.823-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired on daemon addresses registry. +2026-10-16T08:22:41.825-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on daemon addresses registry. +2026-10-16T08:22:41.825-0400 [LIFECYCLE] [org.gradle.launcher.daemon.server.Daemon] Daemon server started. +2026-10-16T08:22:41.826-0400 [DEBUG] [org.gradle.launcher.daemon.bootstrap.DaemonStartupCommunication] Completed writing the daemon greeting. Closing streams... +2026-10-16T08:22:41.832-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] stopOnExpiration() called on daemon +2026-10-16T08:22:41.833-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] awaitExpiration() called on daemon +2026-10-16T08:22:41.833-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon is running. Sleeping until state changes. +2026-10-16T08:22:41.840-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.TcpIncomingConnector] Accepted connection from /127.0.0.1:55760 to /127.0.0.1:42397. +2026-10-16T08:22:41.859-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 40: received class org.gradle.launcher.daemon.protocol.Build +2026-10-16T08:22:41.860-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultDaemonConnection] thread 40: Received non-IO message from client: Build{id=eb065153-8009-4195-a76d-f7d1255e2e41, currentDir=/var/home/hellings/Documents/mistring} +2026-10-16T08:22:41.860-0400 [INFO] [org.gradle.launcher.daemon.server.DefaultIncomingConnectionHandler] Received command: Build{id=eb065153-8009-4195-a76d-f7d1255e2e41, currentDir=/var/home/hellings/Documents/mistring}. +2026-10-16T08:22:41.861-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultIncomingConnectionHandler] Starting executing command: Build{id=eb065153-8009-4195-a76d-f7d1255e2e41, currentDir=/var/home/hellings/Documents/mistring} with connection: socket connection from /127.0.0.1:42397 to /127.0.0.1:55760. +2026-10-16T08:22:41.862-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Command execution: started DaemonCommandExecution[command = Build{id=eb065153-8009-4195-a76d-f7d1255e2e41, currentDir=/var/home/hellings/Documents/mistring}, connection = DefaultDaemonConnection: socket connection from /127.0.0.1:42397 to /127.0.0.1:55760] after 0.0011500000000000002 minutes of idle +2026-10-16T08:22:41.862-0400 [INFO] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Marking the daemon as busy, address: [476548f3-7f40-44df-bec3-b73f5c9e6eab port:42397, addresses:[localhost/127.0.0.1]] +2026-10-16T08:22:41.863-0400 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Marking busy by address: [476548f3-7f40-44df-bec3-b73f5c9e6eab port:42397, addresses:[localhost/127.0.0.1]] +2026-10-16T08:22:41.863-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire exclusive lock on daemon addresses registry. +2026-10-16T08:22:41.864-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired on daemon addresses registry. +2026-10-16T08:22:41.865-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on daemon addresses registry. +2026-10-16T08:22:41.865-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] resetting idle timer +2026-10-16T08:22:41.865-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon is running. Sleeping until state changes. +2026-10-16T08:22:41.866-0400 [INFO] [org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy] Daemon is about to start building Build{id=eb065153-8009-4195-a76d-f7d1255e2e41, currentDir=/var/home/hellings/Documents/mistring}. Dispatching build started information... +2026-10-16T08:22:41.866-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 42: dispatching org.gradle.launcher.daemon.protocol.BuildStarted@4a415b90 +2026-10-16T08:22:41.868-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.LogToClient] About to start relaying all logs to the client via the connection. +2026-10-16T08:22:41.868-0400 [INFO] [org.gradle.launcher.daemon.server.exec.LogToClient] The client will now receive all logging from the daemon (pid: 50736). The daemon log file: /var/home/hellings/Documents/mistring/.gradle-user/daemon/9.7.1/daemon-50736.out.log +2026-10-16T08:22:41.868-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.ApplyClientEnvironmentVariables] Configuring env variables: [container, PYENV_SHELL, PATH, GNOME_SHELL_SLOWDOWN_FACTOR, HISTCONTROL, XMODIFIERS, GDMSESSION, GUESTFISH_RESTORE, DBUS_SESSION_BUS_ADDRESS, ANDROID_HOME, XDG_CACHE_HOME, GH_PAGER, LD_LIBRARY_PATH, COLORTERM, SDKMAN_DIR, USERNAME, PWD, MANAGERPID, SDKMAN_BROKER_API, GJS_DEBUG_TOPICS, NVM_CD_FLAGS, LESSOPEN, CHROME_DESKTOP, PAGER, SDKMAN_CANDIDATES_API, GUESTFISH_INIT, DEBUGINFOD_IMA_CERT_PATH, LC_ALL, ZSH_TMUX_AUTOSTARTED, LC_CTYPE, GNOME_SETUP_DISPLAY, CODEX_SESSION_ID, SHLVL, QT_IM_MODULES, HISTSIZE, JAVA_HOME, KOTLIN_HOME, MEMORY_PRESSURE_WATCH, RUST_LOG, TERM, XDG_CONFIG_DIRS, MOZ_GMP_PATH, GRADLE_HOME, NVM_INC, GRADLE_USER_HOME, WAYLAND_DISPLAY, STARSHIP_SHELL, CODEX_THREAD_ID, XDG_SESSION_CLASS, DISABLE_AUTO_UPDATE, SWIFTLY_HOME_DIR, DESKTOP_SESSION, XDG_MENU_PREFIX, ZSH_TMUX_AUTOSTART, NVM_BIN, CONTAINER_ID, INVOCATION_ID, XAUTHORITY, XDG_DATA_DIRS, GIT_PAGER, CODEX_MCP_NODE_PATH, CODEX_SHELL, XDG_CURRENT_DESKTOP, JOURNAL_STREAM, MAIL, XDG_STATE_HOME, CODEX_APP_TOOLS_PIPE_PATH, MANAGERPIDFDID, LOGNAME, SWIFTLY_BIN_DIR, PYENV_VIRTUALENV_INIT, CODEX_INTERNAL_ORIGINATOR_OVERRIDE, CODEX_SAGE_BACKFILL_TRACKER_TAB_REUSE, CODEX_SANDBOX_NETWORK_DISABLED, SHELL, GIO_LAUNCHED_DESKTOP_FILE, PYENV_ROOT, CODEX_PERMISSION_PROFILE, LOG_FORMAT, SSH_ASKPASS, DEBUGINFOD_URLS, SYSTEMD_EXEC_PID, XDG_SESSION_DESKTOP, MEMORY_PRESSURE_WRITE, DOCKER_HOST, QT_IM_MODULE, STARSHIP_SESSION_KEY, XDG_SESSION_EXTRA_DEVICE_ACCESS, LANG, EGL_PLATFORM, XDG_SESSION_TYPE, DISPLAY, FC_FONTATIONS, NO_COLOR, SDKMAN_CANDIDATES_DIR, CODEX_CI, GDM_LANG, NVM_DIR, XDG_DATA_HOME, GUESTFISH_PS1, SWIFTLY_TOOLCHAINS_DIR, GDK_BACKEND, FREETOKEN_FT_BIN, GPG_TTY, SDKMAN_PLATFORM, USER, XDG_CONFIG_HOME, GIO_LAUNCHED_DESKTOP_FILE_PID, GJS_DEBUG_OUTPUT, SSH_AUTH_SOCK, EDITOR, HOSTNAME, DISTROBOX_ENTER_PATH, NO_AT_BRIDGE, XDG_RUNTIME_DIR, HOME, TERMINFO_DIRS, GUESTFISH_OUTPUT] +2026-10-16T08:22:41.872-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon] Requesting daemon stop after processing Build{id=eb065153-8009-4195-a76d-f7d1255e2e41, currentDir=/var/home/hellings/Documents/mistring} +2026-10-16T08:22:41.872-0400 [LIFECYCLE] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Daemon will be stopped at the end of the build +2026-10-16T08:22:41.873-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Stop as soon as idle requested. The daemon is busy +2026-10-16T08:22:41.873-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon stop has been requested. Sleeping until state changes. +2026-10-16T08:22:41.876-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.ExecuteBuild] The daemon has started executing the build. +2026-10-16T08:22:41.877-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.ExecuteBuild] Executing build with daemon context: DefaultDaemonContext[uid=45996304-57e5-44c9-8c85-f994c9d3b80d,javaHome=/var/home/hellings/.sdkman/candidates/java/21.0.8-tem,javaVersion=21,javaVendor=Eclipse Adoptium,daemonRegistryDir=/var/home/hellings/Documents/mistring/.gradle-user/daemon,pid=50736,idleTimeout=120000,priority=NORMAL,applyInstrumentationAgent=true,nativeServicesMode=ENABLED,daemonOpts=-XX:MaxMetaspaceSize=384m,-XX:+HeapDumpOnOutOfMemoryError,-Xms256m,-Xmx512m,-Dfile.encoding=UTF-8,-Duser.country,-Duser.language=en,-Duser.variant] +Calculating task graph as no cached configuration is available for tasks: :moannotes-native:build + +1 problem was found storing the configuration cache. +- Task `:moannotes-native:test` of type `org.gradle.api.tasks.testing.Test`: error writing value of type 'org.gradle.api.internal.file.collections.DefaultConfigurableFileCollection' + +See the complete report at file:///var/home/hellings/Documents/mistring/build/reports/configuration-cache/6vuan8h7oz0hqw59df6z5jysz/9agq55k5vujz0c7eg3j7ukc2/configuration-cache-report.html + +[Incubating] Problems report is available at: file:///var/home/hellings/Documents/mistring/build/reports/problems/problems-report.html + +FAILURE: Build failed with an exception. + +* What went wrong: +Configuration cache state could not be cached: field `classpath` of task `:moannotes-native:test` of type `org.gradle.api.tasks.testing.Test`: error writing value of type 'org.gradle.api.internal.file.collections.DefaultConfigurableFileCollection' +> Could not resolve all files for configuration ':moannotes-native:testRuntimeClasspath'. + > Cannot resolve external dependency com.android.tools.smali:smali-baksmali:3.0.9 because no repositories are defined. + Required by: + project ':moannotes-native' + +* Try: +> Run with --stacktrace option to get the stack trace. +> Run with --info or --debug option to get more log output. +> Run with --scan to get full insights from a Build Scan (powered by Develocity). +> Get more help at https://help.gradle.org. + +BUILD FAILED in 13s +Configuration cache entry discarded due to serialization error. +2026-10-16T08:22:54.027-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.ExecuteBuild] The daemon has finished executing the build. +2026-10-16T08:22:54.037-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon stop has been requested. Sleeping until state changes. +2026-10-16T08:22:54.038-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Command execution: finished waiting for DaemonCommandExecution[command = Build{id=eb065153-8009-4195-a76d-f7d1255e2e41, currentDir=/var/home/hellings/Documents/mistring}, connection = DefaultDaemonConnection: socket connection from /127.0.0.1:42397 to /127.0.0.1:55760]. Result org.gradle.launcher.daemon.server.DaemonStateCoordinator@6a0ae54a with state StopRequested +2026-10-16T08:22:54.038-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Command execution: completed DaemonCommandExecution[command = Build{id=eb065153-8009-4195-a76d-f7d1255e2e41, currentDir=/var/home/hellings/Documents/mistring}, connection = DefaultDaemonConnection: socket connection from /127.0.0.1:42397 to /127.0.0.1:55760] +2026-10-16T08:22:54.039-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] resetting idle timer +2026-10-16T08:22:54.039-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Marking daemon stopped due to command completed and stop requested. The daemon is not running a build +2026-10-16T08:22:54.039-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon has stopped. +2026-10-16T08:22:54.039-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.ReturnResult] Daemon is dispatching the build result: Success[value=org.gradle.launcher.exec.BuildActionResult@7b03b3b2] +2026-10-16T08:22:54.039-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 39: dispatching Success[value=org.gradle.launcher.exec.BuildActionResult@7b03b3b2] +2026-10-16T08:22:54.039-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] stop() called on daemon +2026-10-16T08:22:54.039-0400 [INFO] [org.gradle.launcher.daemon.server.Daemon] Stop requested. Daemon is removing its presence from the registry... +2026-10-16T08:22:54.040-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Removing our presence to clients, eg. removing this address from the registry: [476548f3-7f40-44df-bec3-b73f5c9e6eab port:42397, addresses:[localhost/127.0.0.1]] +2026-10-16T08:22:54.040-0400 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Removing daemon address: [476548f3-7f40-44df-bec3-b73f5c9e6eab port:42397, addresses:[localhost/127.0.0.1]] +2026-10-16T08:22:54.040-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire exclusive lock on daemon addresses registry. +2026-10-16T08:22:54.040-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired on daemon addresses registry. +2026-10-16T08:22:54.041-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on daemon addresses registry. +2026-10-16T08:22:54.041-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Address removed from registry. +2026-10-16T08:22:54.044-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.CleanUpVirtualFileSystemAfterBuild] Cleaning virtual file system after build finished +2026-10-16T08:22:54.045-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultIncomingConnectionHandler] Finishing executing command: Build{id=eb065153-8009-4195-a76d-f7d1255e2e41, currentDir=/var/home/hellings/Documents/mistring} +2026-10-16T08:22:54.068-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 40: received class org.gradle.launcher.daemon.protocol.CloseInput +2026-10-16T08:22:54.068-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultDaemonConnection] thread 40: Received IO message from client: org.gradle.launcher.daemon.protocol.CloseInput@3b2b24ae +2026-10-16T08:22:54.110-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 40: received class org.gradle.launcher.daemon.protocol.Finished +2026-10-16T08:22:54.110-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultDaemonConnection] thread 40: Received non-IO message from client: org.gradle.launcher.daemon.protocol.Finished@5fdae8a +2026-10-16T08:22:54.111-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultIncomingConnectionHandler] Received finished message: org.gradle.launcher.daemon.protocol.Finished@5fdae8a +2026-10-16T08:22:54.111-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 39: stopping connection +2026-10-16T08:22:54.111-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.SocketConnection] Discarding EOFException: java.io.EOFException +2026-10-16T08:22:54.111-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 40: received null +2026-10-16T08:22:54.112-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultDaemonConnection] thread 40: Received end-of-input from client. +2026-10-16T08:22:54.112-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 39: stopping connection +2026-10-16T08:22:54.113-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for jars (/var/home/hellings/Documents/mistring/.gradle-user/caches/jars-9) +2026-10-16T08:22:54.113-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on jars (/var/home/hellings/Documents/mistring/.gradle-user/caches/jars-9). +2026-10-16T08:22:54.113-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for file content cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileContent) +2026-10-16T08:22:54.114-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on file content cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileContent). +2026-10-16T08:22:54.114-0400 [DEBUG] [org.gradle.internal.watch.vfs.impl.WatchingVirtualFileSystem] Closing VFS, dropping state +2026-10-16T08:22:54.115-0400 [DEBUG] [org.gradle.internal.watch.registry.impl.DefaultFileWatcherRegistry] Finished listening to file system change events +2026-10-16T08:22:54.115-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCoordinator] Cache Generated Gradle JARs cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/generated-gradle-jars) was closed 0 times. +2026-10-16T08:22:54.115-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for artifact cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2) +2026-10-16T08:22:54.115-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache module-artifact.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2/metadata-2.107/module-artifact.bin) +2026-10-16T08:22:54.121-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache module-metadata.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2/metadata-2.107/module-metadata.bin) +2026-10-16T08:22:54.121-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache resource-at-url.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2/metadata-2.107/resource-at-url.bin) +2026-10-16T08:22:54.122-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on artifact cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2). +2026-10-16T08:22:54.122-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for journal cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/journal-1) +2026-10-16T08:22:54.122-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache file-access.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/journal-1/file-access.bin) +2026-10-16T08:22:54.122-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on journal cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/journal-1). +2026-10-16T08:22:54.123-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for file hash cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileHashes) +2026-10-16T08:22:54.123-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache fileHashes.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileHashes/fileHashes.bin) +2026-10-16T08:22:54.123-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache resourceHashesCache.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileHashes/resourceHashesCache.bin) +2026-10-16T08:22:54.123-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on file hash cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileHashes). +2026-10-16T08:22:54.124-0400 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationRunner] Build operation 'Deleting unused version-specific caches in /var/home/hellings/Documents/mistring/.gradle-user/caches' started +2026-10-16T08:22:54.128-0400 [DEBUG] [org.gradle.cache.internal.VersionSpecificCacheCleanupAction] Processed version-specific caches at /var/home/hellings/Documents/mistring/.gradle-user/caches for cleanup in 0.004 secs +2026-10-16T08:22:54.128-0400 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationRunner] Completing Build operation 'Deleting unused version-specific caches in /var/home/hellings/Documents/mistring/.gradle-user/caches' +2026-10-16T08:22:54.128-0400 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationRunner] Build operation 'Deleting unused version-specific caches in /var/home/hellings/Documents/mistring/.gradle-user/caches' completed +2026-10-16T08:22:54.129-0400 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationRunner] Build operation 'Deleting unused Gradle distributions in /var/home/hellings/Documents/mistring/.gradle-user/wrapper/dists' started +2026-10-16T08:22:54.129-0400 [DEBUG] [org.gradle.cache.internal.WrapperDistributionCleanupAction] Could not determine Gradle version for /var/home/hellings/Documents/mistring/.gradle-user/wrapper/dists/gradle-9.7.1-bin/1w1c7tv4s851m17nbqdsro2tv: A Gradle distribution must contain exactly one subdirectory: [] (java.lang.IllegalArgumentException) +2026-10-16T08:22:54.129-0400 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationRunner] Completing Build operation 'Deleting unused Gradle distributions in /var/home/hellings/Documents/mistring/.gradle-user/wrapper/dists' +2026-10-16T08:22:54.129-0400 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationRunner] Build operation 'Deleting unused Gradle distributions in /var/home/hellings/Documents/mistring/.gradle-user/wrapper/dists' completed +2026-10-16T08:22:54.130-0400 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationRunner] Build operation 'Deleting old daemon log files in /var/home/hellings/Documents/mistring/.gradle-user/daemon' started +2026-10-16T08:22:54.130-0400 [DEBUG] [org.gradle.cache.internal.DaemonLogCleanupAction] Processed daemon logs at /var/home/hellings/Documents/mistring/.gradle-user/daemon for cleanup in 0.0 secs +2026-10-16T08:22:54.130-0400 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationRunner] Completing Build operation 'Deleting old daemon log files in /var/home/hellings/Documents/mistring/.gradle-user/daemon' +2026-10-16T08:22:54.130-0400 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationRunner] Build operation 'Deleting old daemon log files in /var/home/hellings/Documents/mistring/.gradle-user/daemon' completed +2026-10-16T08:22:54.130-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] stop() called on daemon +2026-10-16T08:22:54.130-0400 [INFO] [org.gradle.launcher.daemon.server.Daemon] Stop requested. Daemon is removing its presence from the registry... +2026-10-16T08:22:54.130-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Removing our presence to clients, eg. removing this address from the registry: [476548f3-7f40-44df-bec3-b73f5c9e6eab port:42397, addresses:[localhost/127.0.0.1]] +2026-10-16T08:22:54.130-0400 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Removing daemon address: [476548f3-7f40-44df-bec3-b73f5c9e6eab port:42397, addresses:[localhost/127.0.0.1]] +2026-10-16T08:22:54.131-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire exclusive lock on daemon addresses registry. +2026-10-16T08:22:54.131-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired on daemon addresses registry. +2026-10-16T08:22:54.131-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on daemon addresses registry. +2026-10-16T08:22:54.131-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Address removed from registry. +2026-10-16T08:22:54.132-0400 [DEBUG] [org.gradle.cache.internal.locklistener.DefaultFileLockContentionHandler] File lock listener thread completed. +2026-10-16T08:22:54.133-0400 [DEBUG] [java.lang.Runtime] Runtime.exit() called with status: 0 +java.lang.Throwable: Runtime.exit(0) + at java.base/java.lang.Shutdown.logRuntimeExit(Shutdown.java:179) + at java.base/java.lang.Shutdown.exit(Shutdown.java:160) + at java.base/java.lang.Runtime.exit(Runtime.java:188) + at java.base/java.lang.System.exit(System.java:1920) + at org.gradle.launcher.bootstrap.ProcessCompleter.complete(ProcessCompleter.java:21) + at org.gradle.launcher.bootstrap.EntryPoint.run(EntryPoint.java:62) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.gradle.launcher.bootstrap.ProcessBootstrap.runNoExit(ProcessBootstrap.java:72) + at org.gradle.launcher.bootstrap.ProcessBootstrap.run(ProcessBootstrap.java:39) + at org.gradle.launcher.daemon.bootstrap.GradleDaemon.main(GradleDaemon.java:23) +Daemon vm is shutting down... The daemon has exited normally or was terminated in response to a user interrupt. +2026-10-16T08:22:54.133-0400 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Removing daemon address: [476548f3-7f40-44df-bec3-b73f5c9e6eab port:42397, addresses:[localhost/127.0.0.1]] +2026-10-16T08:22:54.134-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] VM shutdown hook was unable to remove the daemon address from the registry. It will be cleaned up later. +java.lang.IllegalStateException: Cannot start managing file contention because this handler has been closed. + at org.gradle.cache.internal.locklistener.DefaultFileLockContentionHandler.assertNotStopped(DefaultFileLockContentionHandler.java:267) + at org.gradle.cache.internal.locklistener.DefaultFileLockContentionHandler.reservePort(DefaultFileLockContentionHandler.java:312) + at org.gradle.cache.internal.DefaultFileLockManager.lock(DefaultFileLockManager.java:127) + at org.gradle.cache.internal.DefaultFileLockManager.lock(DefaultFileLockManager.java:109) + at org.gradle.cache.internal.DefaultFileLockManager.lock(DefaultFileLockManager.java:104) + at org.gradle.cache.internal.OnDemandFileAccess.updateFile(OnDemandFileAccess.java:51) + at org.gradle.cache.internal.FileBackedObjectHolder.update(FileBackedObjectHolder.java:77) + at org.gradle.cache.internal.FileIntegrityViolationSuppressingObjectHolderDecorator.lambda$update$0(FileIntegrityViolationSuppressingObjectHolderDecorator.java:48) + at org.gradle.cache.internal.FileIntegrityViolationSuppressingObjectHolderDecorator.doUpdate(FileIntegrityViolationSuppressingObjectHolderDecorator.java:58) + at org.gradle.cache.internal.FileIntegrityViolationSuppressingObjectHolderDecorator.update(FileIntegrityViolationSuppressingObjectHolderDecorator.java:48) + at org.gradle.launcher.daemon.registry.PersistentDaemonRegistry.remove(PersistentDaemonRegistry.java:133) + at org.gradle.launcher.daemon.server.Daemon$1.run(Daemon.java:133) + at java.base/java.lang.Thread.run(Thread.java:1583) diff --git a/.gradle-user/daemon/9.7.1/daemon-53566.out.log b/.gradle-user/daemon/9.7.1/daemon-53566.out.log new file mode 100644 index 0000000..e9ff1b0 --- /dev/null +++ b/.gradle-user/daemon/9.7.1/daemon-53566.out.log @@ -0,0 +1,177 @@ +2026-10-16T08:23:16.720-0400 [DEBUG] [org.gradle.launcher.daemon.bootstrap.DaemonMain] Assuming the daemon was started with following jvm opts: [-XX:MaxMetaspaceSize=384m, -XX:+HeapDumpOnOutOfMemoryError, -Xms256m, -Xmx512m, -Dfile.encoding=UTF-8, -Duser.country, -Duser.language=en, -Duser.variant] +2026-10-16T08:23:16.781-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding IP addresses for network interface tailscale0 +2026-10-16T08:23:16.781-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Is this a loopback interface? false +2026-10-16T08:23:16.782-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding remote address /fe80:0:0:0:8d15:7fb2:299f:dced%tailscale0 +2026-10-16T08:23:16.782-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding IP addresses for network interface wlp98s0 +2026-10-16T08:23:16.782-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Is this a loopback interface? false +2026-10-16T08:23:16.782-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding remote address /fe80:0:0:0:6f3f:89e6:b585:4167%wlp98s0 +2026-10-16T08:23:16.782-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding remote address /192.168.27.163 +2026-10-16T08:23:16.783-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding IP addresses for network interface lo +2026-10-16T08:23:16.783-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Is this a loopback interface? true +2026-10-16T08:23:16.783-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding loopback address /0:0:0:0:0:0:0:1%lo +2026-10-16T08:23:16.783-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding loopback address /127.0.0.1 +2026-10-16T08:23:16.812-0400 [INFO] [org.gradle.launcher.daemon.server.Daemon] start() called on daemon - DefaultDaemonContext[uid=2dfcc5e4-b6c0-4dfb-93a1-5cd93fe0b8f2,javaHome=/var/home/hellings/.sdkman/candidates/java/21.0.8-tem,javaVersion=21,javaVendor=Eclipse Adoptium,daemonRegistryDir=/var/home/hellings/Documents/mistring/.gradle-user/daemon,pid=53566,idleTimeout=120000,priority=NORMAL,applyInstrumentationAgent=true,nativeServicesMode=ENABLED,daemonOpts=-XX:MaxMetaspaceSize=384m,-XX:+HeapDumpOnOutOfMemoryError,-Xms256m,-Xmx512m,-Dfile.encoding=UTF-8,-Duser.country,-Duser.language=en,-Duser.variant] +2026-10-16T08:23:16.816-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.TcpIncomingConnector] Listening on [e0c4f334-3a4b-4d98-b1a3-c8abdb25587c port:43929, addresses:[localhost/127.0.0.1]]. +2026-10-16T08:23:16.819-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] Daemon starting at: Fri Oct 16 08:23:16 EDT 2026, with address: [e0c4f334-3a4b-4d98-b1a3-c8abdb25587c port:43929, addresses:[localhost/127.0.0.1]] +2026-10-16T08:23:16.819-0400 [INFO] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Advertising the daemon address to the clients: [e0c4f334-3a4b-4d98-b1a3-c8abdb25587c port:43929, addresses:[localhost/127.0.0.1]] +2026-10-16T08:23:16.819-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Advertised daemon context: DefaultDaemonContext[uid=2dfcc5e4-b6c0-4dfb-93a1-5cd93fe0b8f2,javaHome=/var/home/hellings/.sdkman/candidates/java/21.0.8-tem,javaVersion=21,javaVendor=Eclipse Adoptium,daemonRegistryDir=/var/home/hellings/Documents/mistring/.gradle-user/daemon,pid=53566,idleTimeout=120000,priority=NORMAL,applyInstrumentationAgent=true,nativeServicesMode=ENABLED,daemonOpts=-XX:MaxMetaspaceSize=384m,-XX:+HeapDumpOnOutOfMemoryError,-Xms256m,-Xmx512m,-Dfile.encoding=UTF-8,-Duser.country,-Duser.language=en,-Duser.variant] +2026-10-16T08:23:16.820-0400 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Storing daemon address: [e0c4f334-3a4b-4d98-b1a3-c8abdb25587c port:43929, addresses:[localhost/127.0.0.1]], context: DefaultDaemonContext[uid=2dfcc5e4-b6c0-4dfb-93a1-5cd93fe0b8f2,javaHome=/var/home/hellings/.sdkman/candidates/java/21.0.8-tem,javaVersion=21,javaVendor=Eclipse Adoptium,daemonRegistryDir=/var/home/hellings/Documents/mistring/.gradle-user/daemon,pid=53566,idleTimeout=120000,priority=NORMAL,applyInstrumentationAgent=true,nativeServicesMode=ENABLED,daemonOpts=-XX:MaxMetaspaceSize=384m,-XX:+HeapDumpOnOutOfMemoryError,-Xms256m,-Xmx512m,-Dfile.encoding=UTF-8,-Duser.country,-Duser.language=en,-Duser.variant] +2026-10-16T08:23:16.825-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire exclusive lock on daemon addresses registry. +2026-10-16T08:23:16.827-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired on daemon addresses registry. +2026-10-16T08:23:16.831-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on daemon addresses registry. +2026-10-16T08:23:16.831-0400 [LIFECYCLE] [org.gradle.launcher.daemon.server.Daemon] Daemon server started. +2026-10-16T08:23:16.832-0400 [DEBUG] [org.gradle.launcher.daemon.bootstrap.DaemonStartupCommunication] Completed writing the daemon greeting. Closing streams... +2026-10-16T08:23:16.838-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] stopOnExpiration() called on daemon +2026-10-16T08:23:16.840-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] awaitExpiration() called on daemon +2026-10-16T08:23:16.840-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon is running. Sleeping until state changes. +2026-10-16T08:23:16.846-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.TcpIncomingConnector] Accepted connection from /127.0.0.1:45712 to /127.0.0.1:43929. +2026-10-16T08:23:16.859-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 40: received class org.gradle.launcher.daemon.protocol.Build +2026-10-16T08:23:16.859-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultDaemonConnection] thread 40: Received non-IO message from client: Build{id=584625c3-0ad1-4f6a-9188-67bde876991a, currentDir=/var/home/hellings/Documents/mistring} +2026-10-16T08:23:16.860-0400 [INFO] [org.gradle.launcher.daemon.server.DefaultIncomingConnectionHandler] Received command: Build{id=584625c3-0ad1-4f6a-9188-67bde876991a, currentDir=/var/home/hellings/Documents/mistring}. +2026-10-16T08:23:16.860-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultIncomingConnectionHandler] Starting executing command: Build{id=584625c3-0ad1-4f6a-9188-67bde876991a, currentDir=/var/home/hellings/Documents/mistring} with connection: socket connection from /127.0.0.1:43929 to /127.0.0.1:45712. +2026-10-16T08:23:16.862-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Command execution: started DaemonCommandExecution[command = Build{id=584625c3-0ad1-4f6a-9188-67bde876991a, currentDir=/var/home/hellings/Documents/mistring}, connection = DefaultDaemonConnection: socket connection from /127.0.0.1:43929 to /127.0.0.1:45712] after 7.833333333333334E-4 minutes of idle +2026-10-16T08:23:16.862-0400 [INFO] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Marking the daemon as busy, address: [e0c4f334-3a4b-4d98-b1a3-c8abdb25587c port:43929, addresses:[localhost/127.0.0.1]] +2026-10-16T08:23:16.862-0400 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Marking busy by address: [e0c4f334-3a4b-4d98-b1a3-c8abdb25587c port:43929, addresses:[localhost/127.0.0.1]] +2026-10-16T08:23:16.863-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire exclusive lock on daemon addresses registry. +2026-10-16T08:23:16.863-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired on daemon addresses registry. +2026-10-16T08:23:16.864-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on daemon addresses registry. +2026-10-16T08:23:16.864-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] resetting idle timer +2026-10-16T08:23:16.864-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon is running. Sleeping until state changes. +2026-10-16T08:23:16.865-0400 [INFO] [org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy] Daemon is about to start building Build{id=584625c3-0ad1-4f6a-9188-67bde876991a, currentDir=/var/home/hellings/Documents/mistring}. Dispatching build started information... +2026-10-16T08:23:16.866-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 42: dispatching org.gradle.launcher.daemon.protocol.BuildStarted@3be6207 +2026-10-16T08:23:16.867-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.LogToClient] About to start relaying all logs to the client via the connection. +2026-10-16T08:23:16.867-0400 [INFO] [org.gradle.launcher.daemon.server.exec.LogToClient] The client will now receive all logging from the daemon (pid: 53566). The daemon log file: /var/home/hellings/Documents/mistring/.gradle-user/daemon/9.7.1/daemon-53566.out.log +2026-10-16T08:23:16.868-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.ApplyClientEnvironmentVariables] Configuring env variables: [container, PYENV_SHELL, PATH, GNOME_SHELL_SLOWDOWN_FACTOR, HISTCONTROL, XMODIFIERS, GDMSESSION, GUESTFISH_RESTORE, DBUS_SESSION_BUS_ADDRESS, ANDROID_HOME, XDG_CACHE_HOME, GH_PAGER, LD_LIBRARY_PATH, COLORTERM, SDKMAN_DIR, USERNAME, PWD, MANAGERPID, SDKMAN_BROKER_API, GJS_DEBUG_TOPICS, NVM_CD_FLAGS, LESSOPEN, CHROME_DESKTOP, PAGER, SDKMAN_CANDIDATES_API, GUESTFISH_INIT, DEBUGINFOD_IMA_CERT_PATH, LC_ALL, ZSH_TMUX_AUTOSTARTED, LC_CTYPE, GNOME_SETUP_DISPLAY, CODEX_SESSION_ID, SHLVL, QT_IM_MODULES, HISTSIZE, JAVA_HOME, KOTLIN_HOME, MEMORY_PRESSURE_WATCH, RUST_LOG, TERM, XDG_CONFIG_DIRS, MOZ_GMP_PATH, GRADLE_HOME, NVM_INC, GRADLE_USER_HOME, WAYLAND_DISPLAY, STARSHIP_SHELL, CODEX_THREAD_ID, XDG_SESSION_CLASS, DISABLE_AUTO_UPDATE, SWIFTLY_HOME_DIR, DESKTOP_SESSION, XDG_MENU_PREFIX, ZSH_TMUX_AUTOSTART, NVM_BIN, CONTAINER_ID, INVOCATION_ID, XAUTHORITY, XDG_DATA_DIRS, GIT_PAGER, CODEX_MCP_NODE_PATH, CODEX_SHELL, XDG_CURRENT_DESKTOP, JOURNAL_STREAM, MAIL, XDG_STATE_HOME, CODEX_APP_TOOLS_PIPE_PATH, MANAGERPIDFDID, LOGNAME, SWIFTLY_BIN_DIR, PYENV_VIRTUALENV_INIT, CODEX_INTERNAL_ORIGINATOR_OVERRIDE, CODEX_SAGE_BACKFILL_TRACKER_TAB_REUSE, CODEX_SANDBOX_NETWORK_DISABLED, SHELL, GIO_LAUNCHED_DESKTOP_FILE, PYENV_ROOT, CODEX_PERMISSION_PROFILE, LOG_FORMAT, SSH_ASKPASS, DEBUGINFOD_URLS, SYSTEMD_EXEC_PID, XDG_SESSION_DESKTOP, MEMORY_PRESSURE_WRITE, DOCKER_HOST, QT_IM_MODULE, STARSHIP_SESSION_KEY, XDG_SESSION_EXTRA_DEVICE_ACCESS, LANG, EGL_PLATFORM, XDG_SESSION_TYPE, DISPLAY, FC_FONTATIONS, NO_COLOR, SDKMAN_CANDIDATES_DIR, CODEX_CI, GDM_LANG, NVM_DIR, XDG_DATA_HOME, GUESTFISH_PS1, SWIFTLY_TOOLCHAINS_DIR, GDK_BACKEND, FREETOKEN_FT_BIN, GPG_TTY, SDKMAN_PLATFORM, USER, XDG_CONFIG_HOME, GIO_LAUNCHED_DESKTOP_FILE_PID, GJS_DEBUG_OUTPUT, SSH_AUTH_SOCK, EDITOR, HOSTNAME, DISTROBOX_ENTER_PATH, NO_AT_BRIDGE, XDG_RUNTIME_DIR, HOME, TERMINFO_DIRS, GUESTFISH_OUTPUT] +2026-10-16T08:23:16.872-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon] Requesting daemon stop after processing Build{id=584625c3-0ad1-4f6a-9188-67bde876991a, currentDir=/var/home/hellings/Documents/mistring} +2026-10-16T08:23:16.873-0400 [LIFECYCLE] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Daemon will be stopped at the end of the build +2026-10-16T08:23:16.873-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Stop as soon as idle requested. The daemon is busy +2026-10-16T08:23:16.873-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon stop has been requested. Sleeping until state changes. +2026-10-16T08:23:16.875-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.ExecuteBuild] The daemon has started executing the build. +2026-10-16T08:23:16.876-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.ExecuteBuild] Executing build with daemon context: DefaultDaemonContext[uid=2dfcc5e4-b6c0-4dfb-93a1-5cd93fe0b8f2,javaHome=/var/home/hellings/.sdkman/candidates/java/21.0.8-tem,javaVersion=21,javaVendor=Eclipse Adoptium,daemonRegistryDir=/var/home/hellings/Documents/mistring/.gradle-user/daemon,pid=53566,idleTimeout=120000,priority=NORMAL,applyInstrumentationAgent=true,nativeServicesMode=ENABLED,daemonOpts=-XX:MaxMetaspaceSize=384m,-XX:+HeapDumpOnOutOfMemoryError,-Xms256m,-Xmx512m,-Dfile.encoding=UTF-8,-Duser.country,-Duser.language=en,-Duser.variant] + +FAILURE: Build failed with an exception. + +* What went wrong: +Execution failed for task ':moannotes-native:smaliRelease' (registered in build file 'moannotes-native/build.gradle'). +> Could not resolve all files for configuration ':moannotes-native:runtimeClasspath'. + > Could not find com.android.tools.smali:smali-baksmali:3.0.9. + Searched in the following locations: + - https://repo.maven.apache.org/maven2/com/android/tools/smali/smali-baksmali/3.0.9/smali-baksmali-3.0.9.pom + Required by: + project ':moannotes-native' + +* Try: +> If the artifact you are trying to retrieve can be found in the repository but without metadata in 'Maven POM' format, you need to adjust the 'metadataSources { ... }' of the repository declaration. +> Run with --stacktrace option to get the stack trace. +> Run with --info or --debug option to get more log output. +> Run with --scan to get full insights from a Build Scan (powered by Develocity). +> Get more help at https://help.gradle.org. + +BUILD FAILED in 7s +4 actionable tasks: 4 executed +2026-10-16T08:23:23.555-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.ExecuteBuild] The daemon has finished executing the build. +2026-10-16T08:23:23.562-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon stop has been requested. Sleeping until state changes. +2026-10-16T08:23:23.563-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Command execution: finished waiting for DaemonCommandExecution[command = Build{id=584625c3-0ad1-4f6a-9188-67bde876991a, currentDir=/var/home/hellings/Documents/mistring}, connection = DefaultDaemonConnection: socket connection from /127.0.0.1:43929 to /127.0.0.1:45712]. Result org.gradle.launcher.daemon.server.DaemonStateCoordinator@1a2750ae with state StopRequested +2026-10-16T08:23:23.563-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Command execution: completed DaemonCommandExecution[command = Build{id=584625c3-0ad1-4f6a-9188-67bde876991a, currentDir=/var/home/hellings/Documents/mistring}, connection = DefaultDaemonConnection: socket connection from /127.0.0.1:43929 to /127.0.0.1:45712] +2026-10-16T08:23:23.563-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] resetting idle timer +2026-10-16T08:23:23.563-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Marking daemon stopped due to command completed and stop requested. The daemon is not running a build +2026-10-16T08:23:23.563-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon has stopped. +2026-10-16T08:23:23.563-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.ReturnResult] Daemon is dispatching the build result: Success[value=org.gradle.launcher.exec.BuildActionResult@28e509c1] +2026-10-16T08:23:23.563-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 39: dispatching Success[value=org.gradle.launcher.exec.BuildActionResult@28e509c1] +2026-10-16T08:23:23.564-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] stop() called on daemon +2026-10-16T08:23:23.564-0400 [INFO] [org.gradle.launcher.daemon.server.Daemon] Stop requested. Daemon is removing its presence from the registry... +2026-10-16T08:23:23.564-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Removing our presence to clients, eg. removing this address from the registry: [e0c4f334-3a4b-4d98-b1a3-c8abdb25587c port:43929, addresses:[localhost/127.0.0.1]] +2026-10-16T08:23:23.564-0400 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Removing daemon address: [e0c4f334-3a4b-4d98-b1a3-c8abdb25587c port:43929, addresses:[localhost/127.0.0.1]] +2026-10-16T08:23:23.565-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire exclusive lock on daemon addresses registry. +2026-10-16T08:23:23.565-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired on daemon addresses registry. +2026-10-16T08:23:23.565-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on daemon addresses registry. +2026-10-16T08:23:23.565-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Address removed from registry. +2026-10-16T08:23:23.569-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.CleanUpVirtualFileSystemAfterBuild] Cleaning virtual file system after build finished +2026-10-16T08:23:23.570-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultIncomingConnectionHandler] Finishing executing command: Build{id=584625c3-0ad1-4f6a-9188-67bde876991a, currentDir=/var/home/hellings/Documents/mistring} +2026-10-16T08:23:23.593-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 40: received class org.gradle.launcher.daemon.protocol.CloseInput +2026-10-16T08:23:23.593-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultDaemonConnection] thread 40: Received IO message from client: org.gradle.launcher.daemon.protocol.CloseInput@c6900dc +2026-10-16T08:23:23.635-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 40: received class org.gradle.launcher.daemon.protocol.Finished +2026-10-16T08:23:23.635-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultDaemonConnection] thread 40: Received non-IO message from client: org.gradle.launcher.daemon.protocol.Finished@30b9db9f +2026-10-16T08:23:23.635-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultIncomingConnectionHandler] Received finished message: org.gradle.launcher.daemon.protocol.Finished@30b9db9f +2026-10-16T08:23:23.636-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 39: stopping connection +2026-10-16T08:23:23.636-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.SocketConnection] Discarding EOFException: java.io.EOFException +2026-10-16T08:23:23.636-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 40: received null +2026-10-16T08:23:23.636-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultDaemonConnection] thread 40: Received end-of-input from client. +2026-10-16T08:23:23.637-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 39: stopping connection +2026-10-16T08:23:23.637-0400 [DEBUG] [org.gradle.workers.internal.WorkerDaemonClientsManager] Stopping 1 worker daemon(s). +2026-10-16T08:23:23.647-0400 [DEBUG] [org.gradle.process.internal.DefaultExecHandle] Changing state to: SUCCEEDED +2026-10-16T08:23:23.648-0400 [DEBUG] [org.gradle.process.internal.DefaultExecHandle] Process 'Gradle Worker Daemon 1' finished with exit value 0 (state: SUCCEEDED) +2026-10-16T08:23:23.648-0400 [INFO] [org.gradle.workers.internal.WorkerDaemonClientsManager] Stopped 1 worker daemon(s). +2026-10-16T08:23:23.649-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for jars (/var/home/hellings/Documents/mistring/.gradle-user/caches/jars-9) +2026-10-16T08:23:23.649-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on jars (/var/home/hellings/Documents/mistring/.gradle-user/caches/jars-9). +2026-10-16T08:23:23.649-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] jars (/var/home/hellings/Documents/mistring/.gradle-user/caches/jars-9) has last been fully cleaned up 0 hours ago +2026-10-16T08:23:23.649-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] Skipping cleanup for jars (/var/home/hellings/Documents/mistring/.gradle-user/caches/jars-9) as it is not yet due +2026-10-16T08:23:23.650-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for file content cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileContent) +2026-10-16T08:23:23.650-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on file content cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileContent). +2026-10-16T08:23:23.650-0400 [DEBUG] [org.gradle.internal.watch.vfs.impl.WatchingVirtualFileSystem] Closing VFS, dropping state +2026-10-16T08:23:23.651-0400 [DEBUG] [org.gradle.internal.watch.registry.impl.DefaultFileWatcherRegistry] Finished listening to file system change events +2026-10-16T08:23:23.651-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCoordinator] Cache Generated Gradle JARs cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/generated-gradle-jars) was closed 0 times. +2026-10-16T08:23:23.651-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for artifact cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2) +2026-10-16T08:23:23.651-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache module-artifact.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2/metadata-2.107/module-artifact.bin) +2026-10-16T08:23:23.651-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache module-metadata.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2/metadata-2.107/module-metadata.bin) +2026-10-16T08:23:23.652-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache resource-at-url.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2/metadata-2.107/resource-at-url.bin) +2026-10-16T08:23:23.653-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on artifact cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2). +2026-10-16T08:23:23.653-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] artifact cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2) has last been fully cleaned up 0 hours ago +2026-10-16T08:23:23.653-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] Skipping cleanup for artifact cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2) as it is not yet due +2026-10-16T08:23:23.653-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] groovy-dsl has last been fully cleaned up 0 hours ago +2026-10-16T08:23:23.653-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] Skipping cleanup for groovy-dsl as it is not yet due +2026-10-16T08:23:23.653-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] Artifact transforms cache has last been fully cleaned up 0 hours ago +2026-10-16T08:23:23.654-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] Skipping cleanup for Artifact transforms cache as it is not yet due +2026-10-16T08:23:23.654-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for journal cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/journal-1) +2026-10-16T08:23:23.654-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache file-access.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/journal-1/file-access.bin) +2026-10-16T08:23:23.654-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on journal cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/journal-1). +2026-10-16T08:23:23.655-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for file hash cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileHashes) +2026-10-16T08:23:23.655-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache fileHashes.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileHashes/fileHashes.bin) +2026-10-16T08:23:23.655-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache resourceHashesCache.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileHashes/resourceHashesCache.bin) +2026-10-16T08:23:23.655-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on file hash cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileHashes). +2026-10-16T08:23:23.655-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for Java compile cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/javaCompile) +2026-10-16T08:23:23.655-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache jarAnalysis.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/javaCompile/jarAnalysis.bin) +2026-10-16T08:23:23.656-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache classAnalysis.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/javaCompile/classAnalysis.bin) +2026-10-16T08:23:23.656-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on Java compile cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/javaCompile). +2026-10-16T08:23:23.656-0400 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationRunner] Build operation 'Deleting unused version-specific caches in /var/home/hellings/Documents/mistring/.gradle-user/caches' started +2026-10-16T08:23:23.657-0400 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationRunner] Completing Build operation 'Deleting unused version-specific caches in /var/home/hellings/Documents/mistring/.gradle-user/caches' +2026-10-16T08:23:23.657-0400 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationRunner] Build operation 'Deleting unused version-specific caches in /var/home/hellings/Documents/mistring/.gradle-user/caches' completed +2026-10-16T08:23:23.657-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] stop() called on daemon +2026-10-16T08:23:23.657-0400 [INFO] [org.gradle.launcher.daemon.server.Daemon] Stop requested. Daemon is removing its presence from the registry... +2026-10-16T08:23:23.657-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Removing our presence to clients, eg. removing this address from the registry: [e0c4f334-3a4b-4d98-b1a3-c8abdb25587c port:43929, addresses:[localhost/127.0.0.1]] +2026-10-16T08:23:23.657-0400 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Removing daemon address: [e0c4f334-3a4b-4d98-b1a3-c8abdb25587c port:43929, addresses:[localhost/127.0.0.1]] +2026-10-16T08:23:23.657-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire exclusive lock on daemon addresses registry. +2026-10-16T08:23:23.657-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired on daemon addresses registry. +2026-10-16T08:23:23.658-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on daemon addresses registry. +2026-10-16T08:23:23.658-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Address removed from registry. +2026-10-16T08:23:23.659-0400 [DEBUG] [org.gradle.cache.internal.locklistener.DefaultFileLockContentionHandler] File lock listener thread completed. +2026-10-16T08:23:23.660-0400 [DEBUG] [java.lang.Runtime] Runtime.exit() called with status: 0 +java.lang.Throwable: Runtime.exit(0) + at java.base/java.lang.Shutdown.logRuntimeExit(Shutdown.java:179) + at java.base/java.lang.Shutdown.exit(Shutdown.java:160) + at java.base/java.lang.Runtime.exit(Runtime.java:188) + at java.base/java.lang.System.exit(System.java:1920) + at org.gradle.launcher.bootstrap.ProcessCompleter.complete(ProcessCompleter.java:21) + at org.gradle.launcher.bootstrap.EntryPoint.run(EntryPoint.java:62) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.gradle.launcher.bootstrap.ProcessBootstrap.runNoExit(ProcessBootstrap.java:72) + at org.gradle.launcher.bootstrap.ProcessBootstrap.run(ProcessBootstrap.java:39) + at org.gradle.launcher.daemon.bootstrap.GradleDaemon.main(GradleDaemon.java:23) +Daemon vm is shutting down... The daemon has exited normally or was terminated in response to a user interrupt. +2026-10-16T08:23:23.661-0400 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Removing daemon address: [e0c4f334-3a4b-4d98-b1a3-c8abdb25587c port:43929, addresses:[localhost/127.0.0.1]] +2026-10-16T08:23:23.661-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] VM shutdown hook was unable to remove the daemon address from the registry. It will be cleaned up later. +java.lang.IllegalStateException: Cannot start managing file contention because this handler has been closed. + at org.gradle.cache.internal.locklistener.DefaultFileLockContentionHandler.assertNotStopped(DefaultFileLockContentionHandler.java:267) + at org.gradle.cache.internal.locklistener.DefaultFileLockContentionHandler.reservePort(DefaultFileLockContentionHandler.java:312) + at org.gradle.cache.internal.DefaultFileLockManager.lock(DefaultFileLockManager.java:127) + at org.gradle.cache.internal.DefaultFileLockManager.lock(DefaultFileLockManager.java:109) + at org.gradle.cache.internal.DefaultFileLockManager.lock(DefaultFileLockManager.java:104) + at org.gradle.cache.internal.OnDemandFileAccess.updateFile(OnDemandFileAccess.java:51) + at org.gradle.cache.internal.FileBackedObjectHolder.update(FileBackedObjectHolder.java:77) + at org.gradle.cache.internal.FileIntegrityViolationSuppressingObjectHolderDecorator.lambda$update$0(FileIntegrityViolationSuppressingObjectHolderDecorator.java:48) + at org.gradle.cache.internal.FileIntegrityViolationSuppressingObjectHolderDecorator.doUpdate(FileIntegrityViolationSuppressingObjectHolderDecorator.java:58) + at org.gradle.cache.internal.FileIntegrityViolationSuppressingObjectHolderDecorator.update(FileIntegrityViolationSuppressingObjectHolderDecorator.java:48) + at org.gradle.launcher.daemon.registry.PersistentDaemonRegistry.remove(PersistentDaemonRegistry.java:133) + at org.gradle.launcher.daemon.server.Daemon$1.run(Daemon.java:133) + at java.base/java.lang.Thread.run(Thread.java:1583) diff --git a/.gradle-user/daemon/9.7.1/daemon-55337.out.log b/.gradle-user/daemon/9.7.1/daemon-55337.out.log new file mode 100644 index 0000000..72e6177 --- /dev/null +++ b/.gradle-user/daemon/9.7.1/daemon-55337.out.log @@ -0,0 +1,151 @@ +2026-10-16T08:23:45.727-0400 [DEBUG] [org.gradle.launcher.daemon.bootstrap.DaemonMain] Assuming the daemon was started with following jvm opts: [-XX:MaxMetaspaceSize=384m, -XX:+HeapDumpOnOutOfMemoryError, -Xms256m, -Xmx512m, -Dfile.encoding=UTF-8, -Duser.country, -Duser.language=en, -Duser.variant] +2026-10-16T08:23:45.791-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding IP addresses for network interface tailscale0 +2026-10-16T08:23:45.792-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Is this a loopback interface? false +2026-10-16T08:23:45.792-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding remote address /fe80:0:0:0:8d15:7fb2:299f:dced%tailscale0 +2026-10-16T08:23:45.792-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding IP addresses for network interface wlp98s0 +2026-10-16T08:23:45.792-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Is this a loopback interface? false +2026-10-16T08:23:45.793-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding remote address /fe80:0:0:0:6f3f:89e6:b585:4167%wlp98s0 +2026-10-16T08:23:45.793-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding remote address /192.168.27.163 +2026-10-16T08:23:45.793-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding IP addresses for network interface lo +2026-10-16T08:23:45.793-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Is this a loopback interface? true +2026-10-16T08:23:45.793-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding loopback address /0:0:0:0:0:0:0:1%lo +2026-10-16T08:23:45.793-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding loopback address /127.0.0.1 +2026-10-16T08:23:45.822-0400 [INFO] [org.gradle.launcher.daemon.server.Daemon] start() called on daemon - DefaultDaemonContext[uid=df0462a2-d046-4548-b2b5-007adc4bf288,javaHome=/var/home/hellings/.sdkman/candidates/java/21.0.8-tem,javaVersion=21,javaVendor=Eclipse Adoptium,daemonRegistryDir=/var/home/hellings/Documents/mistring/.gradle-user/daemon,pid=55337,idleTimeout=120000,priority=NORMAL,applyInstrumentationAgent=true,nativeServicesMode=ENABLED,daemonOpts=-XX:MaxMetaspaceSize=384m,-XX:+HeapDumpOnOutOfMemoryError,-Xms256m,-Xmx512m,-Dfile.encoding=UTF-8,-Duser.country,-Duser.language=en,-Duser.variant] +2026-10-16T08:23:45.825-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.TcpIncomingConnector] Listening on [b75a6179-a3cc-46eb-b232-ac50885c73f9 port:46139, addresses:[localhost/127.0.0.1]]. +2026-10-16T08:23:45.828-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] Daemon starting at: Fri Oct 16 08:23:45 EDT 2026, with address: [b75a6179-a3cc-46eb-b232-ac50885c73f9 port:46139, addresses:[localhost/127.0.0.1]] +2026-10-16T08:23:45.828-0400 [INFO] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Advertising the daemon address to the clients: [b75a6179-a3cc-46eb-b232-ac50885c73f9 port:46139, addresses:[localhost/127.0.0.1]] +2026-10-16T08:23:45.829-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Advertised daemon context: DefaultDaemonContext[uid=df0462a2-d046-4548-b2b5-007adc4bf288,javaHome=/var/home/hellings/.sdkman/candidates/java/21.0.8-tem,javaVersion=21,javaVendor=Eclipse Adoptium,daemonRegistryDir=/var/home/hellings/Documents/mistring/.gradle-user/daemon,pid=55337,idleTimeout=120000,priority=NORMAL,applyInstrumentationAgent=true,nativeServicesMode=ENABLED,daemonOpts=-XX:MaxMetaspaceSize=384m,-XX:+HeapDumpOnOutOfMemoryError,-Xms256m,-Xmx512m,-Dfile.encoding=UTF-8,-Duser.country,-Duser.language=en,-Duser.variant] +2026-10-16T08:23:45.829-0400 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Storing daemon address: [b75a6179-a3cc-46eb-b232-ac50885c73f9 port:46139, addresses:[localhost/127.0.0.1]], context: DefaultDaemonContext[uid=df0462a2-d046-4548-b2b5-007adc4bf288,javaHome=/var/home/hellings/.sdkman/candidates/java/21.0.8-tem,javaVersion=21,javaVendor=Eclipse Adoptium,daemonRegistryDir=/var/home/hellings/Documents/mistring/.gradle-user/daemon,pid=55337,idleTimeout=120000,priority=NORMAL,applyInstrumentationAgent=true,nativeServicesMode=ENABLED,daemonOpts=-XX:MaxMetaspaceSize=384m,-XX:+HeapDumpOnOutOfMemoryError,-Xms256m,-Xmx512m,-Dfile.encoding=UTF-8,-Duser.country,-Duser.language=en,-Duser.variant] +2026-10-16T08:23:45.833-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire exclusive lock on daemon addresses registry. +2026-10-16T08:23:45.835-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired on daemon addresses registry. +2026-10-16T08:23:45.838-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on daemon addresses registry. +2026-10-16T08:23:45.839-0400 [LIFECYCLE] [org.gradle.launcher.daemon.server.Daemon] Daemon server started. +2026-10-16T08:23:45.840-0400 [DEBUG] [org.gradle.launcher.daemon.bootstrap.DaemonStartupCommunication] Completed writing the daemon greeting. Closing streams... +2026-10-16T08:23:45.845-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] stopOnExpiration() called on daemon +2026-10-16T08:23:45.846-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] awaitExpiration() called on daemon +2026-10-16T08:23:45.846-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon is running. Sleeping until state changes. +2026-10-16T08:23:45.854-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.TcpIncomingConnector] Accepted connection from /127.0.0.1:58066 to /127.0.0.1:46139. +2026-10-16T08:23:45.869-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 40: received class org.gradle.launcher.daemon.protocol.Build +2026-10-16T08:23:45.870-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultDaemonConnection] thread 40: Received non-IO message from client: Build{id=381323d8-b775-4569-bcf6-5a8d814c7c23, currentDir=/var/home/hellings/Documents/mistring} +2026-10-16T08:23:45.870-0400 [INFO] [org.gradle.launcher.daemon.server.DefaultIncomingConnectionHandler] Received command: Build{id=381323d8-b775-4569-bcf6-5a8d814c7c23, currentDir=/var/home/hellings/Documents/mistring}. +2026-10-16T08:23:45.870-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultIncomingConnectionHandler] Starting executing command: Build{id=381323d8-b775-4569-bcf6-5a8d814c7c23, currentDir=/var/home/hellings/Documents/mistring} with connection: socket connection from /127.0.0.1:46139 to /127.0.0.1:58066. +2026-10-16T08:23:45.871-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Command execution: started DaemonCommandExecution[command = Build{id=381323d8-b775-4569-bcf6-5a8d814c7c23, currentDir=/var/home/hellings/Documents/mistring}, connection = DefaultDaemonConnection: socket connection from /127.0.0.1:46139 to /127.0.0.1:58066] after 8.0E-4 minutes of idle +2026-10-16T08:23:45.872-0400 [INFO] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Marking the daemon as busy, address: [b75a6179-a3cc-46eb-b232-ac50885c73f9 port:46139, addresses:[localhost/127.0.0.1]] +2026-10-16T08:23:45.872-0400 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Marking busy by address: [b75a6179-a3cc-46eb-b232-ac50885c73f9 port:46139, addresses:[localhost/127.0.0.1]] +2026-10-16T08:23:45.872-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire exclusive lock on daemon addresses registry. +2026-10-16T08:23:45.873-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired on daemon addresses registry. +2026-10-16T08:23:45.873-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on daemon addresses registry. +2026-10-16T08:23:45.873-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] resetting idle timer +2026-10-16T08:23:45.874-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon is running. Sleeping until state changes. +2026-10-16T08:23:45.874-0400 [INFO] [org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy] Daemon is about to start building Build{id=381323d8-b775-4569-bcf6-5a8d814c7c23, currentDir=/var/home/hellings/Documents/mistring}. Dispatching build started information... +2026-10-16T08:23:45.874-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 42: dispatching org.gradle.launcher.daemon.protocol.BuildStarted@4b6f8f9c +2026-10-16T08:23:45.875-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.LogToClient] About to start relaying all logs to the client via the connection. +2026-10-16T08:23:45.876-0400 [INFO] [org.gradle.launcher.daemon.server.exec.LogToClient] The client will now receive all logging from the daemon (pid: 55337). The daemon log file: /var/home/hellings/Documents/mistring/.gradle-user/daemon/9.7.1/daemon-55337.out.log +2026-10-16T08:23:45.877-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.ApplyClientEnvironmentVariables] Configuring env variables: [container, PYENV_SHELL, PATH, GNOME_SHELL_SLOWDOWN_FACTOR, HISTCONTROL, XMODIFIERS, GDMSESSION, GUESTFISH_RESTORE, DBUS_SESSION_BUS_ADDRESS, ANDROID_HOME, XDG_CACHE_HOME, GH_PAGER, LD_LIBRARY_PATH, COLORTERM, SDKMAN_DIR, USERNAME, PWD, MANAGERPID, SDKMAN_BROKER_API, GJS_DEBUG_TOPICS, NVM_CD_FLAGS, LESSOPEN, CHROME_DESKTOP, PAGER, SDKMAN_CANDIDATES_API, GUESTFISH_INIT, DEBUGINFOD_IMA_CERT_PATH, LC_ALL, ZSH_TMUX_AUTOSTARTED, LC_CTYPE, GNOME_SETUP_DISPLAY, CODEX_SESSION_ID, SHLVL, QT_IM_MODULES, HISTSIZE, JAVA_HOME, KOTLIN_HOME, MEMORY_PRESSURE_WATCH, RUST_LOG, TERM, XDG_CONFIG_DIRS, MOZ_GMP_PATH, GRADLE_HOME, NVM_INC, GRADLE_USER_HOME, WAYLAND_DISPLAY, STARSHIP_SHELL, CODEX_THREAD_ID, XDG_SESSION_CLASS, DISABLE_AUTO_UPDATE, SWIFTLY_HOME_DIR, DESKTOP_SESSION, XDG_MENU_PREFIX, ZSH_TMUX_AUTOSTART, NVM_BIN, CONTAINER_ID, INVOCATION_ID, XAUTHORITY, XDG_DATA_DIRS, GIT_PAGER, CODEX_MCP_NODE_PATH, CODEX_SHELL, XDG_CURRENT_DESKTOP, JOURNAL_STREAM, MAIL, XDG_STATE_HOME, CODEX_APP_TOOLS_PIPE_PATH, MANAGERPIDFDID, LOGNAME, SWIFTLY_BIN_DIR, PYENV_VIRTUALENV_INIT, CODEX_INTERNAL_ORIGINATOR_OVERRIDE, CODEX_SAGE_BACKFILL_TRACKER_TAB_REUSE, CODEX_SANDBOX_NETWORK_DISABLED, SHELL, GIO_LAUNCHED_DESKTOP_FILE, PYENV_ROOT, CODEX_PERMISSION_PROFILE, LOG_FORMAT, SSH_ASKPASS, DEBUGINFOD_URLS, SYSTEMD_EXEC_PID, XDG_SESSION_DESKTOP, MEMORY_PRESSURE_WRITE, DOCKER_HOST, QT_IM_MODULE, STARSHIP_SESSION_KEY, XDG_SESSION_EXTRA_DEVICE_ACCESS, LANG, EGL_PLATFORM, XDG_SESSION_TYPE, DISPLAY, FC_FONTATIONS, NO_COLOR, SDKMAN_CANDIDATES_DIR, CODEX_CI, GDM_LANG, NVM_DIR, XDG_DATA_HOME, GUESTFISH_PS1, SWIFTLY_TOOLCHAINS_DIR, GDK_BACKEND, FREETOKEN_FT_BIN, GPG_TTY, SDKMAN_PLATFORM, USER, XDG_CONFIG_HOME, GIO_LAUNCHED_DESKTOP_FILE_PID, GJS_DEBUG_OUTPUT, SSH_AUTH_SOCK, EDITOR, HOSTNAME, DISTROBOX_ENTER_PATH, NO_AT_BRIDGE, XDG_RUNTIME_DIR, HOME, TERMINFO_DIRS, GUESTFISH_OUTPUT] +2026-10-16T08:23:45.880-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon] Requesting daemon stop after processing Build{id=381323d8-b775-4569-bcf6-5a8d814c7c23, currentDir=/var/home/hellings/Documents/mistring} +2026-10-16T08:23:45.880-0400 [LIFECYCLE] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Daemon will be stopped at the end of the build +2026-10-16T08:23:45.880-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Stop as soon as idle requested. The daemon is busy +2026-10-16T08:23:45.880-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon stop has been requested. Sleeping until state changes. +2026-10-16T08:23:45.882-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.ExecuteBuild] The daemon has started executing the build. +2026-10-16T08:23:45.882-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.ExecuteBuild] Executing build with daemon context: DefaultDaemonContext[uid=df0462a2-d046-4548-b2b5-007adc4bf288,javaHome=/var/home/hellings/.sdkman/candidates/java/21.0.8-tem,javaVersion=21,javaVendor=Eclipse Adoptium,daemonRegistryDir=/var/home/hellings/Documents/mistring/.gradle-user/daemon,pid=55337,idleTimeout=120000,priority=NORMAL,applyInstrumentationAgent=true,nativeServicesMode=ENABLED,daemonOpts=-XX:MaxMetaspaceSize=384m,-XX:+HeapDumpOnOutOfMemoryError,-Xms256m,-Xmx512m,-Dfile.encoding=UTF-8,-Duser.country,-Duser.language=en,-Duser.variant] + +BUILD SUCCESSFUL in 6s +4 actionable tasks: 2 executed, 2 up-to-date +2026-10-16T08:23:52.013-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.ExecuteBuild] The daemon has finished executing the build. +2026-10-16T08:23:52.023-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon stop has been requested. Sleeping until state changes. +2026-10-16T08:23:52.023-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Command execution: finished waiting for DaemonCommandExecution[command = Build{id=381323d8-b775-4569-bcf6-5a8d814c7c23, currentDir=/var/home/hellings/Documents/mistring}, connection = DefaultDaemonConnection: socket connection from /127.0.0.1:46139 to /127.0.0.1:58066]. Result org.gradle.launcher.daemon.server.DaemonStateCoordinator@1d0f7463 with state StopRequested +2026-10-16T08:23:52.024-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Command execution: completed DaemonCommandExecution[command = Build{id=381323d8-b775-4569-bcf6-5a8d814c7c23, currentDir=/var/home/hellings/Documents/mistring}, connection = DefaultDaemonConnection: socket connection from /127.0.0.1:46139 to /127.0.0.1:58066] +2026-10-16T08:23:52.024-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] resetting idle timer +2026-10-16T08:23:52.024-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Marking daemon stopped due to command completed and stop requested. The daemon is not running a build +2026-10-16T08:23:52.024-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon has stopped. +2026-10-16T08:23:52.024-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.ReturnResult] Daemon is dispatching the build result: Success[value=org.gradle.launcher.exec.BuildActionResult@613fbc73] +2026-10-16T08:23:52.024-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 39: dispatching Success[value=org.gradle.launcher.exec.BuildActionResult@613fbc73] +2026-10-16T08:23:52.024-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] stop() called on daemon +2026-10-16T08:23:52.024-0400 [INFO] [org.gradle.launcher.daemon.server.Daemon] Stop requested. Daemon is removing its presence from the registry... +2026-10-16T08:23:52.025-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Removing our presence to clients, eg. removing this address from the registry: [b75a6179-a3cc-46eb-b232-ac50885c73f9 port:46139, addresses:[localhost/127.0.0.1]] +2026-10-16T08:23:52.025-0400 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Removing daemon address: [b75a6179-a3cc-46eb-b232-ac50885c73f9 port:46139, addresses:[localhost/127.0.0.1]] +2026-10-16T08:23:52.025-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.CleanUpVirtualFileSystemAfterBuild] Cleaning virtual file system after build finished +2026-10-16T08:23:52.025-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire exclusive lock on daemon addresses registry. +2026-10-16T08:23:52.025-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultIncomingConnectionHandler] Finishing executing command: Build{id=381323d8-b775-4569-bcf6-5a8d814c7c23, currentDir=/var/home/hellings/Documents/mistring} +2026-10-16T08:23:52.025-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 40: received class org.gradle.launcher.daemon.protocol.CloseInput +2026-10-16T08:23:52.026-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired on daemon addresses registry. +2026-10-16T08:23:52.026-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultDaemonConnection] thread 40: Received IO message from client: org.gradle.launcher.daemon.protocol.CloseInput@7afb0b64 +2026-10-16T08:23:52.026-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on daemon addresses registry. +2026-10-16T08:23:52.027-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Address removed from registry. +2026-10-16T08:23:52.065-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 40: received class org.gradle.launcher.daemon.protocol.Finished +2026-10-16T08:23:52.066-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultDaemonConnection] thread 40: Received non-IO message from client: org.gradle.launcher.daemon.protocol.Finished@52bb8d1a +2026-10-16T08:23:52.066-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultIncomingConnectionHandler] Received finished message: org.gradle.launcher.daemon.protocol.Finished@52bb8d1a +2026-10-16T08:23:52.066-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 39: stopping connection +2026-10-16T08:23:52.067-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.SocketConnection] Discarding EOFException: java.io.EOFException +2026-10-16T08:23:52.067-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 40: received null +2026-10-16T08:23:52.067-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultDaemonConnection] thread 40: Received end-of-input from client. +2026-10-16T08:23:52.068-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 39: stopping connection +2026-10-16T08:23:52.068-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for jars (/var/home/hellings/Documents/mistring/.gradle-user/caches/jars-9) +2026-10-16T08:23:52.069-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on jars (/var/home/hellings/Documents/mistring/.gradle-user/caches/jars-9). +2026-10-16T08:23:52.069-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] jars (/var/home/hellings/Documents/mistring/.gradle-user/caches/jars-9) has last been fully cleaned up 0 hours ago +2026-10-16T08:23:52.069-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] Skipping cleanup for jars (/var/home/hellings/Documents/mistring/.gradle-user/caches/jars-9) as it is not yet due +2026-10-16T08:23:52.069-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for file content cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileContent) +2026-10-16T08:23:52.069-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on file content cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileContent). +2026-10-16T08:23:52.070-0400 [DEBUG] [org.gradle.internal.watch.vfs.impl.WatchingVirtualFileSystem] Closing VFS, dropping state +2026-10-16T08:23:52.070-0400 [DEBUG] [org.gradle.internal.watch.registry.impl.DefaultFileWatcherRegistry] Finished listening to file system change events +2026-10-16T08:23:52.070-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCoordinator] Cache Generated Gradle JARs cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/generated-gradle-jars) was closed 0 times. +2026-10-16T08:23:52.071-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for artifact cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2) +2026-10-16T08:23:52.071-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache module-artifact.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2/metadata-2.107/module-artifact.bin) +2026-10-16T08:23:52.071-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache module-metadata.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2/metadata-2.107/module-metadata.bin) +2026-10-16T08:23:52.072-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache resource-at-url.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2/metadata-2.107/resource-at-url.bin) +2026-10-16T08:23:52.072-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on artifact cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2). +2026-10-16T08:23:52.072-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] artifact cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2) has last been fully cleaned up 0 hours ago +2026-10-16T08:23:52.072-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] Skipping cleanup for artifact cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2) as it is not yet due +2026-10-16T08:23:52.072-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] groovy-dsl has last been fully cleaned up 0 hours ago +2026-10-16T08:23:52.073-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] Skipping cleanup for groovy-dsl as it is not yet due +2026-10-16T08:23:52.073-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] Artifact transforms cache has last been fully cleaned up 0 hours ago +2026-10-16T08:23:52.073-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] Skipping cleanup for Artifact transforms cache as it is not yet due +2026-10-16T08:23:52.073-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for journal cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/journal-1) +2026-10-16T08:23:52.073-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache file-access.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/journal-1/file-access.bin) +2026-10-16T08:23:52.073-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on journal cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/journal-1). +2026-10-16T08:23:52.074-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for file hash cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileHashes) +2026-10-16T08:23:52.074-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache fileHashes.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileHashes/fileHashes.bin) +2026-10-16T08:23:52.074-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache resourceHashesCache.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileHashes/resourceHashesCache.bin) +2026-10-16T08:23:52.074-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on file hash cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileHashes). +2026-10-16T08:23:52.075-0400 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationRunner] Build operation 'Deleting unused version-specific caches in /var/home/hellings/Documents/mistring/.gradle-user/caches' started +2026-10-16T08:23:52.075-0400 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationRunner] Completing Build operation 'Deleting unused version-specific caches in /var/home/hellings/Documents/mistring/.gradle-user/caches' +2026-10-16T08:23:52.075-0400 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationRunner] Build operation 'Deleting unused version-specific caches in /var/home/hellings/Documents/mistring/.gradle-user/caches' completed +2026-10-16T08:23:52.075-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] stop() called on daemon +2026-10-16T08:23:52.075-0400 [INFO] [org.gradle.launcher.daemon.server.Daemon] Stop requested. Daemon is removing its presence from the registry... +2026-10-16T08:23:52.075-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Removing our presence to clients, eg. removing this address from the registry: [b75a6179-a3cc-46eb-b232-ac50885c73f9 port:46139, addresses:[localhost/127.0.0.1]] +2026-10-16T08:23:52.075-0400 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Removing daemon address: [b75a6179-a3cc-46eb-b232-ac50885c73f9 port:46139, addresses:[localhost/127.0.0.1]] +2026-10-16T08:23:52.075-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire exclusive lock on daemon addresses registry. +2026-10-16T08:23:52.076-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired on daemon addresses registry. +2026-10-16T08:23:52.076-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on daemon addresses registry. +2026-10-16T08:23:52.076-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Address removed from registry. +2026-10-16T08:23:52.077-0400 [DEBUG] [org.gradle.cache.internal.locklistener.DefaultFileLockContentionHandler] File lock listener thread completed. +2026-10-16T08:23:52.078-0400 [DEBUG] [java.lang.Runtime] Runtime.exit() called with status: 0 +java.lang.Throwable: Runtime.exit(0) + at java.base/java.lang.Shutdown.logRuntimeExit(Shutdown.java:179) + at java.base/java.lang.Shutdown.exit(Shutdown.java:160) + at java.base/java.lang.Runtime.exit(Runtime.java:188) + at java.base/java.lang.System.exit(System.java:1920) + at org.gradle.launcher.bootstrap.ProcessCompleter.complete(ProcessCompleter.java:21) + at org.gradle.launcher.bootstrap.EntryPoint.run(EntryPoint.java:62) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.gradle.launcher.bootstrap.ProcessBootstrap.runNoExit(ProcessBootstrap.java:72) + at org.gradle.launcher.bootstrap.ProcessBootstrap.run(ProcessBootstrap.java:39) + at org.gradle.launcher.daemon.bootstrap.GradleDaemon.main(GradleDaemon.java:23) +Daemon vm is shutting down... The daemon has exited normally or was terminated in response to a user interrupt. +2026-10-16T08:23:52.079-0400 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Removing daemon address: [b75a6179-a3cc-46eb-b232-ac50885c73f9 port:46139, addresses:[localhost/127.0.0.1]] +2026-10-16T08:23:52.080-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] VM shutdown hook was unable to remove the daemon address from the registry. It will be cleaned up later. +java.lang.IllegalStateException: Cannot start managing file contention because this handler has been closed. + at org.gradle.cache.internal.locklistener.DefaultFileLockContentionHandler.assertNotStopped(DefaultFileLockContentionHandler.java:267) + at org.gradle.cache.internal.locklistener.DefaultFileLockContentionHandler.reservePort(DefaultFileLockContentionHandler.java:312) + at org.gradle.cache.internal.DefaultFileLockManager.lock(DefaultFileLockManager.java:127) + at org.gradle.cache.internal.DefaultFileLockManager.lock(DefaultFileLockManager.java:109) + at org.gradle.cache.internal.DefaultFileLockManager.lock(DefaultFileLockManager.java:104) + at org.gradle.cache.internal.OnDemandFileAccess.updateFile(OnDemandFileAccess.java:51) + at org.gradle.cache.internal.FileBackedObjectHolder.update(FileBackedObjectHolder.java:77) + at org.gradle.cache.internal.FileIntegrityViolationSuppressingObjectHolderDecorator.lambda$update$0(FileIntegrityViolationSuppressingObjectHolderDecorator.java:48) + at org.gradle.cache.internal.FileIntegrityViolationSuppressingObjectHolderDecorator.doUpdate(FileIntegrityViolationSuppressingObjectHolderDecorator.java:58) + at org.gradle.cache.internal.FileIntegrityViolationSuppressingObjectHolderDecorator.update(FileIntegrityViolationSuppressingObjectHolderDecorator.java:48) + at org.gradle.launcher.daemon.registry.PersistentDaemonRegistry.remove(PersistentDaemonRegistry.java:133) + at org.gradle.launcher.daemon.server.Daemon$1.run(Daemon.java:133) + at java.base/java.lang.Thread.run(Thread.java:1583) diff --git a/.gradle-user/daemon/9.7.1/daemon-58347.out.log b/.gradle-user/daemon/9.7.1/daemon-58347.out.log new file mode 100644 index 0000000..2a9033b --- /dev/null +++ b/.gradle-user/daemon/9.7.1/daemon-58347.out.log @@ -0,0 +1,158 @@ +2026-10-16T08:25:04.441-0400 [DEBUG] [org.gradle.launcher.daemon.bootstrap.DaemonMain] Assuming the daemon was started with following jvm opts: [-XX:MaxMetaspaceSize=384m, -XX:+HeapDumpOnOutOfMemoryError, -Xms256m, -Xmx512m, -Dfile.encoding=UTF-8, -Duser.country, -Duser.language=en, -Duser.variant] +2026-10-16T08:25:04.509-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding IP addresses for network interface tailscale0 +2026-10-16T08:25:04.510-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Is this a loopback interface? false +2026-10-16T08:25:04.510-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding remote address /fe80:0:0:0:8d15:7fb2:299f:dced%tailscale0 +2026-10-16T08:25:04.510-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding IP addresses for network interface wlp98s0 +2026-10-16T08:25:04.510-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Is this a loopback interface? false +2026-10-16T08:25:04.511-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding remote address /fe80:0:0:0:6f3f:89e6:b585:4167%wlp98s0 +2026-10-16T08:25:04.511-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding remote address /192.168.27.163 +2026-10-16T08:25:04.511-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding IP addresses for network interface lo +2026-10-16T08:25:04.511-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Is this a loopback interface? true +2026-10-16T08:25:04.511-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding loopback address /0:0:0:0:0:0:0:1%lo +2026-10-16T08:25:04.511-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding loopback address /127.0.0.1 +2026-10-16T08:25:04.541-0400 [INFO] [org.gradle.launcher.daemon.server.Daemon] start() called on daemon - DefaultDaemonContext[uid=c4ce5e45-12f3-4501-ae3c-6ab5cc21beaa,javaHome=/var/home/hellings/.sdkman/candidates/java/21.0.8-tem,javaVersion=21,javaVendor=Eclipse Adoptium,daemonRegistryDir=/var/home/hellings/Documents/mistring/.gradle-user/daemon,pid=58347,idleTimeout=120000,priority=NORMAL,applyInstrumentationAgent=true,nativeServicesMode=ENABLED,daemonOpts=-XX:MaxMetaspaceSize=384m,-XX:+HeapDumpOnOutOfMemoryError,-Xms256m,-Xmx512m,-Dfile.encoding=UTF-8,-Duser.country,-Duser.language=en,-Duser.variant] +2026-10-16T08:25:04.544-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.TcpIncomingConnector] Listening on [82c5398b-dec1-4499-942e-43300431ffef port:37713, addresses:[localhost/127.0.0.1]]. +2026-10-16T08:25:04.547-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] Daemon starting at: Fri Oct 16 08:25:04 EDT 2026, with address: [82c5398b-dec1-4499-942e-43300431ffef port:37713, addresses:[localhost/127.0.0.1]] +2026-10-16T08:25:04.548-0400 [INFO] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Advertising the daemon address to the clients: [82c5398b-dec1-4499-942e-43300431ffef port:37713, addresses:[localhost/127.0.0.1]] +2026-10-16T08:25:04.548-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Advertised daemon context: DefaultDaemonContext[uid=c4ce5e45-12f3-4501-ae3c-6ab5cc21beaa,javaHome=/var/home/hellings/.sdkman/candidates/java/21.0.8-tem,javaVersion=21,javaVendor=Eclipse Adoptium,daemonRegistryDir=/var/home/hellings/Documents/mistring/.gradle-user/daemon,pid=58347,idleTimeout=120000,priority=NORMAL,applyInstrumentationAgent=true,nativeServicesMode=ENABLED,daemonOpts=-XX:MaxMetaspaceSize=384m,-XX:+HeapDumpOnOutOfMemoryError,-Xms256m,-Xmx512m,-Dfile.encoding=UTF-8,-Duser.country,-Duser.language=en,-Duser.variant] +2026-10-16T08:25:04.549-0400 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Storing daemon address: [82c5398b-dec1-4499-942e-43300431ffef port:37713, addresses:[localhost/127.0.0.1]], context: DefaultDaemonContext[uid=c4ce5e45-12f3-4501-ae3c-6ab5cc21beaa,javaHome=/var/home/hellings/.sdkman/candidates/java/21.0.8-tem,javaVersion=21,javaVendor=Eclipse Adoptium,daemonRegistryDir=/var/home/hellings/Documents/mistring/.gradle-user/daemon,pid=58347,idleTimeout=120000,priority=NORMAL,applyInstrumentationAgent=true,nativeServicesMode=ENABLED,daemonOpts=-XX:MaxMetaspaceSize=384m,-XX:+HeapDumpOnOutOfMemoryError,-Xms256m,-Xmx512m,-Dfile.encoding=UTF-8,-Duser.country,-Duser.language=en,-Duser.variant] +2026-10-16T08:25:04.553-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire exclusive lock on daemon addresses registry. +2026-10-16T08:25:04.555-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired on daemon addresses registry. +2026-10-16T08:25:04.558-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on daemon addresses registry. +2026-10-16T08:25:04.559-0400 [LIFECYCLE] [org.gradle.launcher.daemon.server.Daemon] Daemon server started. +2026-10-16T08:25:04.560-0400 [DEBUG] [org.gradle.launcher.daemon.bootstrap.DaemonStartupCommunication] Completed writing the daemon greeting. Closing streams... +2026-10-16T08:25:04.564-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] stopOnExpiration() called on daemon +2026-10-16T08:25:04.566-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] awaitExpiration() called on daemon +2026-10-16T08:25:04.566-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon is running. Sleeping until state changes. +2026-10-16T08:25:04.573-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.TcpIncomingConnector] Accepted connection from /127.0.0.1:48732 to /127.0.0.1:37713. +2026-10-16T08:25:04.587-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 40: received class org.gradle.launcher.daemon.protocol.Build +2026-10-16T08:25:04.587-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultDaemonConnection] thread 40: Received non-IO message from client: Build{id=0194b5e3-1247-489b-b40f-741de4f1c8a2, currentDir=/var/home/hellings/Documents/mistring} +2026-10-16T08:25:04.587-0400 [INFO] [org.gradle.launcher.daemon.server.DefaultIncomingConnectionHandler] Received command: Build{id=0194b5e3-1247-489b-b40f-741de4f1c8a2, currentDir=/var/home/hellings/Documents/mistring}. +2026-10-16T08:25:04.588-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultIncomingConnectionHandler] Starting executing command: Build{id=0194b5e3-1247-489b-b40f-741de4f1c8a2, currentDir=/var/home/hellings/Documents/mistring} with connection: socket connection from /127.0.0.1:37713 to /127.0.0.1:48732. +2026-10-16T08:25:04.589-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Command execution: started DaemonCommandExecution[command = Build{id=0194b5e3-1247-489b-b40f-741de4f1c8a2, currentDir=/var/home/hellings/Documents/mistring}, connection = DefaultDaemonConnection: socket connection from /127.0.0.1:37713 to /127.0.0.1:48732] after 7.833333333333334E-4 minutes of idle +2026-10-16T08:25:04.590-0400 [INFO] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Marking the daemon as busy, address: [82c5398b-dec1-4499-942e-43300431ffef port:37713, addresses:[localhost/127.0.0.1]] +2026-10-16T08:25:04.590-0400 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Marking busy by address: [82c5398b-dec1-4499-942e-43300431ffef port:37713, addresses:[localhost/127.0.0.1]] +2026-10-16T08:25:04.590-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire exclusive lock on daemon addresses registry. +2026-10-16T08:25:04.591-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired on daemon addresses registry. +2026-10-16T08:25:04.592-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on daemon addresses registry. +2026-10-16T08:25:04.592-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] resetting idle timer +2026-10-16T08:25:04.592-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon is running. Sleeping until state changes. +2026-10-16T08:25:04.593-0400 [INFO] [org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy] Daemon is about to start building Build{id=0194b5e3-1247-489b-b40f-741de4f1c8a2, currentDir=/var/home/hellings/Documents/mistring}. Dispatching build started information... +2026-10-16T08:25:04.593-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 42: dispatching org.gradle.launcher.daemon.protocol.BuildStarted@65ba0185 +2026-10-16T08:25:04.595-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.LogToClient] About to start relaying all logs to the client via the connection. +2026-10-16T08:25:04.595-0400 [INFO] [org.gradle.launcher.daemon.server.exec.LogToClient] The client will now receive all logging from the daemon (pid: 58347). The daemon log file: /var/home/hellings/Documents/mistring/.gradle-user/daemon/9.7.1/daemon-58347.out.log +2026-10-16T08:25:04.596-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.ApplyClientEnvironmentVariables] Configuring env variables: [container, PYENV_SHELL, PATH, GNOME_SHELL_SLOWDOWN_FACTOR, HISTCONTROL, XMODIFIERS, GDMSESSION, GUESTFISH_RESTORE, DBUS_SESSION_BUS_ADDRESS, ANDROID_HOME, XDG_CACHE_HOME, GH_PAGER, LD_LIBRARY_PATH, COLORTERM, SDKMAN_DIR, USERNAME, PWD, MANAGERPID, SDKMAN_BROKER_API, GJS_DEBUG_TOPICS, NVM_CD_FLAGS, LESSOPEN, CHROME_DESKTOP, PAGER, SDKMAN_CANDIDATES_API, GUESTFISH_INIT, DEBUGINFOD_IMA_CERT_PATH, LC_ALL, ZSH_TMUX_AUTOSTARTED, LC_CTYPE, GNOME_SETUP_DISPLAY, CODEX_SESSION_ID, SHLVL, QT_IM_MODULES, HISTSIZE, JAVA_HOME, KOTLIN_HOME, MEMORY_PRESSURE_WATCH, RUST_LOG, TERM, XDG_CONFIG_DIRS, MOZ_GMP_PATH, GRADLE_HOME, NVM_INC, GRADLE_USER_HOME, WAYLAND_DISPLAY, STARSHIP_SHELL, CODEX_THREAD_ID, XDG_SESSION_CLASS, DISABLE_AUTO_UPDATE, SWIFTLY_HOME_DIR, DESKTOP_SESSION, XDG_MENU_PREFIX, ZSH_TMUX_AUTOSTART, NVM_BIN, CONTAINER_ID, INVOCATION_ID, XAUTHORITY, XDG_DATA_DIRS, GIT_PAGER, CODEX_MCP_NODE_PATH, CODEX_SHELL, XDG_CURRENT_DESKTOP, JOURNAL_STREAM, MAIL, XDG_STATE_HOME, CODEX_APP_TOOLS_PIPE_PATH, MANAGERPIDFDID, LOGNAME, SWIFTLY_BIN_DIR, PYENV_VIRTUALENV_INIT, CODEX_INTERNAL_ORIGINATOR_OVERRIDE, CODEX_SAGE_BACKFILL_TRACKER_TAB_REUSE, CODEX_SANDBOX_NETWORK_DISABLED, SHELL, GIO_LAUNCHED_DESKTOP_FILE, PYENV_ROOT, CODEX_PERMISSION_PROFILE, LOG_FORMAT, SSH_ASKPASS, DEBUGINFOD_URLS, SYSTEMD_EXEC_PID, XDG_SESSION_DESKTOP, MEMORY_PRESSURE_WRITE, DOCKER_HOST, QT_IM_MODULE, STARSHIP_SESSION_KEY, XDG_SESSION_EXTRA_DEVICE_ACCESS, LANG, EGL_PLATFORM, XDG_SESSION_TYPE, DISPLAY, FC_FONTATIONS, NO_COLOR, SDKMAN_CANDIDATES_DIR, CODEX_CI, GDM_LANG, NVM_DIR, XDG_DATA_HOME, GUESTFISH_PS1, SWIFTLY_TOOLCHAINS_DIR, GDK_BACKEND, FREETOKEN_FT_BIN, GPG_TTY, SDKMAN_PLATFORM, USER, XDG_CONFIG_HOME, GIO_LAUNCHED_DESKTOP_FILE_PID, GJS_DEBUG_OUTPUT, SSH_AUTH_SOCK, EDITOR, HOSTNAME, DISTROBOX_ENTER_PATH, NO_AT_BRIDGE, XDG_RUNTIME_DIR, HOME, TERMINFO_DIRS, GUESTFISH_OUTPUT] +2026-10-16T08:25:04.599-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon] Requesting daemon stop after processing Build{id=0194b5e3-1247-489b-b40f-741de4f1c8a2, currentDir=/var/home/hellings/Documents/mistring} +2026-10-16T08:25:04.599-0400 [LIFECYCLE] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Daemon will be stopped at the end of the build +2026-10-16T08:25:04.599-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Stop as soon as idle requested. The daemon is busy +2026-10-16T08:25:04.599-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon stop has been requested. Sleeping until state changes. +2026-10-16T08:25:04.601-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.ExecuteBuild] The daemon has started executing the build. +2026-10-16T08:25:04.602-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.ExecuteBuild] Executing build with daemon context: DefaultDaemonContext[uid=c4ce5e45-12f3-4501-ae3c-6ab5cc21beaa,javaHome=/var/home/hellings/.sdkman/candidates/java/21.0.8-tem,javaVersion=21,javaVendor=Eclipse Adoptium,daemonRegistryDir=/var/home/hellings/Documents/mistring/.gradle-user/daemon,pid=58347,idleTimeout=120000,priority=NORMAL,applyInstrumentationAgent=true,nativeServicesMode=ENABLED,daemonOpts=-XX:MaxMetaspaceSize=384m,-XX:+HeapDumpOnOutOfMemoryError,-Xms256m,-Xmx512m,-Dfile.encoding=UTF-8,-Duser.country,-Duser.language=en,-Duser.variant] + +BUILD SUCCESSFUL in 5s +4 actionable tasks: 4 executed +2026-10-16T08:25:09.712-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.ExecuteBuild] The daemon has finished executing the build. +2026-10-16T08:25:09.723-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon stop has been requested. Sleeping until state changes. +2026-10-16T08:25:09.723-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Command execution: finished waiting for DaemonCommandExecution[command = Build{id=0194b5e3-1247-489b-b40f-741de4f1c8a2, currentDir=/var/home/hellings/Documents/mistring}, connection = DefaultDaemonConnection: socket connection from /127.0.0.1:37713 to /127.0.0.1:48732]. Result org.gradle.launcher.daemon.server.DaemonStateCoordinator@3f434a3e with state StopRequested +2026-10-16T08:25:09.724-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Command execution: completed DaemonCommandExecution[command = Build{id=0194b5e3-1247-489b-b40f-741de4f1c8a2, currentDir=/var/home/hellings/Documents/mistring}, connection = DefaultDaemonConnection: socket connection from /127.0.0.1:37713 to /127.0.0.1:48732] +2026-10-16T08:25:09.724-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] resetting idle timer +2026-10-16T08:25:09.724-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Marking daemon stopped due to command completed and stop requested. The daemon is not running a build +2026-10-16T08:25:09.724-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon has stopped. +2026-10-16T08:25:09.724-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.ReturnResult] Daemon is dispatching the build result: Success[value=org.gradle.launcher.exec.BuildActionResult@1a6495e0] +2026-10-16T08:25:09.724-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 39: dispatching Success[value=org.gradle.launcher.exec.BuildActionResult@1a6495e0] +2026-10-16T08:25:09.724-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] stop() called on daemon +2026-10-16T08:25:09.724-0400 [INFO] [org.gradle.launcher.daemon.server.Daemon] Stop requested. Daemon is removing its presence from the registry... +2026-10-16T08:25:09.725-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Removing our presence to clients, eg. removing this address from the registry: [82c5398b-dec1-4499-942e-43300431ffef port:37713, addresses:[localhost/127.0.0.1]] +2026-10-16T08:25:09.725-0400 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Removing daemon address: [82c5398b-dec1-4499-942e-43300431ffef port:37713, addresses:[localhost/127.0.0.1]] +2026-10-16T08:25:09.725-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 40: received class org.gradle.launcher.daemon.protocol.CloseInput +2026-10-16T08:25:09.725-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire exclusive lock on daemon addresses registry. +2026-10-16T08:25:09.725-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultIncomingConnectionHandler] Finishing executing command: Build{id=0194b5e3-1247-489b-b40f-741de4f1c8a2, currentDir=/var/home/hellings/Documents/mistring} +2026-10-16T08:25:09.725-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.CleanUpVirtualFileSystemAfterBuild] Cleaning virtual file system after build finished +2026-10-16T08:25:09.726-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired on daemon addresses registry. +2026-10-16T08:25:09.726-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultDaemonConnection] thread 40: Received IO message from client: org.gradle.launcher.daemon.protocol.CloseInput@1d7027d5 +2026-10-16T08:25:09.727-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on daemon addresses registry. +2026-10-16T08:25:09.727-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Address removed from registry. +2026-10-16T08:25:09.766-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 40: received class org.gradle.launcher.daemon.protocol.Finished +2026-10-16T08:25:09.767-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultDaemonConnection] thread 40: Received non-IO message from client: org.gradle.launcher.daemon.protocol.Finished@7690823d +2026-10-16T08:25:09.767-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultIncomingConnectionHandler] Received finished message: org.gradle.launcher.daemon.protocol.Finished@7690823d +2026-10-16T08:25:09.767-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 39: stopping connection +2026-10-16T08:25:09.768-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.SocketConnection] Discarding EOFException: java.io.EOFException +2026-10-16T08:25:09.768-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 40: received null +2026-10-16T08:25:09.768-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultDaemonConnection] thread 40: Received end-of-input from client. +2026-10-16T08:25:09.769-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 39: stopping connection +2026-10-16T08:25:09.769-0400 [DEBUG] [org.gradle.workers.internal.WorkerDaemonClientsManager] Stopping 1 worker daemon(s). +2026-10-16T08:25:09.778-0400 [DEBUG] [org.gradle.process.internal.DefaultExecHandle] Changing state to: SUCCEEDED +2026-10-16T08:25:09.778-0400 [DEBUG] [org.gradle.process.internal.DefaultExecHandle] Process 'Gradle Worker Daemon 1' finished with exit value 0 (state: SUCCEEDED) +2026-10-16T08:25:09.779-0400 [INFO] [org.gradle.workers.internal.WorkerDaemonClientsManager] Stopped 1 worker daemon(s). +2026-10-16T08:25:09.779-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for jars (/var/home/hellings/Documents/mistring/.gradle-user/caches/jars-9) +2026-10-16T08:25:09.780-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on jars (/var/home/hellings/Documents/mistring/.gradle-user/caches/jars-9). +2026-10-16T08:25:09.780-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] jars (/var/home/hellings/Documents/mistring/.gradle-user/caches/jars-9) has last been fully cleaned up 0 hours ago +2026-10-16T08:25:09.780-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] Skipping cleanup for jars (/var/home/hellings/Documents/mistring/.gradle-user/caches/jars-9) as it is not yet due +2026-10-16T08:25:09.780-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for file content cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileContent) +2026-10-16T08:25:09.780-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on file content cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileContent). +2026-10-16T08:25:09.780-0400 [DEBUG] [org.gradle.internal.watch.vfs.impl.WatchingVirtualFileSystem] Closing VFS, dropping state +2026-10-16T08:25:09.781-0400 [DEBUG] [org.gradle.internal.watch.registry.impl.DefaultFileWatcherRegistry] Finished listening to file system change events +2026-10-16T08:25:09.781-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCoordinator] Cache Generated Gradle JARs cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/generated-gradle-jars) was closed 0 times. +2026-10-16T08:25:09.781-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for artifact cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2) +2026-10-16T08:25:09.782-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache module-artifact.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2/metadata-2.107/module-artifact.bin) +2026-10-16T08:25:09.782-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache module-metadata.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2/metadata-2.107/module-metadata.bin) +2026-10-16T08:25:09.782-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on artifact cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2). +2026-10-16T08:25:09.782-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] artifact cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2) has last been fully cleaned up 0 hours ago +2026-10-16T08:25:09.782-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] Skipping cleanup for artifact cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2) as it is not yet due +2026-10-16T08:25:09.782-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] groovy-dsl has last been fully cleaned up 0 hours ago +2026-10-16T08:25:09.782-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] Skipping cleanup for groovy-dsl as it is not yet due +2026-10-16T08:25:09.782-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] Artifact transforms cache has last been fully cleaned up 0 hours ago +2026-10-16T08:25:09.783-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] Skipping cleanup for Artifact transforms cache as it is not yet due +2026-10-16T08:25:09.783-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for journal cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/journal-1) +2026-10-16T08:25:09.783-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache file-access.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/journal-1/file-access.bin) +2026-10-16T08:25:09.783-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on journal cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/journal-1). +2026-10-16T08:25:09.783-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for file hash cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileHashes) +2026-10-16T08:25:09.783-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache fileHashes.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileHashes/fileHashes.bin) +2026-10-16T08:25:09.784-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache resourceHashesCache.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileHashes/resourceHashesCache.bin) +2026-10-16T08:25:09.784-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on file hash cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileHashes). +2026-10-16T08:25:09.784-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for Java compile cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/javaCompile) +2026-10-16T08:25:09.784-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache jarAnalysis.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/javaCompile/jarAnalysis.bin) +2026-10-16T08:25:09.784-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache classAnalysis.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/javaCompile/classAnalysis.bin) +2026-10-16T08:25:09.784-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on Java compile cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/javaCompile). +2026-10-16T08:25:09.785-0400 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationRunner] Build operation 'Deleting unused version-specific caches in /var/home/hellings/Documents/mistring/.gradle-user/caches' started +2026-10-16T08:25:09.785-0400 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationRunner] Completing Build operation 'Deleting unused version-specific caches in /var/home/hellings/Documents/mistring/.gradle-user/caches' +2026-10-16T08:25:09.786-0400 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationRunner] Build operation 'Deleting unused version-specific caches in /var/home/hellings/Documents/mistring/.gradle-user/caches' completed +2026-10-16T08:25:09.786-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] stop() called on daemon +2026-10-16T08:25:09.786-0400 [INFO] [org.gradle.launcher.daemon.server.Daemon] Stop requested. Daemon is removing its presence from the registry... +2026-10-16T08:25:09.786-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Removing our presence to clients, eg. removing this address from the registry: [82c5398b-dec1-4499-942e-43300431ffef port:37713, addresses:[localhost/127.0.0.1]] +2026-10-16T08:25:09.786-0400 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Removing daemon address: [82c5398b-dec1-4499-942e-43300431ffef port:37713, addresses:[localhost/127.0.0.1]] +2026-10-16T08:25:09.786-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire exclusive lock on daemon addresses registry. +2026-10-16T08:25:09.786-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired on daemon addresses registry. +2026-10-16T08:25:09.787-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on daemon addresses registry. +2026-10-16T08:25:09.787-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Address removed from registry. +2026-10-16T08:25:09.787-0400 [DEBUG] [org.gradle.cache.internal.locklistener.DefaultFileLockContentionHandler] File lock listener thread completed. +2026-10-16T08:25:09.789-0400 [DEBUG] [java.lang.Runtime] Runtime.exit() called with status: 0 +java.lang.Throwable: Runtime.exit(0) + at java.base/java.lang.Shutdown.logRuntimeExit(Shutdown.java:179) + at java.base/java.lang.Shutdown.exit(Shutdown.java:160) + at java.base/java.lang.Runtime.exit(Runtime.java:188) + at java.base/java.lang.System.exit(System.java:1920) + at org.gradle.launcher.bootstrap.ProcessCompleter.complete(ProcessCompleter.java:21) + at org.gradle.launcher.bootstrap.EntryPoint.run(EntryPoint.java:62) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.gradle.launcher.bootstrap.ProcessBootstrap.runNoExit(ProcessBootstrap.java:72) + at org.gradle.launcher.bootstrap.ProcessBootstrap.run(ProcessBootstrap.java:39) + at org.gradle.launcher.daemon.bootstrap.GradleDaemon.main(GradleDaemon.java:23) +Daemon vm is shutting down... The daemon has exited normally or was terminated in response to a user interrupt. +2026-10-16T08:25:09.790-0400 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Removing daemon address: [82c5398b-dec1-4499-942e-43300431ffef port:37713, addresses:[localhost/127.0.0.1]] +2026-10-16T08:25:09.790-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] VM shutdown hook was unable to remove the daemon address from the registry. It will be cleaned up later. +java.lang.IllegalStateException: Cannot start managing file contention because this handler has been closed. + at org.gradle.cache.internal.locklistener.DefaultFileLockContentionHandler.assertNotStopped(DefaultFileLockContentionHandler.java:267) + at org.gradle.cache.internal.locklistener.DefaultFileLockContentionHandler.reservePort(DefaultFileLockContentionHandler.java:312) + at org.gradle.cache.internal.DefaultFileLockManager.lock(DefaultFileLockManager.java:127) + at org.gradle.cache.internal.DefaultFileLockManager.lock(DefaultFileLockManager.java:109) + at org.gradle.cache.internal.DefaultFileLockManager.lock(DefaultFileLockManager.java:104) + at org.gradle.cache.internal.OnDemandFileAccess.updateFile(OnDemandFileAccess.java:51) + at org.gradle.cache.internal.FileBackedObjectHolder.update(FileBackedObjectHolder.java:77) + at org.gradle.cache.internal.FileIntegrityViolationSuppressingObjectHolderDecorator.lambda$update$0(FileIntegrityViolationSuppressingObjectHolderDecorator.java:48) + at org.gradle.cache.internal.FileIntegrityViolationSuppressingObjectHolderDecorator.doUpdate(FileIntegrityViolationSuppressingObjectHolderDecorator.java:58) + at org.gradle.cache.internal.FileIntegrityViolationSuppressingObjectHolderDecorator.update(FileIntegrityViolationSuppressingObjectHolderDecorator.java:48) + at org.gradle.launcher.daemon.registry.PersistentDaemonRegistry.remove(PersistentDaemonRegistry.java:133) + at org.gradle.launcher.daemon.server.Daemon$1.run(Daemon.java:133) + at java.base/java.lang.Thread.run(Thread.java:1583) diff --git a/.gradle-user/daemon/9.7.1/daemon-59453.out.log b/.gradle-user/daemon/9.7.1/daemon-59453.out.log new file mode 100644 index 0000000..a7d8a92 --- /dev/null +++ b/.gradle-user/daemon/9.7.1/daemon-59453.out.log @@ -0,0 +1,150 @@ +2026-10-16T08:25:10.521-0400 [DEBUG] [org.gradle.launcher.daemon.bootstrap.DaemonMain] Assuming the daemon was started with following jvm opts: [-XX:MaxMetaspaceSize=384m, -XX:+HeapDumpOnOutOfMemoryError, -Xms256m, -Xmx512m, -Dfile.encoding=UTF-8, -Duser.country, -Duser.language=en, -Duser.variant] +2026-10-16T08:25:10.599-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding IP addresses for network interface tailscale0 +2026-10-16T08:25:10.599-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Is this a loopback interface? false +2026-10-16T08:25:10.600-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding remote address /fe80:0:0:0:8d15:7fb2:299f:dced%tailscale0 +2026-10-16T08:25:10.600-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding IP addresses for network interface wlp98s0 +2026-10-16T08:25:10.600-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Is this a loopback interface? false +2026-10-16T08:25:10.600-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding remote address /fe80:0:0:0:6f3f:89e6:b585:4167%wlp98s0 +2026-10-16T08:25:10.600-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding remote address /192.168.27.163 +2026-10-16T08:25:10.601-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding IP addresses for network interface lo +2026-10-16T08:25:10.601-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Is this a loopback interface? true +2026-10-16T08:25:10.601-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding loopback address /0:0:0:0:0:0:0:1%lo +2026-10-16T08:25:10.601-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding loopback address /127.0.0.1 +2026-10-16T08:25:10.632-0400 [INFO] [org.gradle.launcher.daemon.server.Daemon] start() called on daemon - DefaultDaemonContext[uid=92f6ccb1-76dd-4887-89c2-70745cdbeeb4,javaHome=/var/home/hellings/.sdkman/candidates/java/21.0.8-tem,javaVersion=21,javaVendor=Eclipse Adoptium,daemonRegistryDir=/var/home/hellings/Documents/mistring/.gradle-user/daemon,pid=59453,idleTimeout=120000,priority=NORMAL,applyInstrumentationAgent=true,nativeServicesMode=ENABLED,daemonOpts=-XX:MaxMetaspaceSize=384m,-XX:+HeapDumpOnOutOfMemoryError,-Xms256m,-Xmx512m,-Dfile.encoding=UTF-8,-Duser.country,-Duser.language=en,-Duser.variant] +2026-10-16T08:25:10.635-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.TcpIncomingConnector] Listening on [b5adef14-8fb4-49ea-b8a8-2c90c8ded509 port:46581, addresses:[localhost/127.0.0.1]]. +2026-10-16T08:25:10.638-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] Daemon starting at: Fri Oct 16 08:25:10 EDT 2026, with address: [b5adef14-8fb4-49ea-b8a8-2c90c8ded509 port:46581, addresses:[localhost/127.0.0.1]] +2026-10-16T08:25:10.639-0400 [INFO] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Advertising the daemon address to the clients: [b5adef14-8fb4-49ea-b8a8-2c90c8ded509 port:46581, addresses:[localhost/127.0.0.1]] +2026-10-16T08:25:10.639-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Advertised daemon context: DefaultDaemonContext[uid=92f6ccb1-76dd-4887-89c2-70745cdbeeb4,javaHome=/var/home/hellings/.sdkman/candidates/java/21.0.8-tem,javaVersion=21,javaVendor=Eclipse Adoptium,daemonRegistryDir=/var/home/hellings/Documents/mistring/.gradle-user/daemon,pid=59453,idleTimeout=120000,priority=NORMAL,applyInstrumentationAgent=true,nativeServicesMode=ENABLED,daemonOpts=-XX:MaxMetaspaceSize=384m,-XX:+HeapDumpOnOutOfMemoryError,-Xms256m,-Xmx512m,-Dfile.encoding=UTF-8,-Duser.country,-Duser.language=en,-Duser.variant] +2026-10-16T08:25:10.640-0400 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Storing daemon address: [b5adef14-8fb4-49ea-b8a8-2c90c8ded509 port:46581, addresses:[localhost/127.0.0.1]], context: DefaultDaemonContext[uid=92f6ccb1-76dd-4887-89c2-70745cdbeeb4,javaHome=/var/home/hellings/.sdkman/candidates/java/21.0.8-tem,javaVersion=21,javaVendor=Eclipse Adoptium,daemonRegistryDir=/var/home/hellings/Documents/mistring/.gradle-user/daemon,pid=59453,idleTimeout=120000,priority=NORMAL,applyInstrumentationAgent=true,nativeServicesMode=ENABLED,daemonOpts=-XX:MaxMetaspaceSize=384m,-XX:+HeapDumpOnOutOfMemoryError,-Xms256m,-Xmx512m,-Dfile.encoding=UTF-8,-Duser.country,-Duser.language=en,-Duser.variant] +2026-10-16T08:25:10.644-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire exclusive lock on daemon addresses registry. +2026-10-16T08:25:10.646-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired on daemon addresses registry. +2026-10-16T08:25:10.649-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on daemon addresses registry. +2026-10-16T08:25:10.650-0400 [LIFECYCLE] [org.gradle.launcher.daemon.server.Daemon] Daemon server started. +2026-10-16T08:25:10.651-0400 [DEBUG] [org.gradle.launcher.daemon.bootstrap.DaemonStartupCommunication] Completed writing the daemon greeting. Closing streams... +2026-10-16T08:25:10.657-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] stopOnExpiration() called on daemon +2026-10-16T08:25:10.658-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] awaitExpiration() called on daemon +2026-10-16T08:25:10.659-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon is running. Sleeping until state changes. +2026-10-16T08:25:10.665-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.TcpIncomingConnector] Accepted connection from /127.0.0.1:60654 to /127.0.0.1:46581. +2026-10-16T08:25:10.681-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 40: received class org.gradle.launcher.daemon.protocol.Build +2026-10-16T08:25:10.681-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultDaemonConnection] thread 40: Received non-IO message from client: Build{id=5af9c776-e3c0-4440-a5ce-944d71acde8d, currentDir=/var/home/hellings/Documents/mistring} +2026-10-16T08:25:10.681-0400 [INFO] [org.gradle.launcher.daemon.server.DefaultIncomingConnectionHandler] Received command: Build{id=5af9c776-e3c0-4440-a5ce-944d71acde8d, currentDir=/var/home/hellings/Documents/mistring}. +2026-10-16T08:25:10.682-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultIncomingConnectionHandler] Starting executing command: Build{id=5af9c776-e3c0-4440-a5ce-944d71acde8d, currentDir=/var/home/hellings/Documents/mistring} with connection: socket connection from /127.0.0.1:46581 to /127.0.0.1:60654. +2026-10-16T08:25:10.684-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Command execution: started DaemonCommandExecution[command = Build{id=5af9c776-e3c0-4440-a5ce-944d71acde8d, currentDir=/var/home/hellings/Documents/mistring}, connection = DefaultDaemonConnection: socket connection from /127.0.0.1:46581 to /127.0.0.1:60654] after 8.333333333333334E-4 minutes of idle +2026-10-16T08:25:10.684-0400 [INFO] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Marking the daemon as busy, address: [b5adef14-8fb4-49ea-b8a8-2c90c8ded509 port:46581, addresses:[localhost/127.0.0.1]] +2026-10-16T08:25:10.685-0400 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Marking busy by address: [b5adef14-8fb4-49ea-b8a8-2c90c8ded509 port:46581, addresses:[localhost/127.0.0.1]] +2026-10-16T08:25:10.686-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire exclusive lock on daemon addresses registry. +2026-10-16T08:25:10.686-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired on daemon addresses registry. +2026-10-16T08:25:10.687-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on daemon addresses registry. +2026-10-16T08:25:10.687-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] resetting idle timer +2026-10-16T08:25:10.688-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon is running. Sleeping until state changes. +2026-10-16T08:25:10.688-0400 [INFO] [org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy] Daemon is about to start building Build{id=5af9c776-e3c0-4440-a5ce-944d71acde8d, currentDir=/var/home/hellings/Documents/mistring}. Dispatching build started information... +2026-10-16T08:25:10.689-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 42: dispatching org.gradle.launcher.daemon.protocol.BuildStarted@4b6f8f9c +2026-10-16T08:25:10.690-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.LogToClient] About to start relaying all logs to the client via the connection. +2026-10-16T08:25:10.690-0400 [INFO] [org.gradle.launcher.daemon.server.exec.LogToClient] The client will now receive all logging from the daemon (pid: 59453). The daemon log file: /var/home/hellings/Documents/mistring/.gradle-user/daemon/9.7.1/daemon-59453.out.log +2026-10-16T08:25:10.691-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.ApplyClientEnvironmentVariables] Configuring env variables: [container, PYENV_SHELL, PATH, GNOME_SHELL_SLOWDOWN_FACTOR, HISTCONTROL, XMODIFIERS, GDMSESSION, npm_lifecycle_script, GUESTFISH_RESTORE, DBUS_SESSION_BUS_ADDRESS, ANDROID_HOME, XDG_CACHE_HOME, GH_PAGER, LD_LIBRARY_PATH, COLORTERM, SDKMAN_DIR, USERNAME, PWD, MANAGERPID, SDKMAN_BROKER_API, GJS_DEBUG_TOPICS, NVM_CD_FLAGS, LESSOPEN, CHROME_DESKTOP, PAGER, NODE, SDKMAN_CANDIDATES_API, npm_node_execpath, GUESTFISH_INIT, DEBUGINFOD_IMA_CERT_PATH, LC_ALL, ZSH_TMUX_AUTOSTARTED, LC_CTYPE, GNOME_SETUP_DISPLAY, CODEX_SESSION_ID, SHLVL, QT_IM_MODULES, HISTSIZE, JAVA_HOME, npm_command, KOTLIN_HOME, MEMORY_PRESSURE_WATCH, RUST_LOG, TERM, XDG_CONFIG_DIRS, MOZ_GMP_PATH, GRADLE_HOME, NVM_INC, GRADLE_USER_HOME, WAYLAND_DISPLAY, STARSHIP_SHELL, CODEX_THREAD_ID, XDG_SESSION_CLASS, DISABLE_AUTO_UPDATE, SWIFTLY_HOME_DIR, npm_config_user_agent, DESKTOP_SESSION, XDG_MENU_PREFIX, npm_package_name, ZSH_TMUX_AUTOSTART, NVM_BIN, CONTAINER_ID, INVOCATION_ID, XAUTHORITY, XDG_DATA_DIRS, GIT_PAGER, CODEX_MCP_NODE_PATH, CODEX_SHELL, XDG_CURRENT_DESKTOP, JOURNAL_STREAM, MAIL, XDG_STATE_HOME, CODEX_APP_TOOLS_PIPE_PATH, MANAGERPIDFDID, npm_lifecycle_event, LOGNAME, SWIFTLY_BIN_DIR, PYENV_VIRTUALENV_INIT, CODEX_INTERNAL_ORIGINATOR_OVERRIDE, CODEX_SAGE_BACKFILL_TRACKER_TAB_REUSE, CODEX_SANDBOX_NETWORK_DISABLED, SHELL, GIO_LAUNCHED_DESKTOP_FILE, PYENV_ROOT, CODEX_PERMISSION_PROFILE, LOG_FORMAT, SSH_ASKPASS, DEBUGINFOD_URLS, SYSTEMD_EXEC_PID, XDG_SESSION_DESKTOP, npm_package_json, MEMORY_PRESSURE_WRITE, DOCKER_HOST, QT_IM_MODULE, STARSHIP_SESSION_KEY, XDG_SESSION_EXTRA_DEVICE_ACCESS, LANG, EGL_PLATFORM, XDG_SESSION_TYPE, DISPLAY, FC_FONTATIONS, npm_execpath, NO_COLOR, SDKMAN_CANDIDATES_DIR, CODEX_CI, npm_config_local_prefix, GDM_LANG, NVM_DIR, XDG_DATA_HOME, GUESTFISH_PS1, SWIFTLY_TOOLCHAINS_DIR, GDK_BACKEND, FREETOKEN_FT_BIN, GPG_TTY, SDKMAN_PLATFORM, USER, XDG_CONFIG_HOME, GIO_LAUNCHED_DESKTOP_FILE_PID, GJS_DEBUG_OUTPUT, SSH_AUTH_SOCK, EDITOR, HOSTNAME, DISTROBOX_ENTER_PATH, NO_AT_BRIDGE, XDG_RUNTIME_DIR, HOME, TERMINFO_DIRS, GUESTFISH_OUTPUT] +2026-10-16T08:25:10.695-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon] Requesting daemon stop after processing Build{id=5af9c776-e3c0-4440-a5ce-944d71acde8d, currentDir=/var/home/hellings/Documents/mistring} +2026-10-16T08:25:10.695-0400 [LIFECYCLE] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Daemon will be stopped at the end of the build +2026-10-16T08:25:10.695-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Stop as soon as idle requested. The daemon is busy +2026-10-16T08:25:10.695-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon stop has been requested. Sleeping until state changes. +2026-10-16T08:25:10.697-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.ExecuteBuild] The daemon has started executing the build. +2026-10-16T08:25:10.698-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.ExecuteBuild] Executing build with daemon context: DefaultDaemonContext[uid=92f6ccb1-76dd-4887-89c2-70745cdbeeb4,javaHome=/var/home/hellings/.sdkman/candidates/java/21.0.8-tem,javaVersion=21,javaVendor=Eclipse Adoptium,daemonRegistryDir=/var/home/hellings/Documents/mistring/.gradle-user/daemon,pid=59453,idleTimeout=120000,priority=NORMAL,applyInstrumentationAgent=true,nativeServicesMode=ENABLED,daemonOpts=-XX:MaxMetaspaceSize=384m,-XX:+HeapDumpOnOutOfMemoryError,-Xms256m,-Xmx512m,-Dfile.encoding=UTF-8,-Duser.country,-Duser.language=en,-Duser.variant] + +BUILD SUCCESSFUL in 3s +4 actionable tasks: 1 executed, 3 up-to-date +2026-10-16T08:25:13.845-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.ExecuteBuild] The daemon has finished executing the build. +2026-10-16T08:25:13.847-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon stop has been requested. Sleeping until state changes. +2026-10-16T08:25:13.848-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Command execution: finished waiting for DaemonCommandExecution[command = Build{id=5af9c776-e3c0-4440-a5ce-944d71acde8d, currentDir=/var/home/hellings/Documents/mistring}, connection = DefaultDaemonConnection: socket connection from /127.0.0.1:46581 to /127.0.0.1:60654]. Result org.gradle.launcher.daemon.server.DaemonStateCoordinator@1d0f7463 with state StopRequested +2026-10-16T08:25:13.848-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Command execution: completed DaemonCommandExecution[command = Build{id=5af9c776-e3c0-4440-a5ce-944d71acde8d, currentDir=/var/home/hellings/Documents/mistring}, connection = DefaultDaemonConnection: socket connection from /127.0.0.1:46581 to /127.0.0.1:60654] +2026-10-16T08:25:13.849-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] resetting idle timer +2026-10-16T08:25:13.849-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Marking daemon stopped due to command completed and stop requested. The daemon is not running a build +2026-10-16T08:25:13.849-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon has stopped. +2026-10-16T08:25:13.849-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.ReturnResult] Daemon is dispatching the build result: Success[value=org.gradle.launcher.exec.BuildActionResult@613fbc73] +2026-10-16T08:25:13.849-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 39: dispatching Success[value=org.gradle.launcher.exec.BuildActionResult@613fbc73] +2026-10-16T08:25:13.849-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] stop() called on daemon +2026-10-16T08:25:13.849-0400 [INFO] [org.gradle.launcher.daemon.server.Daemon] Stop requested. Daemon is removing its presence from the registry... +2026-10-16T08:25:13.850-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Removing our presence to clients, eg. removing this address from the registry: [b5adef14-8fb4-49ea-b8a8-2c90c8ded509 port:46581, addresses:[localhost/127.0.0.1]] +2026-10-16T08:25:13.850-0400 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Removing daemon address: [b5adef14-8fb4-49ea-b8a8-2c90c8ded509 port:46581, addresses:[localhost/127.0.0.1]] +2026-10-16T08:25:13.850-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 40: received class org.gradle.launcher.daemon.protocol.CloseInput +2026-10-16T08:25:13.850-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultIncomingConnectionHandler] Finishing executing command: Build{id=5af9c776-e3c0-4440-a5ce-944d71acde8d, currentDir=/var/home/hellings/Documents/mistring} +2026-10-16T08:25:13.850-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.CleanUpVirtualFileSystemAfterBuild] Cleaning virtual file system after build finished +2026-10-16T08:25:13.851-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire exclusive lock on daemon addresses registry. +2026-10-16T08:25:13.851-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultDaemonConnection] thread 40: Received IO message from client: org.gradle.launcher.daemon.protocol.CloseInput@7afb0b64 +2026-10-16T08:25:13.852-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired on daemon addresses registry. +2026-10-16T08:25:13.852-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on daemon addresses registry. +2026-10-16T08:25:13.852-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Address removed from registry. +2026-10-16T08:25:13.890-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 40: received class org.gradle.launcher.daemon.protocol.Finished +2026-10-16T08:25:13.891-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultDaemonConnection] thread 40: Received non-IO message from client: org.gradle.launcher.daemon.protocol.Finished@52bb8d1a +2026-10-16T08:25:13.891-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultIncomingConnectionHandler] Received finished message: org.gradle.launcher.daemon.protocol.Finished@52bb8d1a +2026-10-16T08:25:13.891-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 39: stopping connection +2026-10-16T08:25:13.892-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.SocketConnection] Discarding EOFException: java.io.EOFException +2026-10-16T08:25:13.892-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 40: received null +2026-10-16T08:25:13.892-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultDaemonConnection] thread 40: Received end-of-input from client. +2026-10-16T08:25:13.892-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 39: stopping connection +2026-10-16T08:25:13.896-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for jars (/var/home/hellings/Documents/mistring/.gradle-user/caches/jars-9) +2026-10-16T08:25:13.896-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on jars (/var/home/hellings/Documents/mistring/.gradle-user/caches/jars-9). +2026-10-16T08:25:13.896-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] jars (/var/home/hellings/Documents/mistring/.gradle-user/caches/jars-9) has last been fully cleaned up 0 hours ago +2026-10-16T08:25:13.897-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] Skipping cleanup for jars (/var/home/hellings/Documents/mistring/.gradle-user/caches/jars-9) as it is not yet due +2026-10-16T08:25:13.897-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for file content cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileContent) +2026-10-16T08:25:13.897-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on file content cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileContent). +2026-10-16T08:25:13.897-0400 [DEBUG] [org.gradle.internal.watch.vfs.impl.WatchingVirtualFileSystem] Closing VFS, dropping state +2026-10-16T08:25:13.898-0400 [DEBUG] [org.gradle.internal.watch.registry.impl.DefaultFileWatcherRegistry] Finished listening to file system change events +2026-10-16T08:25:13.898-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCoordinator] Cache Generated Gradle JARs cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/generated-gradle-jars) was closed 0 times. +2026-10-16T08:25:13.898-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for artifact cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2) +2026-10-16T08:25:13.898-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache module-artifact.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2/metadata-2.107/module-artifact.bin) +2026-10-16T08:25:13.898-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache module-metadata.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2/metadata-2.107/module-metadata.bin) +2026-10-16T08:25:13.898-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on artifact cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2). +2026-10-16T08:25:13.899-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] artifact cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2) has last been fully cleaned up 0 hours ago +2026-10-16T08:25:13.899-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] Skipping cleanup for artifact cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2) as it is not yet due +2026-10-16T08:25:13.899-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] groovy-dsl has last been fully cleaned up 0 hours ago +2026-10-16T08:25:13.899-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] Skipping cleanup for groovy-dsl as it is not yet due +2026-10-16T08:25:13.899-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] Artifact transforms cache has last been fully cleaned up 0 hours ago +2026-10-16T08:25:13.899-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] Skipping cleanup for Artifact transforms cache as it is not yet due +2026-10-16T08:25:13.899-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for journal cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/journal-1) +2026-10-16T08:25:13.899-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache file-access.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/journal-1/file-access.bin) +2026-10-16T08:25:13.900-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on journal cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/journal-1). +2026-10-16T08:25:13.900-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for file hash cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileHashes) +2026-10-16T08:25:13.900-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache fileHashes.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileHashes/fileHashes.bin) +2026-10-16T08:25:13.900-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache resourceHashesCache.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileHashes/resourceHashesCache.bin) +2026-10-16T08:25:13.900-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on file hash cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileHashes). +2026-10-16T08:25:13.901-0400 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationRunner] Build operation 'Deleting unused version-specific caches in /var/home/hellings/Documents/mistring/.gradle-user/caches' started +2026-10-16T08:25:13.901-0400 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationRunner] Completing Build operation 'Deleting unused version-specific caches in /var/home/hellings/Documents/mistring/.gradle-user/caches' +2026-10-16T08:25:13.901-0400 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationRunner] Build operation 'Deleting unused version-specific caches in /var/home/hellings/Documents/mistring/.gradle-user/caches' completed +2026-10-16T08:25:13.902-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] stop() called on daemon +2026-10-16T08:25:13.902-0400 [INFO] [org.gradle.launcher.daemon.server.Daemon] Stop requested. Daemon is removing its presence from the registry... +2026-10-16T08:25:13.902-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Removing our presence to clients, eg. removing this address from the registry: [b5adef14-8fb4-49ea-b8a8-2c90c8ded509 port:46581, addresses:[localhost/127.0.0.1]] +2026-10-16T08:25:13.902-0400 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Removing daemon address: [b5adef14-8fb4-49ea-b8a8-2c90c8ded509 port:46581, addresses:[localhost/127.0.0.1]] +2026-10-16T08:25:13.902-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire exclusive lock on daemon addresses registry. +2026-10-16T08:25:13.902-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired on daemon addresses registry. +2026-10-16T08:25:13.903-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on daemon addresses registry. +2026-10-16T08:25:13.903-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Address removed from registry. +2026-10-16T08:25:13.903-0400 [DEBUG] [org.gradle.cache.internal.locklistener.DefaultFileLockContentionHandler] File lock listener thread completed. +2026-10-16T08:25:13.905-0400 [DEBUG] [java.lang.Runtime] Runtime.exit() called with status: 0 +java.lang.Throwable: Runtime.exit(0) + at java.base/java.lang.Shutdown.logRuntimeExit(Shutdown.java:179) + at java.base/java.lang.Shutdown.exit(Shutdown.java:160) + at java.base/java.lang.Runtime.exit(Runtime.java:188) + at java.base/java.lang.System.exit(System.java:1920) + at org.gradle.launcher.bootstrap.ProcessCompleter.complete(ProcessCompleter.java:21) + at org.gradle.launcher.bootstrap.EntryPoint.run(EntryPoint.java:62) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.gradle.launcher.bootstrap.ProcessBootstrap.runNoExit(ProcessBootstrap.java:72) + at org.gradle.launcher.bootstrap.ProcessBootstrap.run(ProcessBootstrap.java:39) + at org.gradle.launcher.daemon.bootstrap.GradleDaemon.main(GradleDaemon.java:23) +Daemon vm is shutting down... The daemon has exited normally or was terminated in response to a user interrupt. +2026-10-16T08:25:13.906-0400 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Removing daemon address: [b5adef14-8fb4-49ea-b8a8-2c90c8ded509 port:46581, addresses:[localhost/127.0.0.1]] +2026-10-16T08:25:13.906-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] VM shutdown hook was unable to remove the daemon address from the registry. It will be cleaned up later. +java.lang.IllegalStateException: Cannot start managing file contention because this handler has been closed. + at org.gradle.cache.internal.locklistener.DefaultFileLockContentionHandler.assertNotStopped(DefaultFileLockContentionHandler.java:267) + at org.gradle.cache.internal.locklistener.DefaultFileLockContentionHandler.reservePort(DefaultFileLockContentionHandler.java:312) + at org.gradle.cache.internal.DefaultFileLockManager.lock(DefaultFileLockManager.java:127) + at org.gradle.cache.internal.DefaultFileLockManager.lock(DefaultFileLockManager.java:109) + at org.gradle.cache.internal.DefaultFileLockManager.lock(DefaultFileLockManager.java:104) + at org.gradle.cache.internal.OnDemandFileAccess.updateFile(OnDemandFileAccess.java:51) + at org.gradle.cache.internal.FileBackedObjectHolder.update(FileBackedObjectHolder.java:77) + at org.gradle.cache.internal.FileIntegrityViolationSuppressingObjectHolderDecorator.lambda$update$0(FileIntegrityViolationSuppressingObjectHolderDecorator.java:48) + at org.gradle.cache.internal.FileIntegrityViolationSuppressingObjectHolderDecorator.doUpdate(FileIntegrityViolationSuppressingObjectHolderDecorator.java:58) + at org.gradle.cache.internal.FileIntegrityViolationSuppressingObjectHolderDecorator.update(FileIntegrityViolationSuppressingObjectHolderDecorator.java:48) + at org.gradle.launcher.daemon.registry.PersistentDaemonRegistry.remove(PersistentDaemonRegistry.java:133) + at org.gradle.launcher.daemon.server.Daemon$1.run(Daemon.java:133) + at java.base/java.lang.Thread.run(Thread.java:1583) diff --git a/.gradle-user/daemon/9.7.1/daemon-62585.out.log b/.gradle-user/daemon/9.7.1/daemon-62585.out.log new file mode 100644 index 0000000..5feac9d --- /dev/null +++ b/.gradle-user/daemon/9.7.1/daemon-62585.out.log @@ -0,0 +1,158 @@ +2026-10-16T08:26:40.719-0400 [DEBUG] [org.gradle.launcher.daemon.bootstrap.DaemonMain] Assuming the daemon was started with following jvm opts: [-XX:MaxMetaspaceSize=384m, -XX:+HeapDumpOnOutOfMemoryError, -Xms256m, -Xmx512m, -Dfile.encoding=UTF-8, -Duser.country, -Duser.language=en, -Duser.variant] +2026-10-16T08:26:40.778-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding IP addresses for network interface tailscale0 +2026-10-16T08:26:40.778-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Is this a loopback interface? false +2026-10-16T08:26:40.778-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding remote address /fe80:0:0:0:8d15:7fb2:299f:dced%tailscale0 +2026-10-16T08:26:40.779-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding IP addresses for network interface wlp98s0 +2026-10-16T08:26:40.779-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Is this a loopback interface? false +2026-10-16T08:26:40.779-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding remote address /fe80:0:0:0:6f3f:89e6:b585:4167%wlp98s0 +2026-10-16T08:26:40.779-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding remote address /192.168.27.163 +2026-10-16T08:26:40.779-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding IP addresses for network interface lo +2026-10-16T08:26:40.780-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Is this a loopback interface? true +2026-10-16T08:26:40.780-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding loopback address /0:0:0:0:0:0:0:1%lo +2026-10-16T08:26:40.780-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding loopback address /127.0.0.1 +2026-10-16T08:26:40.809-0400 [INFO] [org.gradle.launcher.daemon.server.Daemon] start() called on daemon - DefaultDaemonContext[uid=dd022c39-0ee2-4a5e-9150-2c66ac2c0ce2,javaHome=/var/home/hellings/.sdkman/candidates/java/21.0.8-tem,javaVersion=21,javaVendor=Eclipse Adoptium,daemonRegistryDir=/var/home/hellings/Documents/mistring/.gradle-user/daemon,pid=62585,idleTimeout=120000,priority=NORMAL,applyInstrumentationAgent=true,nativeServicesMode=ENABLED,daemonOpts=-XX:MaxMetaspaceSize=384m,-XX:+HeapDumpOnOutOfMemoryError,-Xms256m,-Xmx512m,-Dfile.encoding=UTF-8,-Duser.country,-Duser.language=en,-Duser.variant] +2026-10-16T08:26:40.812-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.TcpIncomingConnector] Listening on [e423e685-08b9-458f-b734-bc49ba8a7edf port:42257, addresses:[localhost/127.0.0.1]]. +2026-10-16T08:26:40.816-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] Daemon starting at: Fri Oct 16 08:26:40 EDT 2026, with address: [e423e685-08b9-458f-b734-bc49ba8a7edf port:42257, addresses:[localhost/127.0.0.1]] +2026-10-16T08:26:40.817-0400 [INFO] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Advertising the daemon address to the clients: [e423e685-08b9-458f-b734-bc49ba8a7edf port:42257, addresses:[localhost/127.0.0.1]] +2026-10-16T08:26:40.817-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Advertised daemon context: DefaultDaemonContext[uid=dd022c39-0ee2-4a5e-9150-2c66ac2c0ce2,javaHome=/var/home/hellings/.sdkman/candidates/java/21.0.8-tem,javaVersion=21,javaVendor=Eclipse Adoptium,daemonRegistryDir=/var/home/hellings/Documents/mistring/.gradle-user/daemon,pid=62585,idleTimeout=120000,priority=NORMAL,applyInstrumentationAgent=true,nativeServicesMode=ENABLED,daemonOpts=-XX:MaxMetaspaceSize=384m,-XX:+HeapDumpOnOutOfMemoryError,-Xms256m,-Xmx512m,-Dfile.encoding=UTF-8,-Duser.country,-Duser.language=en,-Duser.variant] +2026-10-16T08:26:40.818-0400 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Storing daemon address: [e423e685-08b9-458f-b734-bc49ba8a7edf port:42257, addresses:[localhost/127.0.0.1]], context: DefaultDaemonContext[uid=dd022c39-0ee2-4a5e-9150-2c66ac2c0ce2,javaHome=/var/home/hellings/.sdkman/candidates/java/21.0.8-tem,javaVersion=21,javaVendor=Eclipse Adoptium,daemonRegistryDir=/var/home/hellings/Documents/mistring/.gradle-user/daemon,pid=62585,idleTimeout=120000,priority=NORMAL,applyInstrumentationAgent=true,nativeServicesMode=ENABLED,daemonOpts=-XX:MaxMetaspaceSize=384m,-XX:+HeapDumpOnOutOfMemoryError,-Xms256m,-Xmx512m,-Dfile.encoding=UTF-8,-Duser.country,-Duser.language=en,-Duser.variant] +2026-10-16T08:26:40.822-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire exclusive lock on daemon addresses registry. +2026-10-16T08:26:40.823-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired on daemon addresses registry. +2026-10-16T08:26:40.826-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on daemon addresses registry. +2026-10-16T08:26:40.827-0400 [LIFECYCLE] [org.gradle.launcher.daemon.server.Daemon] Daemon server started. +2026-10-16T08:26:40.828-0400 [DEBUG] [org.gradle.launcher.daemon.bootstrap.DaemonStartupCommunication] Completed writing the daemon greeting. Closing streams... +2026-10-16T08:26:40.832-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] stopOnExpiration() called on daemon +2026-10-16T08:26:40.833-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] awaitExpiration() called on daemon +2026-10-16T08:26:40.833-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon is running. Sleeping until state changes. +2026-10-16T08:26:40.840-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.TcpIncomingConnector] Accepted connection from /127.0.0.1:49028 to /127.0.0.1:42257. +2026-10-16T08:26:40.854-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 40: received class org.gradle.launcher.daemon.protocol.Build +2026-10-16T08:26:40.854-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultDaemonConnection] thread 40: Received non-IO message from client: Build{id=22a83cf1-2a5b-4a2f-ac99-b7ad8e95adbd, currentDir=/var/home/hellings/Documents/mistring} +2026-10-16T08:26:40.855-0400 [INFO] [org.gradle.launcher.daemon.server.DefaultIncomingConnectionHandler] Received command: Build{id=22a83cf1-2a5b-4a2f-ac99-b7ad8e95adbd, currentDir=/var/home/hellings/Documents/mistring}. +2026-10-16T08:26:40.855-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultIncomingConnectionHandler] Starting executing command: Build{id=22a83cf1-2a5b-4a2f-ac99-b7ad8e95adbd, currentDir=/var/home/hellings/Documents/mistring} with connection: socket connection from /127.0.0.1:42257 to /127.0.0.1:49028. +2026-10-16T08:26:40.856-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Command execution: started DaemonCommandExecution[command = Build{id=22a83cf1-2a5b-4a2f-ac99-b7ad8e95adbd, currentDir=/var/home/hellings/Documents/mistring}, connection = DefaultDaemonConnection: socket connection from /127.0.0.1:42257 to /127.0.0.1:49028] after 7.666666666666667E-4 minutes of idle +2026-10-16T08:26:40.857-0400 [INFO] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Marking the daemon as busy, address: [e423e685-08b9-458f-b734-bc49ba8a7edf port:42257, addresses:[localhost/127.0.0.1]] +2026-10-16T08:26:40.857-0400 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Marking busy by address: [e423e685-08b9-458f-b734-bc49ba8a7edf port:42257, addresses:[localhost/127.0.0.1]] +2026-10-16T08:26:40.857-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire exclusive lock on daemon addresses registry. +2026-10-16T08:26:40.858-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired on daemon addresses registry. +2026-10-16T08:26:40.858-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on daemon addresses registry. +2026-10-16T08:26:40.859-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] resetting idle timer +2026-10-16T08:26:40.859-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon is running. Sleeping until state changes. +2026-10-16T08:26:40.860-0400 [INFO] [org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy] Daemon is about to start building Build{id=22a83cf1-2a5b-4a2f-ac99-b7ad8e95adbd, currentDir=/var/home/hellings/Documents/mistring}. Dispatching build started information... +2026-10-16T08:26:40.860-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 42: dispatching org.gradle.launcher.daemon.protocol.BuildStarted@4c69ac59 +2026-10-16T08:26:40.861-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.LogToClient] About to start relaying all logs to the client via the connection. +2026-10-16T08:26:40.862-0400 [INFO] [org.gradle.launcher.daemon.server.exec.LogToClient] The client will now receive all logging from the daemon (pid: 62585). The daemon log file: /var/home/hellings/Documents/mistring/.gradle-user/daemon/9.7.1/daemon-62585.out.log +2026-10-16T08:26:40.863-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.ApplyClientEnvironmentVariables] Configuring env variables: [container, PYENV_SHELL, PATH, GNOME_SHELL_SLOWDOWN_FACTOR, HISTCONTROL, XMODIFIERS, GDMSESSION, GUESTFISH_RESTORE, DBUS_SESSION_BUS_ADDRESS, ANDROID_HOME, XDG_CACHE_HOME, GH_PAGER, LD_LIBRARY_PATH, COLORTERM, SDKMAN_DIR, USERNAME, PWD, MANAGERPID, SDKMAN_BROKER_API, GJS_DEBUG_TOPICS, NVM_CD_FLAGS, LESSOPEN, CHROME_DESKTOP, PAGER, SDKMAN_CANDIDATES_API, GUESTFISH_INIT, DEBUGINFOD_IMA_CERT_PATH, LC_ALL, ZSH_TMUX_AUTOSTARTED, LC_CTYPE, GNOME_SETUP_DISPLAY, CODEX_SESSION_ID, SHLVL, QT_IM_MODULES, HISTSIZE, JAVA_HOME, KOTLIN_HOME, MEMORY_PRESSURE_WATCH, RUST_LOG, TERM, XDG_CONFIG_DIRS, MOZ_GMP_PATH, GRADLE_HOME, NVM_INC, GRADLE_USER_HOME, WAYLAND_DISPLAY, STARSHIP_SHELL, CODEX_THREAD_ID, XDG_SESSION_CLASS, DISABLE_AUTO_UPDATE, SWIFTLY_HOME_DIR, DESKTOP_SESSION, XDG_MENU_PREFIX, ZSH_TMUX_AUTOSTART, NVM_BIN, CONTAINER_ID, INVOCATION_ID, XAUTHORITY, XDG_DATA_DIRS, GIT_PAGER, CODEX_MCP_NODE_PATH, CODEX_SHELL, XDG_CURRENT_DESKTOP, JOURNAL_STREAM, MAIL, XDG_STATE_HOME, CODEX_APP_TOOLS_PIPE_PATH, MANAGERPIDFDID, LOGNAME, SWIFTLY_BIN_DIR, PYENV_VIRTUALENV_INIT, CODEX_INTERNAL_ORIGINATOR_OVERRIDE, CODEX_SAGE_BACKFILL_TRACKER_TAB_REUSE, CODEX_SANDBOX_NETWORK_DISABLED, SHELL, GIO_LAUNCHED_DESKTOP_FILE, PYENV_ROOT, CODEX_PERMISSION_PROFILE, LOG_FORMAT, SSH_ASKPASS, DEBUGINFOD_URLS, SYSTEMD_EXEC_PID, XDG_SESSION_DESKTOP, MEMORY_PRESSURE_WRITE, DOCKER_HOST, QT_IM_MODULE, STARSHIP_SESSION_KEY, XDG_SESSION_EXTRA_DEVICE_ACCESS, LANG, EGL_PLATFORM, XDG_SESSION_TYPE, DISPLAY, FC_FONTATIONS, NO_COLOR, SDKMAN_CANDIDATES_DIR, CODEX_CI, GDM_LANG, NVM_DIR, XDG_DATA_HOME, GUESTFISH_PS1, SWIFTLY_TOOLCHAINS_DIR, GDK_BACKEND, FREETOKEN_FT_BIN, GPG_TTY, SDKMAN_PLATFORM, USER, XDG_CONFIG_HOME, GIO_LAUNCHED_DESKTOP_FILE_PID, GJS_DEBUG_OUTPUT, SSH_AUTH_SOCK, EDITOR, HOSTNAME, DISTROBOX_ENTER_PATH, NO_AT_BRIDGE, XDG_RUNTIME_DIR, HOME, TERMINFO_DIRS, GUESTFISH_OUTPUT] +2026-10-16T08:26:40.867-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon] Requesting daemon stop after processing Build{id=22a83cf1-2a5b-4a2f-ac99-b7ad8e95adbd, currentDir=/var/home/hellings/Documents/mistring} +2026-10-16T08:26:40.868-0400 [LIFECYCLE] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Daemon will be stopped at the end of the build +2026-10-16T08:26:40.868-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Stop as soon as idle requested. The daemon is busy +2026-10-16T08:26:40.868-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon stop has been requested. Sleeping until state changes. +2026-10-16T08:26:40.870-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.ExecuteBuild] The daemon has started executing the build. +2026-10-16T08:26:40.871-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.ExecuteBuild] Executing build with daemon context: DefaultDaemonContext[uid=dd022c39-0ee2-4a5e-9150-2c66ac2c0ce2,javaHome=/var/home/hellings/.sdkman/candidates/java/21.0.8-tem,javaVersion=21,javaVendor=Eclipse Adoptium,daemonRegistryDir=/var/home/hellings/Documents/mistring/.gradle-user/daemon,pid=62585,idleTimeout=120000,priority=NORMAL,applyInstrumentationAgent=true,nativeServicesMode=ENABLED,daemonOpts=-XX:MaxMetaspaceSize=384m,-XX:+HeapDumpOnOutOfMemoryError,-Xms256m,-Xmx512m,-Dfile.encoding=UTF-8,-Duser.country,-Duser.language=en,-Duser.variant] + +BUILD SUCCESSFUL in 5s +4 actionable tasks: 4 executed +2026-10-16T08:26:45.327-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.ExecuteBuild] The daemon has finished executing the build. +2026-10-16T08:26:45.338-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon stop has been requested. Sleeping until state changes. +2026-10-16T08:26:45.338-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Command execution: finished waiting for DaemonCommandExecution[command = Build{id=22a83cf1-2a5b-4a2f-ac99-b7ad8e95adbd, currentDir=/var/home/hellings/Documents/mistring}, connection = DefaultDaemonConnection: socket connection from /127.0.0.1:42257 to /127.0.0.1:49028]. Result org.gradle.launcher.daemon.server.DaemonStateCoordinator@4e085dc with state StopRequested +2026-10-16T08:26:45.339-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Command execution: completed DaemonCommandExecution[command = Build{id=22a83cf1-2a5b-4a2f-ac99-b7ad8e95adbd, currentDir=/var/home/hellings/Documents/mistring}, connection = DefaultDaemonConnection: socket connection from /127.0.0.1:42257 to /127.0.0.1:49028] +2026-10-16T08:26:45.339-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] resetting idle timer +2026-10-16T08:26:45.339-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Marking daemon stopped due to command completed and stop requested. The daemon is not running a build +2026-10-16T08:26:45.339-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon has stopped. +2026-10-16T08:26:45.339-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.ReturnResult] Daemon is dispatching the build result: Success[value=org.gradle.launcher.exec.BuildActionResult@7ac022b6] +2026-10-16T08:26:45.339-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 39: dispatching Success[value=org.gradle.launcher.exec.BuildActionResult@7ac022b6] +2026-10-16T08:26:45.340-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] stop() called on daemon +2026-10-16T08:26:45.340-0400 [INFO] [org.gradle.launcher.daemon.server.Daemon] Stop requested. Daemon is removing its presence from the registry... +2026-10-16T08:26:45.340-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Removing our presence to clients, eg. removing this address from the registry: [e423e685-08b9-458f-b734-bc49ba8a7edf port:42257, addresses:[localhost/127.0.0.1]] +2026-10-16T08:26:45.340-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.CleanUpVirtualFileSystemAfterBuild] Cleaning virtual file system after build finished +2026-10-16T08:26:45.340-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultIncomingConnectionHandler] Finishing executing command: Build{id=22a83cf1-2a5b-4a2f-ac99-b7ad8e95adbd, currentDir=/var/home/hellings/Documents/mistring} +2026-10-16T08:26:45.340-0400 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Removing daemon address: [e423e685-08b9-458f-b734-bc49ba8a7edf port:42257, addresses:[localhost/127.0.0.1]] +2026-10-16T08:26:45.341-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 40: received class org.gradle.launcher.daemon.protocol.CloseInput +2026-10-16T08:26:45.341-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultDaemonConnection] thread 40: Received IO message from client: org.gradle.launcher.daemon.protocol.CloseInput@45b7004f +2026-10-16T08:26:45.342-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire exclusive lock on daemon addresses registry. +2026-10-16T08:26:45.342-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired on daemon addresses registry. +2026-10-16T08:26:45.343-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on daemon addresses registry. +2026-10-16T08:26:45.343-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Address removed from registry. +2026-10-16T08:26:45.381-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 40: received class org.gradle.launcher.daemon.protocol.Finished +2026-10-16T08:26:45.381-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultDaemonConnection] thread 40: Received non-IO message from client: org.gradle.launcher.daemon.protocol.Finished@4d8fd656 +2026-10-16T08:26:45.382-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultIncomingConnectionHandler] Received finished message: org.gradle.launcher.daemon.protocol.Finished@4d8fd656 +2026-10-16T08:26:45.382-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 39: stopping connection +2026-10-16T08:26:45.383-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.SocketConnection] Discarding EOFException: java.io.EOFException +2026-10-16T08:26:45.383-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 40: received null +2026-10-16T08:26:45.383-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultDaemonConnection] thread 40: Received end-of-input from client. +2026-10-16T08:26:45.383-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 39: stopping connection +2026-10-16T08:26:45.384-0400 [DEBUG] [org.gradle.workers.internal.WorkerDaemonClientsManager] Stopping 1 worker daemon(s). +2026-10-16T08:26:45.404-0400 [DEBUG] [org.gradle.process.internal.DefaultExecHandle] Changing state to: SUCCEEDED +2026-10-16T08:26:45.404-0400 [DEBUG] [org.gradle.process.internal.DefaultExecHandle] Process 'Gradle Worker Daemon 1' finished with exit value 0 (state: SUCCEEDED) +2026-10-16T08:26:45.405-0400 [INFO] [org.gradle.workers.internal.WorkerDaemonClientsManager] Stopped 1 worker daemon(s). +2026-10-16T08:26:45.406-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for jars (/var/home/hellings/Documents/mistring/.gradle-user/caches/jars-9) +2026-10-16T08:26:45.406-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on jars (/var/home/hellings/Documents/mistring/.gradle-user/caches/jars-9). +2026-10-16T08:26:45.407-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] jars (/var/home/hellings/Documents/mistring/.gradle-user/caches/jars-9) has last been fully cleaned up 0 hours ago +2026-10-16T08:26:45.407-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] Skipping cleanup for jars (/var/home/hellings/Documents/mistring/.gradle-user/caches/jars-9) as it is not yet due +2026-10-16T08:26:45.407-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for file content cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileContent) +2026-10-16T08:26:45.407-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on file content cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileContent). +2026-10-16T08:26:45.407-0400 [DEBUG] [org.gradle.internal.watch.vfs.impl.WatchingVirtualFileSystem] Closing VFS, dropping state +2026-10-16T08:26:45.408-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCoordinator] Cache Generated Gradle JARs cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/generated-gradle-jars) was closed 0 times. +2026-10-16T08:26:45.408-0400 [DEBUG] [org.gradle.internal.watch.registry.impl.DefaultFileWatcherRegistry] Finished listening to file system change events +2026-10-16T08:26:45.408-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for artifact cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2) +2026-10-16T08:26:45.408-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache module-artifact.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2/metadata-2.107/module-artifact.bin) +2026-10-16T08:26:45.408-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache module-metadata.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2/metadata-2.107/module-metadata.bin) +2026-10-16T08:26:45.408-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on artifact cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2). +2026-10-16T08:26:45.408-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] artifact cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2) has last been fully cleaned up 0 hours ago +2026-10-16T08:26:45.409-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] Skipping cleanup for artifact cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2) as it is not yet due +2026-10-16T08:26:45.409-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] groovy-dsl has last been fully cleaned up 0 hours ago +2026-10-16T08:26:45.409-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] Skipping cleanup for groovy-dsl as it is not yet due +2026-10-16T08:26:45.409-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] Artifact transforms cache has last been fully cleaned up 0 hours ago +2026-10-16T08:26:45.409-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] Skipping cleanup for Artifact transforms cache as it is not yet due +2026-10-16T08:26:45.409-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for journal cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/journal-1) +2026-10-16T08:26:45.409-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache file-access.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/journal-1/file-access.bin) +2026-10-16T08:26:45.409-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on journal cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/journal-1). +2026-10-16T08:26:45.409-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for file hash cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileHashes) +2026-10-16T08:26:45.409-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache fileHashes.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileHashes/fileHashes.bin) +2026-10-16T08:26:45.409-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache resourceHashesCache.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileHashes/resourceHashesCache.bin) +2026-10-16T08:26:45.409-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on file hash cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileHashes). +2026-10-16T08:26:45.410-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for Java compile cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/javaCompile) +2026-10-16T08:26:45.410-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache jarAnalysis.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/javaCompile/jarAnalysis.bin) +2026-10-16T08:26:45.410-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache classAnalysis.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/javaCompile/classAnalysis.bin) +2026-10-16T08:26:45.410-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on Java compile cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/javaCompile). +2026-10-16T08:26:45.411-0400 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationRunner] Build operation 'Deleting unused version-specific caches in /var/home/hellings/Documents/mistring/.gradle-user/caches' started +2026-10-16T08:26:45.411-0400 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationRunner] Completing Build operation 'Deleting unused version-specific caches in /var/home/hellings/Documents/mistring/.gradle-user/caches' +2026-10-16T08:26:45.411-0400 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationRunner] Build operation 'Deleting unused version-specific caches in /var/home/hellings/Documents/mistring/.gradle-user/caches' completed +2026-10-16T08:26:45.411-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] stop() called on daemon +2026-10-16T08:26:45.411-0400 [INFO] [org.gradle.launcher.daemon.server.Daemon] Stop requested. Daemon is removing its presence from the registry... +2026-10-16T08:26:45.411-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Removing our presence to clients, eg. removing this address from the registry: [e423e685-08b9-458f-b734-bc49ba8a7edf port:42257, addresses:[localhost/127.0.0.1]] +2026-10-16T08:26:45.411-0400 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Removing daemon address: [e423e685-08b9-458f-b734-bc49ba8a7edf port:42257, addresses:[localhost/127.0.0.1]] +2026-10-16T08:26:45.411-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire exclusive lock on daemon addresses registry. +2026-10-16T08:26:45.411-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired on daemon addresses registry. +2026-10-16T08:26:45.412-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on daemon addresses registry. +2026-10-16T08:26:45.412-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Address removed from registry. +2026-10-16T08:26:45.412-0400 [DEBUG] [org.gradle.cache.internal.locklistener.DefaultFileLockContentionHandler] File lock listener thread completed. +2026-10-16T08:26:45.414-0400 [DEBUG] [java.lang.Runtime] Runtime.exit() called with status: 0 +java.lang.Throwable: Runtime.exit(0) + at java.base/java.lang.Shutdown.logRuntimeExit(Shutdown.java:179) + at java.base/java.lang.Shutdown.exit(Shutdown.java:160) + at java.base/java.lang.Runtime.exit(Runtime.java:188) + at java.base/java.lang.System.exit(System.java:1920) + at org.gradle.launcher.bootstrap.ProcessCompleter.complete(ProcessCompleter.java:21) + at org.gradle.launcher.bootstrap.EntryPoint.run(EntryPoint.java:62) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.gradle.launcher.bootstrap.ProcessBootstrap.runNoExit(ProcessBootstrap.java:72) + at org.gradle.launcher.bootstrap.ProcessBootstrap.run(ProcessBootstrap.java:39) + at org.gradle.launcher.daemon.bootstrap.GradleDaemon.main(GradleDaemon.java:23) +Daemon vm is shutting down... The daemon has exited normally or was terminated in response to a user interrupt. +2026-10-16T08:26:45.414-0400 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Removing daemon address: [e423e685-08b9-458f-b734-bc49ba8a7edf port:42257, addresses:[localhost/127.0.0.1]] +2026-10-16T08:26:45.415-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] VM shutdown hook was unable to remove the daemon address from the registry. It will be cleaned up later. +java.lang.IllegalStateException: Cannot start managing file contention because this handler has been closed. + at org.gradle.cache.internal.locklistener.DefaultFileLockContentionHandler.assertNotStopped(DefaultFileLockContentionHandler.java:267) + at org.gradle.cache.internal.locklistener.DefaultFileLockContentionHandler.reservePort(DefaultFileLockContentionHandler.java:312) + at org.gradle.cache.internal.DefaultFileLockManager.lock(DefaultFileLockManager.java:127) + at org.gradle.cache.internal.DefaultFileLockManager.lock(DefaultFileLockManager.java:109) + at org.gradle.cache.internal.DefaultFileLockManager.lock(DefaultFileLockManager.java:104) + at org.gradle.cache.internal.OnDemandFileAccess.updateFile(OnDemandFileAccess.java:51) + at org.gradle.cache.internal.FileBackedObjectHolder.update(FileBackedObjectHolder.java:77) + at org.gradle.cache.internal.FileIntegrityViolationSuppressingObjectHolderDecorator.lambda$update$0(FileIntegrityViolationSuppressingObjectHolderDecorator.java:48) + at org.gradle.cache.internal.FileIntegrityViolationSuppressingObjectHolderDecorator.doUpdate(FileIntegrityViolationSuppressingObjectHolderDecorator.java:58) + at org.gradle.cache.internal.FileIntegrityViolationSuppressingObjectHolderDecorator.update(FileIntegrityViolationSuppressingObjectHolderDecorator.java:48) + at org.gradle.launcher.daemon.registry.PersistentDaemonRegistry.remove(PersistentDaemonRegistry.java:133) + at org.gradle.launcher.daemon.server.Daemon$1.run(Daemon.java:133) + at java.base/java.lang.Thread.run(Thread.java:1583) diff --git a/.gradle-user/daemon/9.7.1/daemon-74605.out.log b/.gradle-user/daemon/9.7.1/daemon-74605.out.log new file mode 100644 index 0000000..779f34d --- /dev/null +++ b/.gradle-user/daemon/9.7.1/daemon-74605.out.log @@ -0,0 +1,158 @@ +2026-10-16T08:33:16.560-0400 [DEBUG] [org.gradle.launcher.daemon.bootstrap.DaemonMain] Assuming the daemon was started with following jvm opts: [-XX:MaxMetaspaceSize=384m, -XX:+HeapDumpOnOutOfMemoryError, -Xms256m, -Xmx512m, -Dfile.encoding=UTF-8, -Duser.country=US, -Duser.language=en, -Duser.variant] +2026-10-16T08:33:16.615-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding IP addresses for network interface tailscale0 +2026-10-16T08:33:16.615-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Is this a loopback interface? false +2026-10-16T08:33:16.616-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding remote address /fe80:0:0:0:8d15:7fb2:299f:dced%tailscale0 +2026-10-16T08:33:16.616-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding IP addresses for network interface wlp98s0 +2026-10-16T08:33:16.616-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Is this a loopback interface? false +2026-10-16T08:33:16.616-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding remote address /fe80:0:0:0:6f3f:89e6:b585:4167%wlp98s0 +2026-10-16T08:33:16.616-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding remote address /192.168.27.163 +2026-10-16T08:33:16.616-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding IP addresses for network interface lo +2026-10-16T08:33:16.616-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Is this a loopback interface? true +2026-10-16T08:33:16.617-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding loopback address /0:0:0:0:0:0:0:1%lo +2026-10-16T08:33:16.617-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding loopback address /127.0.0.1 +2026-10-16T08:33:16.647-0400 [INFO] [org.gradle.launcher.daemon.server.Daemon] start() called on daemon - DefaultDaemonContext[uid=8ad0c2b8-9bad-4cfa-a88c-f7ec41578876,javaHome=/var/home/hellings/.sdkman/candidates/java/21.0.8-tem,javaVersion=21,javaVendor=Eclipse Adoptium,daemonRegistryDir=/var/home/hellings/Documents/mistring/.gradle-user/daemon,pid=74605,idleTimeout=120000,priority=NORMAL,applyInstrumentationAgent=true,nativeServicesMode=ENABLED,daemonOpts=-XX:MaxMetaspaceSize=384m,-XX:+HeapDumpOnOutOfMemoryError,-Xms256m,-Xmx512m,-Dfile.encoding=UTF-8,-Duser.country=US,-Duser.language=en,-Duser.variant] +2026-10-16T08:33:16.651-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.TcpIncomingConnector] Listening on [dcf375ce-8ef4-4861-9be4-ef42af02d473 port:37507, addresses:[localhost/127.0.0.1]]. +2026-10-16T08:33:16.654-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] Daemon starting at: Fri Oct 16 08:33:16 EDT 2026, with address: [dcf375ce-8ef4-4861-9be4-ef42af02d473 port:37507, addresses:[localhost/127.0.0.1]] +2026-10-16T08:33:16.654-0400 [INFO] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Advertising the daemon address to the clients: [dcf375ce-8ef4-4861-9be4-ef42af02d473 port:37507, addresses:[localhost/127.0.0.1]] +2026-10-16T08:33:16.655-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Advertised daemon context: DefaultDaemonContext[uid=8ad0c2b8-9bad-4cfa-a88c-f7ec41578876,javaHome=/var/home/hellings/.sdkman/candidates/java/21.0.8-tem,javaVersion=21,javaVendor=Eclipse Adoptium,daemonRegistryDir=/var/home/hellings/Documents/mistring/.gradle-user/daemon,pid=74605,idleTimeout=120000,priority=NORMAL,applyInstrumentationAgent=true,nativeServicesMode=ENABLED,daemonOpts=-XX:MaxMetaspaceSize=384m,-XX:+HeapDumpOnOutOfMemoryError,-Xms256m,-Xmx512m,-Dfile.encoding=UTF-8,-Duser.country=US,-Duser.language=en,-Duser.variant] +2026-10-16T08:33:16.655-0400 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Storing daemon address: [dcf375ce-8ef4-4861-9be4-ef42af02d473 port:37507, addresses:[localhost/127.0.0.1]], context: DefaultDaemonContext[uid=8ad0c2b8-9bad-4cfa-a88c-f7ec41578876,javaHome=/var/home/hellings/.sdkman/candidates/java/21.0.8-tem,javaVersion=21,javaVendor=Eclipse Adoptium,daemonRegistryDir=/var/home/hellings/Documents/mistring/.gradle-user/daemon,pid=74605,idleTimeout=120000,priority=NORMAL,applyInstrumentationAgent=true,nativeServicesMode=ENABLED,daemonOpts=-XX:MaxMetaspaceSize=384m,-XX:+HeapDumpOnOutOfMemoryError,-Xms256m,-Xmx512m,-Dfile.encoding=UTF-8,-Duser.country=US,-Duser.language=en,-Duser.variant] +2026-10-16T08:33:16.659-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire exclusive lock on daemon addresses registry. +2026-10-16T08:33:16.661-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired on daemon addresses registry. +2026-10-16T08:33:16.664-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on daemon addresses registry. +2026-10-16T08:33:16.665-0400 [LIFECYCLE] [org.gradle.launcher.daemon.server.Daemon] Daemon server started. +2026-10-16T08:33:16.666-0400 [DEBUG] [org.gradle.launcher.daemon.bootstrap.DaemonStartupCommunication] Completed writing the daemon greeting. Closing streams... +2026-10-16T08:33:16.671-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] stopOnExpiration() called on daemon +2026-10-16T08:33:16.672-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] awaitExpiration() called on daemon +2026-10-16T08:33:16.673-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon is running. Sleeping until state changes. +2026-10-16T08:33:16.679-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.TcpIncomingConnector] Accepted connection from /127.0.0.1:51480 to /127.0.0.1:37507. +2026-10-16T08:33:16.693-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 40: received class org.gradle.launcher.daemon.protocol.Build +2026-10-16T08:33:16.694-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultDaemonConnection] thread 40: Received non-IO message from client: Build{id=9e2e51f8-313a-4e2b-bc12-882358724661, currentDir=/var/home/hellings/Documents/mistring} +2026-10-16T08:33:16.694-0400 [INFO] [org.gradle.launcher.daemon.server.DefaultIncomingConnectionHandler] Received command: Build{id=9e2e51f8-313a-4e2b-bc12-882358724661, currentDir=/var/home/hellings/Documents/mistring}. +2026-10-16T08:33:16.695-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultIncomingConnectionHandler] Starting executing command: Build{id=9e2e51f8-313a-4e2b-bc12-882358724661, currentDir=/var/home/hellings/Documents/mistring} with connection: socket connection from /127.0.0.1:37507 to /127.0.0.1:51480. +2026-10-16T08:33:16.697-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Command execution: started DaemonCommandExecution[command = Build{id=9e2e51f8-313a-4e2b-bc12-882358724661, currentDir=/var/home/hellings/Documents/mistring}, connection = DefaultDaemonConnection: socket connection from /127.0.0.1:37507 to /127.0.0.1:51480] after 7.833333333333334E-4 minutes of idle +2026-10-16T08:33:16.697-0400 [INFO] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Marking the daemon as busy, address: [dcf375ce-8ef4-4861-9be4-ef42af02d473 port:37507, addresses:[localhost/127.0.0.1]] +2026-10-16T08:33:16.697-0400 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Marking busy by address: [dcf375ce-8ef4-4861-9be4-ef42af02d473 port:37507, addresses:[localhost/127.0.0.1]] +2026-10-16T08:33:16.698-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire exclusive lock on daemon addresses registry. +2026-10-16T08:33:16.698-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired on daemon addresses registry. +2026-10-16T08:33:16.699-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on daemon addresses registry. +2026-10-16T08:33:16.699-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] resetting idle timer +2026-10-16T08:33:16.699-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon is running. Sleeping until state changes. +2026-10-16T08:33:16.700-0400 [INFO] [org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy] Daemon is about to start building Build{id=9e2e51f8-313a-4e2b-bc12-882358724661, currentDir=/var/home/hellings/Documents/mistring}. Dispatching build started information... +2026-10-16T08:33:16.700-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 42: dispatching org.gradle.launcher.daemon.protocol.BuildStarted@4b6f8f9c +2026-10-16T08:33:16.702-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.LogToClient] About to start relaying all logs to the client via the connection. +2026-10-16T08:33:16.702-0400 [INFO] [org.gradle.launcher.daemon.server.exec.LogToClient] The client will now receive all logging from the daemon (pid: 74605). The daemon log file: /var/home/hellings/Documents/mistring/.gradle-user/daemon/9.7.1/daemon-74605.out.log +2026-10-16T08:33:16.703-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.ApplyClientEnvironmentVariables] Configuring env variables: [container, PYENV_SHELL, PATH, GNOME_SHELL_SLOWDOWN_FACTOR, HISTCONTROL, XMODIFIERS, GDMSESSION, npm_lifecycle_script, GUESTFISH_RESTORE, DBUS_SESSION_BUS_ADDRESS, ANDROID_HOME, XDG_CACHE_HOME, LD_LIBRARY_PATH, SDKMAN_DIR, USERNAME, PWD, MANAGERPID, SDKMAN_BROKER_API, NVM_CD_FLAGS, LESSOPEN, NODE, SDKMAN_CANDIDATES_API, npm_node_execpath, GUESTFISH_INIT, DEBUGINFOD_IMA_CERT_PATH, GNOME_SETUP_DISPLAY, SHLVL, QT_IM_MODULES, HISTSIZE, JAVA_HOME, npm_command, KOTLIN_HOME, MEMORY_PRESSURE_WATCH, TERM, XDG_CONFIG_DIRS, MOZ_GMP_PATH, GRADLE_HOME, NVM_INC, GRADLE_USER_HOME, WAYLAND_DISPLAY, STARSHIP_SHELL, XDG_SESSION_CLASS, SWIFTLY_HOME_DIR, npm_config_user_agent, DESKTOP_SESSION, XDG_MENU_PREFIX, npm_package_name, NVM_BIN, CONTAINER_ID, INVOCATION_ID, XAUTHORITY, XDG_DATA_DIRS, XDG_CURRENT_DESKTOP, JOURNAL_STREAM, MAIL, XDG_STATE_HOME, MANAGERPIDFDID, npm_lifecycle_event, LOGNAME, INFOPATH, SWIFTLY_BIN_DIR, PYENV_VIRTUALENV_INIT, SHELL, PYENV_ROOT, SSH_ASKPASS, DEBUGINFOD_URLS, BREW_BASH_COMPLETION, SYSTEMD_EXEC_PID, XDG_SESSION_DESKTOP, LS_COLORS, npm_package_json, MEMORY_PRESSURE_WRITE, DOCKER_HOST, QT_IM_MODULE, STARSHIP_SESSION_KEY, XDG_SESSION_EXTRA_DEVICE_ACCESS, LANG, XDG_SESSION_TYPE, DISPLAY, npm_execpath, SDKMAN_CANDIDATES_DIR, npm_config_local_prefix, GDM_LANG, NVM_DIR, XDG_DATA_HOME, GUESTFISH_PS1, SWIFTLY_TOOLCHAINS_DIR, FREETOKEN_FT_BIN, GPG_TTY, SDKMAN_PLATFORM, USER, XDG_CONFIG_HOME, SSH_AUTH_SOCK, EDITOR, HOSTNAME, DISTROBOX_ENTER_PATH, XDG_RUNTIME_DIR, HOME, TERMINFO_DIRS, GUESTFISH_OUTPUT] +2026-10-16T08:33:16.707-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon] Requesting daemon stop after processing Build{id=9e2e51f8-313a-4e2b-bc12-882358724661, currentDir=/var/home/hellings/Documents/mistring} +2026-10-16T08:33:16.707-0400 [LIFECYCLE] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Daemon will be stopped at the end of the build +2026-10-16T08:33:16.707-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Stop as soon as idle requested. The daemon is busy +2026-10-16T08:33:16.707-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon stop has been requested. Sleeping until state changes. +2026-10-16T08:33:16.710-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.ExecuteBuild] The daemon has started executing the build. +2026-10-16T08:33:16.710-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.ExecuteBuild] Executing build with daemon context: DefaultDaemonContext[uid=8ad0c2b8-9bad-4cfa-a88c-f7ec41578876,javaHome=/var/home/hellings/.sdkman/candidates/java/21.0.8-tem,javaVersion=21,javaVendor=Eclipse Adoptium,daemonRegistryDir=/var/home/hellings/Documents/mistring/.gradle-user/daemon,pid=74605,idleTimeout=120000,priority=NORMAL,applyInstrumentationAgent=true,nativeServicesMode=ENABLED,daemonOpts=-XX:MaxMetaspaceSize=384m,-XX:+HeapDumpOnOutOfMemoryError,-Xms256m,-Xmx512m,-Dfile.encoding=UTF-8,-Duser.country=US,-Duser.language=en,-Duser.variant] + +BUILD SUCCESSFUL in 5s +4 actionable tasks: 4 executed +2026-10-16T08:33:21.504-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.ExecuteBuild] The daemon has finished executing the build. +2026-10-16T08:33:21.515-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon stop has been requested. Sleeping until state changes. +2026-10-16T08:33:21.515-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Command execution: finished waiting for DaemonCommandExecution[command = Build{id=9e2e51f8-313a-4e2b-bc12-882358724661, currentDir=/var/home/hellings/Documents/mistring}, connection = DefaultDaemonConnection: socket connection from /127.0.0.1:37507 to /127.0.0.1:51480]. Result org.gradle.launcher.daemon.server.DaemonStateCoordinator@1d0f7463 with state StopRequested +2026-10-16T08:33:21.515-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Command execution: completed DaemonCommandExecution[command = Build{id=9e2e51f8-313a-4e2b-bc12-882358724661, currentDir=/var/home/hellings/Documents/mistring}, connection = DefaultDaemonConnection: socket connection from /127.0.0.1:37507 to /127.0.0.1:51480] +2026-10-16T08:33:21.516-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] resetting idle timer +2026-10-16T08:33:21.516-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Marking daemon stopped due to command completed and stop requested. The daemon is not running a build +2026-10-16T08:33:21.516-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon has stopped. +2026-10-16T08:33:21.516-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.ReturnResult] Daemon is dispatching the build result: Success[value=org.gradle.launcher.exec.BuildActionResult@613fbc73] +2026-10-16T08:33:21.516-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 39: dispatching Success[value=org.gradle.launcher.exec.BuildActionResult@613fbc73] +2026-10-16T08:33:21.517-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] stop() called on daemon +2026-10-16T08:33:21.517-0400 [INFO] [org.gradle.launcher.daemon.server.Daemon] Stop requested. Daemon is removing its presence from the registry... +2026-10-16T08:33:21.517-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Removing our presence to clients, eg. removing this address from the registry: [dcf375ce-8ef4-4861-9be4-ef42af02d473 port:37507, addresses:[localhost/127.0.0.1]] +2026-10-16T08:33:21.517-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.CleanUpVirtualFileSystemAfterBuild] Cleaning virtual file system after build finished +2026-10-16T08:33:21.517-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultIncomingConnectionHandler] Finishing executing command: Build{id=9e2e51f8-313a-4e2b-bc12-882358724661, currentDir=/var/home/hellings/Documents/mistring} +2026-10-16T08:33:21.517-0400 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Removing daemon address: [dcf375ce-8ef4-4861-9be4-ef42af02d473 port:37507, addresses:[localhost/127.0.0.1]] +2026-10-16T08:33:21.518-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 40: received class org.gradle.launcher.daemon.protocol.CloseInput +2026-10-16T08:33:21.518-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultDaemonConnection] thread 40: Received IO message from client: org.gradle.launcher.daemon.protocol.CloseInput@7afb0b64 +2026-10-16T08:33:21.518-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire exclusive lock on daemon addresses registry. +2026-10-16T08:33:21.519-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired on daemon addresses registry. +2026-10-16T08:33:21.520-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on daemon addresses registry. +2026-10-16T08:33:21.520-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Address removed from registry. +2026-10-16T08:33:21.559-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 40: received class org.gradle.launcher.daemon.protocol.Finished +2026-10-16T08:33:21.559-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultDaemonConnection] thread 40: Received non-IO message from client: org.gradle.launcher.daemon.protocol.Finished@52bb8d1a +2026-10-16T08:33:21.560-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultIncomingConnectionHandler] Received finished message: org.gradle.launcher.daemon.protocol.Finished@52bb8d1a +2026-10-16T08:33:21.560-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 39: stopping connection +2026-10-16T08:33:21.561-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.SocketConnection] Discarding EOFException: java.io.EOFException +2026-10-16T08:33:21.561-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 40: received null +2026-10-16T08:33:21.561-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultDaemonConnection] thread 40: Received end-of-input from client. +2026-10-16T08:33:21.561-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 39: stopping connection +2026-10-16T08:33:21.561-0400 [DEBUG] [org.gradle.workers.internal.WorkerDaemonClientsManager] Stopping 1 worker daemon(s). +2026-10-16T08:33:21.572-0400 [DEBUG] [org.gradle.process.internal.DefaultExecHandle] Changing state to: SUCCEEDED +2026-10-16T08:33:21.573-0400 [DEBUG] [org.gradle.process.internal.DefaultExecHandle] Process 'Gradle Worker Daemon 1' finished with exit value 0 (state: SUCCEEDED) +2026-10-16T08:33:21.574-0400 [INFO] [org.gradle.workers.internal.WorkerDaemonClientsManager] Stopped 1 worker daemon(s). +2026-10-16T08:33:21.574-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for jars (/var/home/hellings/Documents/mistring/.gradle-user/caches/jars-9) +2026-10-16T08:33:21.575-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on jars (/var/home/hellings/Documents/mistring/.gradle-user/caches/jars-9). +2026-10-16T08:33:21.575-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] jars (/var/home/hellings/Documents/mistring/.gradle-user/caches/jars-9) has last been fully cleaned up 0 hours ago +2026-10-16T08:33:21.575-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] Skipping cleanup for jars (/var/home/hellings/Documents/mistring/.gradle-user/caches/jars-9) as it is not yet due +2026-10-16T08:33:21.575-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for file content cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileContent) +2026-10-16T08:33:21.575-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on file content cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileContent). +2026-10-16T08:33:21.575-0400 [DEBUG] [org.gradle.internal.watch.vfs.impl.WatchingVirtualFileSystem] Closing VFS, dropping state +2026-10-16T08:33:21.576-0400 [DEBUG] [org.gradle.internal.watch.registry.impl.DefaultFileWatcherRegistry] Finished listening to file system change events +2026-10-16T08:33:21.576-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCoordinator] Cache Generated Gradle JARs cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/generated-gradle-jars) was closed 0 times. +2026-10-16T08:33:21.576-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for artifact cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2) +2026-10-16T08:33:21.576-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache module-artifact.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2/metadata-2.107/module-artifact.bin) +2026-10-16T08:33:21.576-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache module-metadata.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2/metadata-2.107/module-metadata.bin) +2026-10-16T08:33:21.576-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on artifact cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2). +2026-10-16T08:33:21.576-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] artifact cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2) has last been fully cleaned up 0 hours ago +2026-10-16T08:33:21.577-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] Skipping cleanup for artifact cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2) as it is not yet due +2026-10-16T08:33:21.577-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] groovy-dsl has last been fully cleaned up 0 hours ago +2026-10-16T08:33:21.577-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] Skipping cleanup for groovy-dsl as it is not yet due +2026-10-16T08:33:21.577-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] Artifact transforms cache has last been fully cleaned up 0 hours ago +2026-10-16T08:33:21.577-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] Skipping cleanup for Artifact transforms cache as it is not yet due +2026-10-16T08:33:21.577-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for journal cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/journal-1) +2026-10-16T08:33:21.577-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache file-access.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/journal-1/file-access.bin) +2026-10-16T08:33:21.577-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on journal cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/journal-1). +2026-10-16T08:33:21.577-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for file hash cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileHashes) +2026-10-16T08:33:21.577-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache fileHashes.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileHashes/fileHashes.bin) +2026-10-16T08:33:21.577-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache resourceHashesCache.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileHashes/resourceHashesCache.bin) +2026-10-16T08:33:21.577-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on file hash cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileHashes). +2026-10-16T08:33:21.578-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for Java compile cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/javaCompile) +2026-10-16T08:33:21.578-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache jarAnalysis.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/javaCompile/jarAnalysis.bin) +2026-10-16T08:33:21.578-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache classAnalysis.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/javaCompile/classAnalysis.bin) +2026-10-16T08:33:21.578-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on Java compile cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/javaCompile). +2026-10-16T08:33:21.579-0400 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationRunner] Build operation 'Deleting unused version-specific caches in /var/home/hellings/Documents/mistring/.gradle-user/caches' started +2026-10-16T08:33:21.579-0400 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationRunner] Completing Build operation 'Deleting unused version-specific caches in /var/home/hellings/Documents/mistring/.gradle-user/caches' +2026-10-16T08:33:21.579-0400 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationRunner] Build operation 'Deleting unused version-specific caches in /var/home/hellings/Documents/mistring/.gradle-user/caches' completed +2026-10-16T08:33:21.579-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] stop() called on daemon +2026-10-16T08:33:21.579-0400 [INFO] [org.gradle.launcher.daemon.server.Daemon] Stop requested. Daemon is removing its presence from the registry... +2026-10-16T08:33:21.579-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Removing our presence to clients, eg. removing this address from the registry: [dcf375ce-8ef4-4861-9be4-ef42af02d473 port:37507, addresses:[localhost/127.0.0.1]] +2026-10-16T08:33:21.579-0400 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Removing daemon address: [dcf375ce-8ef4-4861-9be4-ef42af02d473 port:37507, addresses:[localhost/127.0.0.1]] +2026-10-16T08:33:21.580-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire exclusive lock on daemon addresses registry. +2026-10-16T08:33:21.581-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired on daemon addresses registry. +2026-10-16T08:33:21.582-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on daemon addresses registry. +2026-10-16T08:33:21.582-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Address removed from registry. +2026-10-16T08:33:21.583-0400 [DEBUG] [org.gradle.cache.internal.locklistener.DefaultFileLockContentionHandler] File lock listener thread completed. +2026-10-16T08:33:21.584-0400 [DEBUG] [java.lang.Runtime] Runtime.exit() called with status: 0 +java.lang.Throwable: Runtime.exit(0) + at java.base/java.lang.Shutdown.logRuntimeExit(Shutdown.java:179) + at java.base/java.lang.Shutdown.exit(Shutdown.java:160) + at java.base/java.lang.Runtime.exit(Runtime.java:188) + at java.base/java.lang.System.exit(System.java:1920) + at org.gradle.launcher.bootstrap.ProcessCompleter.complete(ProcessCompleter.java:21) + at org.gradle.launcher.bootstrap.EntryPoint.run(EntryPoint.java:62) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.gradle.launcher.bootstrap.ProcessBootstrap.runNoExit(ProcessBootstrap.java:72) + at org.gradle.launcher.bootstrap.ProcessBootstrap.run(ProcessBootstrap.java:39) + at org.gradle.launcher.daemon.bootstrap.GradleDaemon.main(GradleDaemon.java:23) +Daemon vm is shutting down... The daemon has exited normally or was terminated in response to a user interrupt. +2026-10-16T08:33:21.585-0400 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Removing daemon address: [dcf375ce-8ef4-4861-9be4-ef42af02d473 port:37507, addresses:[localhost/127.0.0.1]] +2026-10-16T08:33:21.586-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] VM shutdown hook was unable to remove the daemon address from the registry. It will be cleaned up later. +java.lang.IllegalStateException: Cannot start managing file contention because this handler has been closed. + at org.gradle.cache.internal.locklistener.DefaultFileLockContentionHandler.assertNotStopped(DefaultFileLockContentionHandler.java:267) + at org.gradle.cache.internal.locklistener.DefaultFileLockContentionHandler.reservePort(DefaultFileLockContentionHandler.java:312) + at org.gradle.cache.internal.DefaultFileLockManager.lock(DefaultFileLockManager.java:127) + at org.gradle.cache.internal.DefaultFileLockManager.lock(DefaultFileLockManager.java:109) + at org.gradle.cache.internal.DefaultFileLockManager.lock(DefaultFileLockManager.java:104) + at org.gradle.cache.internal.OnDemandFileAccess.updateFile(OnDemandFileAccess.java:51) + at org.gradle.cache.internal.FileBackedObjectHolder.update(FileBackedObjectHolder.java:77) + at org.gradle.cache.internal.FileIntegrityViolationSuppressingObjectHolderDecorator.lambda$update$0(FileIntegrityViolationSuppressingObjectHolderDecorator.java:48) + at org.gradle.cache.internal.FileIntegrityViolationSuppressingObjectHolderDecorator.doUpdate(FileIntegrityViolationSuppressingObjectHolderDecorator.java:58) + at org.gradle.cache.internal.FileIntegrityViolationSuppressingObjectHolderDecorator.update(FileIntegrityViolationSuppressingObjectHolderDecorator.java:48) + at org.gradle.launcher.daemon.registry.PersistentDaemonRegistry.remove(PersistentDaemonRegistry.java:133) + at org.gradle.launcher.daemon.server.Daemon$1.run(Daemon.java:133) + at java.base/java.lang.Thread.run(Thread.java:1583) diff --git a/.gradle-user/daemon/9.7.1/daemon-78803.out.log b/.gradle-user/daemon/9.7.1/daemon-78803.out.log new file mode 100644 index 0000000..b0d382c --- /dev/null +++ b/.gradle-user/daemon/9.7.1/daemon-78803.out.log @@ -0,0 +1,150 @@ +2026-10-16T08:35:02.346-0400 [DEBUG] [org.gradle.launcher.daemon.bootstrap.DaemonMain] Assuming the daemon was started with following jvm opts: [-XX:MaxMetaspaceSize=384m, -XX:+HeapDumpOnOutOfMemoryError, -Xms256m, -Xmx512m, -Dfile.encoding=UTF-8, -Duser.country=US, -Duser.language=en, -Duser.variant] +2026-10-16T08:35:02.407-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding IP addresses for network interface tailscale0 +2026-10-16T08:35:02.407-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Is this a loopback interface? false +2026-10-16T08:35:02.407-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding remote address /fe80:0:0:0:8d15:7fb2:299f:dced%tailscale0 +2026-10-16T08:35:02.408-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding IP addresses for network interface wlp98s0 +2026-10-16T08:35:02.408-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Is this a loopback interface? false +2026-10-16T08:35:02.408-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding remote address /fe80:0:0:0:6f3f:89e6:b585:4167%wlp98s0 +2026-10-16T08:35:02.408-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding remote address /192.168.27.163 +2026-10-16T08:35:02.408-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding IP addresses for network interface lo +2026-10-16T08:35:02.409-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Is this a loopback interface? true +2026-10-16T08:35:02.409-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding loopback address /0:0:0:0:0:0:0:1%lo +2026-10-16T08:35:02.409-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.InetAddresses] Adding loopback address /127.0.0.1 +2026-10-16T08:35:02.436-0400 [INFO] [org.gradle.launcher.daemon.server.Daemon] start() called on daemon - DefaultDaemonContext[uid=d8640dcd-6b3b-4da3-aff1-ad8c7e4a3834,javaHome=/var/home/hellings/.sdkman/candidates/java/21.0.8-tem,javaVersion=21,javaVendor=Eclipse Adoptium,daemonRegistryDir=/var/home/hellings/Documents/mistring/.gradle-user/daemon,pid=78803,idleTimeout=120000,priority=NORMAL,applyInstrumentationAgent=true,nativeServicesMode=ENABLED,daemonOpts=-XX:MaxMetaspaceSize=384m,-XX:+HeapDumpOnOutOfMemoryError,-Xms256m,-Xmx512m,-Dfile.encoding=UTF-8,-Duser.country=US,-Duser.language=en,-Duser.variant] +2026-10-16T08:35:02.440-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.TcpIncomingConnector] Listening on [7bdde7b1-2099-4646-894e-3e8c947990cd port:44907, addresses:[localhost/127.0.0.1]]. +2026-10-16T08:35:02.443-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] Daemon starting at: Fri Oct 16 08:35:02 EDT 2026, with address: [7bdde7b1-2099-4646-894e-3e8c947990cd port:44907, addresses:[localhost/127.0.0.1]] +2026-10-16T08:35:02.443-0400 [INFO] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Advertising the daemon address to the clients: [7bdde7b1-2099-4646-894e-3e8c947990cd port:44907, addresses:[localhost/127.0.0.1]] +2026-10-16T08:35:02.443-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Advertised daemon context: DefaultDaemonContext[uid=d8640dcd-6b3b-4da3-aff1-ad8c7e4a3834,javaHome=/var/home/hellings/.sdkman/candidates/java/21.0.8-tem,javaVersion=21,javaVendor=Eclipse Adoptium,daemonRegistryDir=/var/home/hellings/Documents/mistring/.gradle-user/daemon,pid=78803,idleTimeout=120000,priority=NORMAL,applyInstrumentationAgent=true,nativeServicesMode=ENABLED,daemonOpts=-XX:MaxMetaspaceSize=384m,-XX:+HeapDumpOnOutOfMemoryError,-Xms256m,-Xmx512m,-Dfile.encoding=UTF-8,-Duser.country=US,-Duser.language=en,-Duser.variant] +2026-10-16T08:35:02.444-0400 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Storing daemon address: [7bdde7b1-2099-4646-894e-3e8c947990cd port:44907, addresses:[localhost/127.0.0.1]], context: DefaultDaemonContext[uid=d8640dcd-6b3b-4da3-aff1-ad8c7e4a3834,javaHome=/var/home/hellings/.sdkman/candidates/java/21.0.8-tem,javaVersion=21,javaVendor=Eclipse Adoptium,daemonRegistryDir=/var/home/hellings/Documents/mistring/.gradle-user/daemon,pid=78803,idleTimeout=120000,priority=NORMAL,applyInstrumentationAgent=true,nativeServicesMode=ENABLED,daemonOpts=-XX:MaxMetaspaceSize=384m,-XX:+HeapDumpOnOutOfMemoryError,-Xms256m,-Xmx512m,-Dfile.encoding=UTF-8,-Duser.country=US,-Duser.language=en,-Duser.variant] +2026-10-16T08:35:02.448-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire exclusive lock on daemon addresses registry. +2026-10-16T08:35:02.450-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired on daemon addresses registry. +2026-10-16T08:35:02.453-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on daemon addresses registry. +2026-10-16T08:35:02.453-0400 [LIFECYCLE] [org.gradle.launcher.daemon.server.Daemon] Daemon server started. +2026-10-16T08:35:02.454-0400 [DEBUG] [org.gradle.launcher.daemon.bootstrap.DaemonStartupCommunication] Completed writing the daemon greeting. Closing streams... +2026-10-16T08:35:02.458-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] stopOnExpiration() called on daemon +2026-10-16T08:35:02.459-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] awaitExpiration() called on daemon +2026-10-16T08:35:02.459-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon is running. Sleeping until state changes. +2026-10-16T08:35:02.468-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.TcpIncomingConnector] Accepted connection from /127.0.0.1:51544 to /127.0.0.1:44907. +2026-10-16T08:35:02.481-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 40: received class org.gradle.launcher.daemon.protocol.Build +2026-10-16T08:35:02.481-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultDaemonConnection] thread 40: Received non-IO message from client: Build{id=9d550a3b-6686-41ff-a424-9ae218e4f8ec, currentDir=/var/home/hellings/Documents/mistring} +2026-10-16T08:35:02.481-0400 [INFO] [org.gradle.launcher.daemon.server.DefaultIncomingConnectionHandler] Received command: Build{id=9d550a3b-6686-41ff-a424-9ae218e4f8ec, currentDir=/var/home/hellings/Documents/mistring}. +2026-10-16T08:35:02.482-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultIncomingConnectionHandler] Starting executing command: Build{id=9d550a3b-6686-41ff-a424-9ae218e4f8ec, currentDir=/var/home/hellings/Documents/mistring} with connection: socket connection from /127.0.0.1:44907 to /127.0.0.1:51544. +2026-10-16T08:35:02.483-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Command execution: started DaemonCommandExecution[command = Build{id=9d550a3b-6686-41ff-a424-9ae218e4f8ec, currentDir=/var/home/hellings/Documents/mistring}, connection = DefaultDaemonConnection: socket connection from /127.0.0.1:44907 to /127.0.0.1:51544] after 7.5E-4 minutes of idle +2026-10-16T08:35:02.484-0400 [INFO] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Marking the daemon as busy, address: [7bdde7b1-2099-4646-894e-3e8c947990cd port:44907, addresses:[localhost/127.0.0.1]] +2026-10-16T08:35:02.484-0400 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Marking busy by address: [7bdde7b1-2099-4646-894e-3e8c947990cd port:44907, addresses:[localhost/127.0.0.1]] +2026-10-16T08:35:02.484-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire exclusive lock on daemon addresses registry. +2026-10-16T08:35:02.485-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired on daemon addresses registry. +2026-10-16T08:35:02.485-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on daemon addresses registry. +2026-10-16T08:35:02.485-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] resetting idle timer +2026-10-16T08:35:02.485-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon is running. Sleeping until state changes. +2026-10-16T08:35:02.486-0400 [INFO] [org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy] Daemon is about to start building Build{id=9d550a3b-6686-41ff-a424-9ae218e4f8ec, currentDir=/var/home/hellings/Documents/mistring}. Dispatching build started information... +2026-10-16T08:35:02.486-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 42: dispatching org.gradle.launcher.daemon.protocol.BuildStarted@7756877f +2026-10-16T08:35:02.487-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.LogToClient] About to start relaying all logs to the client via the connection. +2026-10-16T08:35:02.488-0400 [INFO] [org.gradle.launcher.daemon.server.exec.LogToClient] The client will now receive all logging from the daemon (pid: 78803). The daemon log file: /var/home/hellings/Documents/mistring/.gradle-user/daemon/9.7.1/daemon-78803.out.log +2026-10-16T08:35:02.488-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.ApplyClientEnvironmentVariables] Configuring env variables: [container, PYENV_SHELL, PATH, GNOME_SHELL_SLOWDOWN_FACTOR, HISTCONTROL, XMODIFIERS, GDMSESSION, npm_lifecycle_script, GUESTFISH_RESTORE, DBUS_SESSION_BUS_ADDRESS, ANDROID_HOME, XDG_CACHE_HOME, LD_LIBRARY_PATH, SDKMAN_DIR, USERNAME, PWD, MANAGERPID, SDKMAN_BROKER_API, NVM_CD_FLAGS, LESSOPEN, NODE, SDKMAN_CANDIDATES_API, npm_node_execpath, GUESTFISH_INIT, DEBUGINFOD_IMA_CERT_PATH, GNOME_SETUP_DISPLAY, SHLVL, QT_IM_MODULES, HISTSIZE, JAVA_HOME, npm_command, KOTLIN_HOME, MEMORY_PRESSURE_WATCH, TERM, XDG_CONFIG_DIRS, MOZ_GMP_PATH, GRADLE_HOME, NVM_INC, GRADLE_USER_HOME, WAYLAND_DISPLAY, STARSHIP_SHELL, XDG_SESSION_CLASS, SWIFTLY_HOME_DIR, npm_config_user_agent, DESKTOP_SESSION, XDG_MENU_PREFIX, npm_package_name, NVM_BIN, CONTAINER_ID, INVOCATION_ID, XAUTHORITY, XDG_DATA_DIRS, XDG_CURRENT_DESKTOP, JOURNAL_STREAM, MAIL, XDG_STATE_HOME, MANAGERPIDFDID, npm_lifecycle_event, LOGNAME, INFOPATH, SWIFTLY_BIN_DIR, PYENV_VIRTUALENV_INIT, SHELL, PYENV_ROOT, SSH_ASKPASS, DEBUGINFOD_URLS, BREW_BASH_COMPLETION, SYSTEMD_EXEC_PID, XDG_SESSION_DESKTOP, LS_COLORS, npm_package_json, MEMORY_PRESSURE_WRITE, DOCKER_HOST, QT_IM_MODULE, STARSHIP_SESSION_KEY, XDG_SESSION_EXTRA_DEVICE_ACCESS, LANG, XDG_SESSION_TYPE, DISPLAY, npm_execpath, SDKMAN_CANDIDATES_DIR, npm_config_local_prefix, GDM_LANG, NVM_DIR, XDG_DATA_HOME, GUESTFISH_PS1, SWIFTLY_TOOLCHAINS_DIR, FREETOKEN_FT_BIN, GPG_TTY, SDKMAN_PLATFORM, USER, XDG_CONFIG_HOME, SSH_AUTH_SOCK, EDITOR, HOSTNAME, DISTROBOX_ENTER_PATH, XDG_RUNTIME_DIR, HOME, TERMINFO_DIRS, GUESTFISH_OUTPUT] +2026-10-16T08:35:02.492-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon] Requesting daemon stop after processing Build{id=9d550a3b-6686-41ff-a424-9ae218e4f8ec, currentDir=/var/home/hellings/Documents/mistring} +2026-10-16T08:35:02.492-0400 [LIFECYCLE] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Daemon will be stopped at the end of the build +2026-10-16T08:35:02.492-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Stop as soon as idle requested. The daemon is busy +2026-10-16T08:35:02.493-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon stop has been requested. Sleeping until state changes. +2026-10-16T08:35:02.495-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.ExecuteBuild] The daemon has started executing the build. +2026-10-16T08:35:02.495-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.ExecuteBuild] Executing build with daemon context: DefaultDaemonContext[uid=d8640dcd-6b3b-4da3-aff1-ad8c7e4a3834,javaHome=/var/home/hellings/.sdkman/candidates/java/21.0.8-tem,javaVersion=21,javaVendor=Eclipse Adoptium,daemonRegistryDir=/var/home/hellings/Documents/mistring/.gradle-user/daemon,pid=78803,idleTimeout=120000,priority=NORMAL,applyInstrumentationAgent=true,nativeServicesMode=ENABLED,daemonOpts=-XX:MaxMetaspaceSize=384m,-XX:+HeapDumpOnOutOfMemoryError,-Xms256m,-Xmx512m,-Dfile.encoding=UTF-8,-Duser.country=US,-Duser.language=en,-Duser.variant] + +BUILD SUCCESSFUL in 3s +4 actionable tasks: 1 executed, 3 up-to-date +2026-10-16T08:35:05.481-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.ExecuteBuild] The daemon has finished executing the build. +2026-10-16T08:35:05.493-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon stop has been requested. Sleeping until state changes. +2026-10-16T08:35:05.494-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Command execution: finished waiting for DaemonCommandExecution[command = Build{id=9d550a3b-6686-41ff-a424-9ae218e4f8ec, currentDir=/var/home/hellings/Documents/mistring}, connection = DefaultDaemonConnection: socket connection from /127.0.0.1:44907 to /127.0.0.1:51544]. Result org.gradle.launcher.daemon.server.DaemonStateCoordinator@5bd0e2f with state StopRequested +2026-10-16T08:35:05.495-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Command execution: completed DaemonCommandExecution[command = Build{id=9d550a3b-6686-41ff-a424-9ae218e4f8ec, currentDir=/var/home/hellings/Documents/mistring}, connection = DefaultDaemonConnection: socket connection from /127.0.0.1:44907 to /127.0.0.1:51544] +2026-10-16T08:35:05.495-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] resetting idle timer +2026-10-16T08:35:05.495-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] Marking daemon stopped due to command completed and stop requested. The daemon is not running a build +2026-10-16T08:35:05.495-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonStateCoordinator] daemon has stopped. +2026-10-16T08:35:05.495-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.ReturnResult] Daemon is dispatching the build result: Success[value=org.gradle.launcher.exec.BuildActionResult@1957fa2a] +2026-10-16T08:35:05.495-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 39: dispatching Success[value=org.gradle.launcher.exec.BuildActionResult@1957fa2a] +2026-10-16T08:35:05.495-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] stop() called on daemon +2026-10-16T08:35:05.496-0400 [INFO] [org.gradle.launcher.daemon.server.Daemon] Stop requested. Daemon is removing its presence from the registry... +2026-10-16T08:35:05.496-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Removing our presence to clients, eg. removing this address from the registry: [7bdde7b1-2099-4646-894e-3e8c947990cd port:44907, addresses:[localhost/127.0.0.1]] +2026-10-16T08:35:05.496-0400 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Removing daemon address: [7bdde7b1-2099-4646-894e-3e8c947990cd port:44907, addresses:[localhost/127.0.0.1]] +2026-10-16T08:35:05.496-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultIncomingConnectionHandler] Finishing executing command: Build{id=9d550a3b-6686-41ff-a424-9ae218e4f8ec, currentDir=/var/home/hellings/Documents/mistring} +2026-10-16T08:35:05.496-0400 [DEBUG] [org.gradle.launcher.daemon.server.exec.CleanUpVirtualFileSystemAfterBuild] Cleaning virtual file system after build finished +2026-10-16T08:35:05.497-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire exclusive lock on daemon addresses registry. +2026-10-16T08:35:05.496-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 40: received class org.gradle.launcher.daemon.protocol.CloseInput +2026-10-16T08:35:05.497-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired on daemon addresses registry. +2026-10-16T08:35:05.498-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultDaemonConnection] thread 40: Received IO message from client: org.gradle.launcher.daemon.protocol.CloseInput@731c408d +2026-10-16T08:35:05.498-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on daemon addresses registry. +2026-10-16T08:35:05.498-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Address removed from registry. +2026-10-16T08:35:05.537-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 40: received class org.gradle.launcher.daemon.protocol.Finished +2026-10-16T08:35:05.537-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultDaemonConnection] thread 40: Received non-IO message from client: org.gradle.launcher.daemon.protocol.Finished@70fb7c35 +2026-10-16T08:35:05.537-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultIncomingConnectionHandler] Received finished message: org.gradle.launcher.daemon.protocol.Finished@70fb7c35 +2026-10-16T08:35:05.538-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 39: stopping connection +2026-10-16T08:35:05.539-0400 [DEBUG] [org.gradle.internal.remote.internal.inet.SocketConnection] Discarding EOFException: java.io.EOFException +2026-10-16T08:35:05.539-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 40: received null +2026-10-16T08:35:05.539-0400 [DEBUG] [org.gradle.launcher.daemon.server.DefaultDaemonConnection] thread 40: Received end-of-input from client. +2026-10-16T08:35:05.539-0400 [DEBUG] [org.gradle.launcher.daemon.server.SynchronizedDispatchConnection] thread 39: stopping connection +2026-10-16T08:35:05.543-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for jars (/var/home/hellings/Documents/mistring/.gradle-user/caches/jars-9) +2026-10-16T08:35:05.543-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on jars (/var/home/hellings/Documents/mistring/.gradle-user/caches/jars-9). +2026-10-16T08:35:05.543-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] jars (/var/home/hellings/Documents/mistring/.gradle-user/caches/jars-9) has last been fully cleaned up 0 hours ago +2026-10-16T08:35:05.543-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] Skipping cleanup for jars (/var/home/hellings/Documents/mistring/.gradle-user/caches/jars-9) as it is not yet due +2026-10-16T08:35:05.543-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for file content cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileContent) +2026-10-16T08:35:05.544-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on file content cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileContent). +2026-10-16T08:35:05.544-0400 [DEBUG] [org.gradle.internal.watch.vfs.impl.WatchingVirtualFileSystem] Closing VFS, dropping state +2026-10-16T08:35:05.544-0400 [DEBUG] [org.gradle.internal.watch.registry.impl.DefaultFileWatcherRegistry] Finished listening to file system change events +2026-10-16T08:35:05.544-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCoordinator] Cache Generated Gradle JARs cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/generated-gradle-jars) was closed 0 times. +2026-10-16T08:35:05.545-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for artifact cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2) +2026-10-16T08:35:05.545-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache module-artifact.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2/metadata-2.107/module-artifact.bin) +2026-10-16T08:35:05.545-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache module-metadata.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2/metadata-2.107/module-metadata.bin) +2026-10-16T08:35:05.545-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on artifact cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2). +2026-10-16T08:35:05.545-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] artifact cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2) has last been fully cleaned up 0 hours ago +2026-10-16T08:35:05.545-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] Skipping cleanup for artifact cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/modules-2) as it is not yet due +2026-10-16T08:35:05.545-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] groovy-dsl has last been fully cleaned up 0 hours ago +2026-10-16T08:35:05.545-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] Skipping cleanup for groovy-dsl as it is not yet due +2026-10-16T08:35:05.546-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] Artifact transforms cache has last been fully cleaned up 0 hours ago +2026-10-16T08:35:05.546-0400 [DEBUG] [org.gradle.cache.internal.DefaultCacheCleanupExecutor] Skipping cleanup for Artifact transforms cache as it is not yet due +2026-10-16T08:35:05.546-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for journal cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/journal-1) +2026-10-16T08:35:05.546-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache file-access.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/journal-1/file-access.bin) +2026-10-16T08:35:05.546-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on journal cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/journal-1). +2026-10-16T08:35:05.546-0400 [DEBUG] [org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess] Releasing file lock for file hash cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileHashes) +2026-10-16T08:35:05.546-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache fileHashes.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileHashes/fileHashes.bin) +2026-10-16T08:35:05.546-0400 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache resourceHashesCache.bin (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileHashes/resourceHashesCache.bin) +2026-10-16T08:35:05.547-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on file hash cache (/var/home/hellings/Documents/mistring/.gradle-user/caches/9.7.1/fileHashes). +2026-10-16T08:35:05.547-0400 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationRunner] Build operation 'Deleting unused version-specific caches in /var/home/hellings/Documents/mistring/.gradle-user/caches' started +2026-10-16T08:35:05.547-0400 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationRunner] Completing Build operation 'Deleting unused version-specific caches in /var/home/hellings/Documents/mistring/.gradle-user/caches' +2026-10-16T08:35:05.547-0400 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationRunner] Build operation 'Deleting unused version-specific caches in /var/home/hellings/Documents/mistring/.gradle-user/caches' completed +2026-10-16T08:35:05.548-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] stop() called on daemon +2026-10-16T08:35:05.548-0400 [INFO] [org.gradle.launcher.daemon.server.Daemon] Stop requested. Daemon is removing its presence from the registry... +2026-10-16T08:35:05.548-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Removing our presence to clients, eg. removing this address from the registry: [7bdde7b1-2099-4646-894e-3e8c947990cd port:44907, addresses:[localhost/127.0.0.1]] +2026-10-16T08:35:05.548-0400 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Removing daemon address: [7bdde7b1-2099-4646-894e-3e8c947990cd port:44907, addresses:[localhost/127.0.0.1]] +2026-10-16T08:35:05.548-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire exclusive lock on daemon addresses registry. +2026-10-16T08:35:05.548-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired on daemon addresses registry. +2026-10-16T08:35:05.549-0400 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on daemon addresses registry. +2026-10-16T08:35:05.549-0400 [DEBUG] [org.gradle.launcher.daemon.server.DaemonRegistryUpdater] Address removed from registry. +2026-10-16T08:35:05.549-0400 [DEBUG] [org.gradle.cache.internal.locklistener.DefaultFileLockContentionHandler] File lock listener thread completed. +2026-10-16T08:35:05.551-0400 [DEBUG] [java.lang.Runtime] Runtime.exit() called with status: 0 +java.lang.Throwable: Runtime.exit(0) + at java.base/java.lang.Shutdown.logRuntimeExit(Shutdown.java:179) + at java.base/java.lang.Shutdown.exit(Shutdown.java:160) + at java.base/java.lang.Runtime.exit(Runtime.java:188) + at java.base/java.lang.System.exit(System.java:1920) + at org.gradle.launcher.bootstrap.ProcessCompleter.complete(ProcessCompleter.java:21) + at org.gradle.launcher.bootstrap.EntryPoint.run(EntryPoint.java:62) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.gradle.launcher.bootstrap.ProcessBootstrap.runNoExit(ProcessBootstrap.java:72) + at org.gradle.launcher.bootstrap.ProcessBootstrap.run(ProcessBootstrap.java:39) + at org.gradle.launcher.daemon.bootstrap.GradleDaemon.main(GradleDaemon.java:23) +Daemon vm is shutting down... The daemon has exited normally or was terminated in response to a user interrupt. +2026-10-16T08:35:05.551-0400 [DEBUG] [org.gradle.launcher.daemon.registry.PersistentDaemonRegistry] Removing daemon address: [7bdde7b1-2099-4646-894e-3e8c947990cd port:44907, addresses:[localhost/127.0.0.1]] +2026-10-16T08:35:05.552-0400 [DEBUG] [org.gradle.launcher.daemon.server.Daemon] VM shutdown hook was unable to remove the daemon address from the registry. It will be cleaned up later. +java.lang.IllegalStateException: Cannot start managing file contention because this handler has been closed. + at org.gradle.cache.internal.locklistener.DefaultFileLockContentionHandler.assertNotStopped(DefaultFileLockContentionHandler.java:267) + at org.gradle.cache.internal.locklistener.DefaultFileLockContentionHandler.reservePort(DefaultFileLockContentionHandler.java:312) + at org.gradle.cache.internal.DefaultFileLockManager.lock(DefaultFileLockManager.java:127) + at org.gradle.cache.internal.DefaultFileLockManager.lock(DefaultFileLockManager.java:109) + at org.gradle.cache.internal.DefaultFileLockManager.lock(DefaultFileLockManager.java:104) + at org.gradle.cache.internal.OnDemandFileAccess.updateFile(OnDemandFileAccess.java:51) + at org.gradle.cache.internal.FileBackedObjectHolder.update(FileBackedObjectHolder.java:77) + at org.gradle.cache.internal.FileIntegrityViolationSuppressingObjectHolderDecorator.lambda$update$0(FileIntegrityViolationSuppressingObjectHolderDecorator.java:48) + at org.gradle.cache.internal.FileIntegrityViolationSuppressingObjectHolderDecorator.doUpdate(FileIntegrityViolationSuppressingObjectHolderDecorator.java:58) + at org.gradle.cache.internal.FileIntegrityViolationSuppressingObjectHolderDecorator.update(FileIntegrityViolationSuppressingObjectHolderDecorator.java:48) + at org.gradle.launcher.daemon.registry.PersistentDaemonRegistry.remove(PersistentDaemonRegistry.java:133) + at org.gradle.launcher.daemon.server.Daemon$1.run(Daemon.java:133) + at java.base/java.lang.Thread.run(Thread.java:1583) diff --git a/.gradle-user/daemon/9.7.1/registry.bin b/.gradle-user/daemon/9.7.1/registry.bin new file mode 100644 index 0000000..22fd28d Binary files /dev/null and b/.gradle-user/daemon/9.7.1/registry.bin differ diff --git a/.gradle-user/daemon/9.7.1/registry.bin.lock b/.gradle-user/daemon/9.7.1/registry.bin.lock new file mode 100644 index 0000000..9301334 Binary files /dev/null and b/.gradle-user/daemon/9.7.1/registry.bin.lock differ diff --git a/.gradle-user/daemon/CACHEDIR.TAG b/.gradle-user/daemon/CACHEDIR.TAG new file mode 100644 index 0000000..c8907d7 --- /dev/null +++ b/.gradle-user/daemon/CACHEDIR.TAG @@ -0,0 +1,4 @@ +Signature: 8a477f597d28d172789f06886806bc55 +# This file is a cache directory tag created by Gradle. +# For information about cache directory tags, see: +# https://bford.info/cachedir/ \ No newline at end of file diff --git a/.gradle-user/native/0.2.8/x86_64-linux-gnu/libgradle-fileevents.so b/.gradle-user/native/0.2.8/x86_64-linux-gnu/libgradle-fileevents.so new file mode 100644 index 0000000..118136b Binary files /dev/null and b/.gradle-user/native/0.2.8/x86_64-linux-gnu/libgradle-fileevents.so differ diff --git a/.gradle-user/native/0.2.8/x86_64-linux-gnu/libgradle-fileevents.so.lock b/.gradle-user/native/0.2.8/x86_64-linux-gnu/libgradle-fileevents.so.lock new file mode 100644 index 0000000..6b2aaa7 --- /dev/null +++ b/.gradle-user/native/0.2.8/x86_64-linux-gnu/libgradle-fileevents.so.lock @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/.gradle-user/native/660c5614fbf4a5f2a75b1949f50a0caf5cd603558e7d8a26e50b933a0cfb79d1/linux-amd64-ncurses5/libnative-platform-curses.so b/.gradle-user/native/660c5614fbf4a5f2a75b1949f50a0caf5cd603558e7d8a26e50b933a0cfb79d1/linux-amd64-ncurses5/libnative-platform-curses.so new file mode 100644 index 0000000..99f47ae Binary files /dev/null and b/.gradle-user/native/660c5614fbf4a5f2a75b1949f50a0caf5cd603558e7d8a26e50b933a0cfb79d1/linux-amd64-ncurses5/libnative-platform-curses.so differ diff --git a/.gradle-user/native/660c5614fbf4a5f2a75b1949f50a0caf5cd603558e7d8a26e50b933a0cfb79d1/linux-amd64-ncurses5/libnative-platform-curses.so.lock b/.gradle-user/native/660c5614fbf4a5f2a75b1949f50a0caf5cd603558e7d8a26e50b933a0cfb79d1/linux-amd64-ncurses5/libnative-platform-curses.so.lock new file mode 100644 index 0000000..6b2aaa7 --- /dev/null +++ b/.gradle-user/native/660c5614fbf4a5f2a75b1949f50a0caf5cd603558e7d8a26e50b933a0cfb79d1/linux-amd64-ncurses5/libnative-platform-curses.so.lock @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/.gradle-user/native/660c5614fbf4a5f2a75b1949f50a0caf5cd603558e7d8a26e50b933a0cfb79d1/linux-amd64-ncurses6/libnative-platform-curses.so b/.gradle-user/native/660c5614fbf4a5f2a75b1949f50a0caf5cd603558e7d8a26e50b933a0cfb79d1/linux-amd64-ncurses6/libnative-platform-curses.so new file mode 100644 index 0000000..db86f4a Binary files /dev/null and b/.gradle-user/native/660c5614fbf4a5f2a75b1949f50a0caf5cd603558e7d8a26e50b933a0cfb79d1/linux-amd64-ncurses6/libnative-platform-curses.so differ diff --git a/.gradle-user/native/660c5614fbf4a5f2a75b1949f50a0caf5cd603558e7d8a26e50b933a0cfb79d1/linux-amd64-ncurses6/libnative-platform-curses.so.lock b/.gradle-user/native/660c5614fbf4a5f2a75b1949f50a0caf5cd603558e7d8a26e50b933a0cfb79d1/linux-amd64-ncurses6/libnative-platform-curses.so.lock new file mode 100644 index 0000000..6b2aaa7 --- /dev/null +++ b/.gradle-user/native/660c5614fbf4a5f2a75b1949f50a0caf5cd603558e7d8a26e50b933a0cfb79d1/linux-amd64-ncurses6/libnative-platform-curses.so.lock @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/.gradle-user/native/660c5614fbf4a5f2a75b1949f50a0caf5cd603558e7d8a26e50b933a0cfb79d1/linux-amd64/libnative-platform.so b/.gradle-user/native/660c5614fbf4a5f2a75b1949f50a0caf5cd603558e7d8a26e50b933a0cfb79d1/linux-amd64/libnative-platform.so new file mode 100644 index 0000000..0d73a12 Binary files /dev/null and b/.gradle-user/native/660c5614fbf4a5f2a75b1949f50a0caf5cd603558e7d8a26e50b933a0cfb79d1/linux-amd64/libnative-platform.so differ diff --git a/.gradle-user/native/660c5614fbf4a5f2a75b1949f50a0caf5cd603558e7d8a26e50b933a0cfb79d1/linux-amd64/libnative-platform.so.lock b/.gradle-user/native/660c5614fbf4a5f2a75b1949f50a0caf5cd603558e7d8a26e50b933a0cfb79d1/linux-amd64/libnative-platform.so.lock new file mode 100644 index 0000000..6b2aaa7 --- /dev/null +++ b/.gradle-user/native/660c5614fbf4a5f2a75b1949f50a0caf5cd603558e7d8a26e50b933a0cfb79d1/linux-amd64/libnative-platform.so.lock @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/.gradle-user/native/jansi/2.4.2/Linux/x86_64/libjansi.so b/.gradle-user/native/jansi/2.4.2/Linux/x86_64/libjansi.so new file mode 100644 index 0000000..78a1054 Binary files /dev/null and b/.gradle-user/native/jansi/2.4.2/Linux/x86_64/libjansi.so differ diff --git a/.gradle-user/notifications/9.7.1/release-features.rendered b/.gradle-user/notifications/9.7.1/release-features.rendered new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/wrapper/dists/CACHEDIR.TAG b/.gradle-user/wrapper/dists/CACHEDIR.TAG new file mode 100644 index 0000000..c8907d7 --- /dev/null +++ b/.gradle-user/wrapper/dists/CACHEDIR.TAG @@ -0,0 +1,4 @@ +Signature: 8a477f597d28d172789f06886806bc55 +# This file is a cache directory tag created by Gradle. +# For information about cache directory tags, see: +# https://bford.info/cachedir/ \ No newline at end of file diff --git a/.gradle-user/wrapper/dists/gradle-9.7.1-bin/1w1c7tv4s851m17nbqdsro2tv/gradle-9.7.1-bin.zip.lck b/.gradle-user/wrapper/dists/gradle-9.7.1-bin/1w1c7tv4s851m17nbqdsro2tv/gradle-9.7.1-bin.zip.lck new file mode 100644 index 0000000..e69de29 diff --git a/.gradle-user/wrapper/dists/gradle-9.7.1-bin/1w1c7tv4s851m17nbqdsro2tv/gradle-9.7.1-bin.zip.part b/.gradle-user/wrapper/dists/gradle-9.7.1-bin/1w1c7tv4s851m17nbqdsro2tv/gradle-9.7.1-bin.zip.part new file mode 100644 index 0000000..e69de29 diff --git a/.mcp.json b/.mcp.json new file mode 100644 index 0000000..c4fc42b --- /dev/null +++ b/.mcp.json @@ -0,0 +1,9 @@ +{ + "mcpServers": { + "tessl": { + "type": "stdio", + "command": "tessl", + "args": ["mcp", "start"] + } + } +} diff --git a/.project b/.project new file mode 100644 index 0000000..0800131 --- /dev/null +++ b/.project @@ -0,0 +1,34 @@ + + + mistring + Project mistring created by Buildship. + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.buildship.core.gradleprojectbuilder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.buildship.core.gradleprojectnature + + + + 1792077804714 + + 30 + + org.eclipse.core.resources.regexFilterMatcher + node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ + + + + diff --git a/.sdkmanrc b/.sdkmanrc new file mode 100644 index 0000000..c390358 --- /dev/null +++ b/.sdkmanrc @@ -0,0 +1,3 @@ +# Enable auto-env through the sdkman_auto_env config +# Add key=value pairs of SDKs to use below +java=25.4.4+1-graal diff --git a/.settings/org.eclipse.buildship.core.prefs b/.settings/org.eclipse.buildship.core.prefs new file mode 100644 index 0000000..387c799 --- /dev/null +++ b/.settings/org.eclipse.buildship.core.prefs @@ -0,0 +1,13 @@ +arguments=--init-script /var/home/hellings/.var/app/com.visualstudio.code/config/Code/User/globalStorage/redhat.java/1.57.0/config_linux/org.eclipse.osgi/57/0/.cp/gradle/init/init.gradle --init-script /var/home/hellings/.var/app/com.visualstudio.code/config/Code/User/globalStorage/redhat.java/1.57.0/config_linux/org.eclipse.osgi/57/0/.cp/gradle/protobuf/init.gradle --init-script /var/home/hellings/.var/app/com.visualstudio.code/config/Code/User/globalStorage/redhat.java/1.57.0/config_linux/org.eclipse.osgi/57/0/.cp/gradle/kotlin/init.gradle --init-script /var/home/hellings/.var/app/com.visualstudio.code/config/Code/User/globalStorage/redhat.java/1.57.0/config_linux/org.eclipse.osgi/57/0/.cp/gradle/groovy/init.gradle --init-script /var/home/hellings/.var/app/com.visualstudio.code/config/Code/User/globalStorage/redhat.java/1.57.0/config_linux/org.eclipse.osgi/57/0/.cp/gradle/scala/init.gradle +auto.sync=false +build.scans.enabled=false +connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER) +connection.project.dir= +eclipse.preferences.version=1 +gradle.user.home= +java.home=/var/home/hellings/.var/app/com.visualstudio.code/data/vscode/extensions/redhat.java-1.57.0-linux-x64/jre/25.0.4.1-linux-x86_64 +jvm.arguments= +offline.mode=false +override.workspace.settings=true +show.console.view=true +show.executions.view=true diff --git a/.tessl/RULES.md b/.tessl/RULES.md new file mode 100644 index 0000000..9188c9b --- /dev/null +++ b/.tessl/RULES.md @@ -0,0 +1,3 @@ +# Agent Rules + +This file is updated when running `tessl install`. If a linked file is missing, make sure to run the command to download any missing plugins from the registry. diff --git a/.tessl/plugins/bergside/awesome-design-skills/README.md b/.tessl/plugins/bergside/awesome-design-skills/README.md new file mode 100644 index 0000000..9466ece --- /dev/null +++ b/.tessl/plugins/bergside/awesome-design-skills/README.md @@ -0,0 +1,553 @@ +# Awesome Design Skills [![Awesome](https://awesome.re/badge.svg)](https://awesome.re) + +awesome-design-skills + +
+ +> A curated registry of 67 design system skill files for AI-powered agentic tools like [Claude Code](https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/overview), [Cursor](https://www.cursor.com/), [Codex](https://openai.com/index/codex/), and others. Pull any skill into your project with a single command. + +Each skill now ships as a folder with: +- `SKILL.md` for AI-agent instructions (tokens, component rules, accessibility constraints, quality gates) +- `DESIGN.md` for human-readable design intent, rationale, and implementation notes + +**[Preview all design skills on TypeUI](https://typeui.sh/design-skills)** + +## Design Skills + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Agentic
+ Agentic
+ npx typeui.sh pull agentic +
+ Ant
+ Ant
+ npx typeui.sh pull ant +
+ Roku
+ Roku
+ npx typeui.sh pull roku +
+ Artistic
+ Artistic
+ npx typeui.sh pull artistic +
+ Bento
+ Bento
+ npx typeui.sh pull bento +
+ Bold
+ Bold
+ npx typeui.sh pull bold +
+ Brutalism
+ Brutalism
+ npx typeui.sh pull brutalism +
+ Cafe
+ Cafe
+ npx typeui.sh pull cafe +
+ Claymorphism
+ Claymorphism
+ npx typeui.sh pull claymorphism +
+ Claude
+ Claude
+ npx typeui.sh pull claude +
+ Clean
+ Clean
+ npx typeui.sh pull clean +
+ Codex
+ Codex
+ npx typeui.sh pull codex +
+ Colorful
+ Colorful
+ npx typeui.sh pull colorful +
+ Contemporary
+ Contemporary
+ npx typeui.sh pull contemporary +
+ Corporate
+ Corporate
+ npx typeui.sh pull corporate +
+ Cosmic
+ Cosmic
+ npx typeui.sh pull cosmic +
+ Creative
+ Creative
+ npx typeui.sh pull creative +
+ Enterprise
+ Enterprise
+ npx typeui.sh pull enterprise +
+ Dithered
+ Dithered
+ npx typeui.sh pull dithered +
+ Doodle
+ Doodle
+ npx typeui.sh pull doodle +
+ Dramatic
+ Dramatic
+ npx typeui.sh pull dramatic +
+ Editorial
+ Editorial
+ npx typeui.sh pull editorial +
+ Square
+ Square
+ npx typeui.sh pull square +
+ Pulse
+ Pulse
+ npx typeui.sh pull pulse +
+ Stitch
+ Stitch
+ npx typeui.sh pull stitch +
+ Expressive
+ Expressive
+ npx typeui.sh pull expressive +
+ Fantasy
+ Fantasy
+ npx typeui.sh pull fantasy +
+ Fiction
+ Fiction
+ npx typeui.sh pull fiction +
+ Flat
+ Flat
+ npx typeui.sh pull flat +
+ Friendly
+ Friendly
+ npx typeui.sh pull friendly +
+ Futuristic
+ Futuristic
+ npx typeui.sh pull futuristic +
+ Glassmorphism
+ Glassmorphism
+ npx typeui.sh pull glassmorphism +
+ Gradient
+ Gradient
+ npx typeui.sh pull gradient +
+ Immersive
+ Immersive
+ npx typeui.sh pull immersive +
+ Impeccable
+ Impeccable
+ npx typeui.sh pull impeccable +
+ Levels
+ Levels
+ npx typeui.sh pull levels +
+ Lingo
+ Lingo
+ npx typeui.sh pull lingo +
+ Power
+ Power
+ npx typeui.sh pull power +
+ Material
+ Material
+ npx typeui.sh pull material +
+ Matrix
+ Matrix
+ npx typeui.sh pull matrix +
+ Minimal
+ Minimal
+ npx typeui.sh pull minimal +
+ Modern
+ Modern
+ npx typeui.sh pull modern +
+ Mono
+ Mono
+ npx typeui.sh pull mono +
+ Neon
+ Neon
+ npx typeui.sh pull neon +
+ Neobrutalism
+ Neobrutalism
+ npx typeui.sh pull neobrutalism +
+ Neumorphism
+ Neumorphism
+ npx typeui.sh pull neumorphism +
+ Pacman
+ Pacman
+ npx typeui.sh pull pacman +
+ Paper
+ Paper
+ npx typeui.sh pull paper +
+ Perspective
+ Perspective
+ npx typeui.sh pull perspective +
+ Premium
+ Premium
+ npx typeui.sh pull premium +
+ Professional
+ Professional
+ npx typeui.sh pull professional +
+ Basic
+ Basic
+ npx typeui.sh pull basic +
+ Refined
+ Refined
+ npx typeui.sh pull refined +
+ Retro
+ Retro
+ npx typeui.sh pull retro +
+ Riso
+ Riso
+ npx typeui.sh pull riso +
+ Sega
+ Sega
+ npx typeui.sh pull sega +
+ Shadcn
+ Shadcn
+ npx typeui.sh pull shadcn +
+ Geometric
+ Geometric
+ npx typeui.sh pull geometric +
+ Sketch
+ Sketch
+ npx typeui.sh pull sketch +
+ Skeumorphism
+ Skeumorphism
+ npx typeui.sh pull skeumorphism +
+ Sleek
+ Sleek
+ npx typeui.sh pull sleek +
+ Spacious
+ Spacious
+ npx typeui.sh pull spacious +
+ Storytelling
+ Storytelling
+ npx typeui.sh pull storytelling +
+ Terracotta
+ Terracotta
+ npx typeui.sh pull terracotta +
+ Tetris
+ Tetris
+ npx typeui.sh pull tetris +
+ Vibrant
+ Vibrant
+ npx typeui.sh pull vibrant +
+ Vintage
+ Vintage
+ npx typeui.sh pull vintage +
+ +## Quick Start + +Pull any design skill directly into your project using the [TypeUI CLI](https://github.com/bergside/typeui.sh): + +```bash +npx typeui.sh pull +``` + +For example, to pull the Glassmorphism design skill: + +```bash +npx typeui.sh pull glassmorphism +``` + +Or browse all available skills interactively: + +```bash +npx typeui.sh list +``` + +## What is a Design Skill? + +A design skill is a folder containing `SKILL.md` and `DESIGN.md`. + +`SKILL.md` acts as the instruction source for AI agents and LLMs. It contains: + +- **Brand & mission** — the design philosophy and visual identity +- **Style foundations** — typography scale, color palette, spacing system +- **Component families** — buttons, inputs, cards, modals, navigation, and more +- **Accessibility rules** — WCAG 2.2 AA compliance, keyboard-first interactions +- **Writing tone** — content and voice guidelines +- **Do/Don't rules** — explicit patterns and anti-patterns +- **Quality gates** — testable acceptance criteria for code review + +`DESIGN.md` is a companion document for human readers and maintainers. It captures: + +- **Design overview** — concise summary of the visual direction +- **Rationale and references** — context for why patterns/tokens exist +- **Maintenance notes** — guidance for keeping design decisions aligned over time + +When an AI agent reads a skill file, it follows the `SKILL.md` guidelines to generate UI code that is consistent, accessible, and true to the design system. + +## Usage + +### Pull a skill into your project + +Use the [TypeUI CLI](https://github.com/bergside/typeui.sh) to pull any skill by its slug: + +```bash +npx typeui.sh pull +``` + +The CLI will fetch the `SKILL.md` file from this registry and write it to your configured provider paths (e.g., `.cursor/skills/`, `.claude/`, etc.). The companion `DESIGN.md` remains in this repo alongside each skill for reference and maintenance. + +### Specify providers + +Target specific agentic tools when pulling: + +```bash +npx typeui.sh pull glassmorphism -p cursor,claude +``` + +### Preview before writing + +Use `--dry-run` to see what would be written without making changes: + +```bash +npx typeui.sh pull glassmorphism --dry-run +``` + +### Browse and pull interactively + +List all available skills with preview links, then pull one: + +```bash +npx typeui.sh list +``` + +### Generate a custom skill + +Run the interactive prompts to create your own design system skill: + +```bash +npx typeui.sh generate +``` + +## Registry Structure + +Each skill lives in its own folder under `skills/`: + +``` +skills/ +├── index.json # Slug-keyed map for fast CLI lookups +├── glassmorphism/ +│ ├── SKILL.md # AI-agent instruction file +│ └── DESIGN.md # Human-readable design companion +├── brutalism/ +│ ├── SKILL.md +│ └── DESIGN.md +├── minimal/ +│ ├── SKILL.md +│ └── DESIGN.md +└── ... +``` + +The `index.json` file maps each slug to its skill path: + +```json +{ + "glassmorphism": { + "slug": "glassmorphism", + "name": "Glassmorphism", + "skillPath": "skills/glassmorphism/SKILL.md" + } +} +``` + +When you run `npx typeui.sh pull `, the CLI reads this index, resolves the skill path, and fetches the corresponding `SKILL.md` file. `DESIGN.md` is stored next to each skill for human-facing documentation. + +## Contributing + +Contributions are welcome! If you'd like to add a new design skill to the registry: + +1. Create a new folder under `skills/` with your slug name +2. Add a `SKILL.md` file following the existing format +3. Add a companion `DESIGN.md` file in the same folder +4. Add an entry to `skills/index.json` +5. Submit a pull request + +Please ensure your skill file includes all required sections: mission, brand, style foundations, component families, accessibility rules, writing tone, do/don't rules, and quality gates. + +## License + +[MIT License](LICENSE) © Built and maintained by [Bergside](https://github.com/bergside). + +## Sponsors + +A huge thank you to the companies supporting our open-source work. + + + + + +
+ + Skybridge +
Skybridge +
+
+ +Want to see your logo here? [Become a sponsor](https://www.typeui.sh/sponsor). diff --git a/.tessl/plugins/bergside/awesome-design-skills/skills/neumorphism/DESIGN.md b/.tessl/plugins/bergside/awesome-design-skills/skills/neumorphism/DESIGN.md new file mode 100644 index 0000000..6252624 --- /dev/null +++ b/.tessl/plugins/bergside/awesome-design-skills/skills/neumorphism/DESIGN.md @@ -0,0 +1,55 @@ +--- +name: Neumorphism +colors: + primary: "#006666" + secondary: "#F1F2F5" + success: "#00A63D" + warning: "#FE9900" + danger: "#FF2157" + surface: "#E7E5E4" + text: "#1E2938" + neutral: "#E7E5E4" +typography: + h1: + fontFamily: "Space Mono" + fontSize: 3rem + body-md: + fontFamily: "Space Mono" + fontSize: 1rem + label-caps: + fontFamily: "JetBrains Mono" + fontSize: 0.75rem + sourceScale: "desktop-first expressive scale" + weights: "100, 200, 300, 400, 500, 600, 700, 800, 900" +rounded: + sm: 4px + md: 8px +spacing: + sm: 4px + md: 8px + sourceScale: "compact density mode" +--- + +## Overview + +Soft, extruded UI elements with inner and outer shadows on monochromatic surfaces for a tactile, embedded look. + +## Style Foundations + +- **Visual style:** minimal, clean, high-contrast, playful, matrix +- **Typography scale:** desktop-first expressive scale +- **Typography fonts:** primary=Space Mono, display=Space Mono, mono=JetBrains Mono +- **Typography weights:** 100, 200, 300, 400, 500, 600, 700, 800, 900 +- **Color palette:** primary, secondary, success, warning, danger, info +- **Spacing scale:** compact density mode + +## Colors + +- **Primary (#006666):** Token from style foundations. +- **Secondary (#F1F2F5):** Token from style foundations. +- **Success (#00A63D):** Token from style foundations. +- **Warning (#FE9900):** Token from style foundations. +- **Danger (#FF2157):** Token from style foundations. +- **Surface (#E7E5E4):** Token from style foundations. +- **Text (#1E2938):** Token from style foundations. +- **Neutral (#E7E5E4):** Derived from the surface token for official format compatibility. diff --git a/.tessl/plugins/bergside/awesome-design-skills/skills/neumorphism/SKILL.md b/.tessl/plugins/bergside/awesome-design-skills/skills/neumorphism/SKILL.md new file mode 100644 index 0000000..13d7495 --- /dev/null +++ b/.tessl/plugins/bergside/awesome-design-skills/skills/neumorphism/SKILL.md @@ -0,0 +1,88 @@ +--- +name: neumorphism +description: Soft, extruded UI elements with inner and outer shadows on monochromatic surfaces for a tactile, embedded look. +license: MIT +metadata: + author: typeui.sh +--- + + +# Neumorphism club Design System Skill (Universal) + +## Mission +You are an expert design-system guideline author for neumorphism. +Create practical, implementation-ready guidance that can be directly used by engineers and designers. + +## Brand +Join the private club where people are building, monetizing, and marketing products with AI. + +## Style Foundations +- Visual style: minimal, clean, high-contrast, playful, matrix +- Typography scale: desktop-first expressive scale | Fonts: primary=Space Mono, display=Space Mono, mono=JetBrains Mono | weights=100, 200, 300, 400, 500, 600, 700, 800, 900 +- Color palette: primary, secondary, success, warning, danger, info | Tokens: primary=#006666, secondary=#F1F2F5, success=#00A63D, warning=#FE9900, danger=#FF2157, surface=#E7E5E4, text=#1E2938 +- Spacing scale: compact density mode + + +## Accessibility +WCAG 2.2 AA, keyboard-first interactions, visible focus states, semantic HTML before ARIA, screen-reader tested labels + +## Writing Tone +concise, confident, helpful, clear, friendly + +## Rules: Do +- prefer semantic tokens over raw values +- preserve visual hierarchy +- keep interaction states explicit +- design for empty/loading/error states +- ensure responsive behavior by default + +## Rules: Don't +- avoid low contrast text +- avoid inconsistent spacing rhythm +- avoid decorative motion without purpose +- avoid ambiguous labels +- avoid mixing multiple visual metaphors +- avoid inaccessible hit areas + +## Expected Behavior +- Follow the foundations first, then component consistency. +- When uncertain, prioritize accessibility and clarity over novelty. +- Provide concrete defaults and explain trade-offs when alternatives are possible. +- Keep guidance opinionated, concise, and implementation-focused. + +## Guideline Authoring Workflow +1. Restate the design intent in one sentence before proposing rules. +2. Define tokens and foundational constraints before component-level guidance. +3. Specify component anatomy, states, variants, and interaction behavior. +4. Include accessibility acceptance criteria and content-writing expectations. +5. Add anti-patterns and migration notes for existing inconsistent UI. +6. End with a QA checklist that can be executed in code review. + +## Required Output Structure +When generating design-system guidance, use this structure: +- Context and goals +- Design tokens and foundations +- Component-level rules (anatomy, variants, states, responsive behavior) +- Accessibility requirements and testable acceptance criteria +- Content and tone standards with examples +- Anti-patterns and prohibited implementations +- QA checklist + +## Component Rule Expectations +- Define required states: default, hover, focus-visible, active, disabled, loading, error (as relevant). +- Describe interaction behavior for keyboard, pointer, and touch. +- State spacing, typography, and color-token usage explicitly. +- Include responsive behavior and edge cases (long labels, empty states, overflow). + +## Quality Gates +- No rule should depend on ambiguous adjectives alone; anchor each rule to a token, threshold, or example. +- Every accessibility statement must be testable in implementation. +- Prefer system consistency over one-off local optimizations. +- Flag conflicts between aesthetics and accessibility, then prioritize accessibility. + +## Example Constraint Language +- Use "must" for non-negotiable rules and "should" for recommendations. +- Pair every do-rule with at least one concrete don't-example. +- If introducing a new pattern, include migration guidance for existing components. + + diff --git a/.tessl/plugins/bergside/awesome-design-skills/tessl-package.json b/.tessl/plugins/bergside/awesome-design-skills/tessl-package.json new file mode 100644 index 0000000..656de39 --- /dev/null +++ b/.tessl/plugins/bergside/awesome-design-skills/tessl-package.json @@ -0,0 +1,4 @@ +{ + "name": "bergside/awesome-design-skills", + "version": "f631a09b4fcc0166f2e2c1a8c81906ef680c57e8" +} diff --git a/.tessl/plugins/bergside/awesome-design-skills/tile.json b/.tessl/plugins/bergside/awesome-design-skills/tile.json new file mode 100644 index 0000000..0bb293e --- /dev/null +++ b/.tessl/plugins/bergside/awesome-design-skills/tile.json @@ -0,0 +1,81 @@ +{ + "name": "bergside/awesome-design-skills", + "version": "f631a09b4fcc0166f2e2c1a8c81906ef680c57e8", + "summary": "Auto-generated plugin from GitHub (67 skills)", + "private": true, + "skills": { + "neumorphism": { + "path": "skills/neumorphism/SKILL.md" + } + }, + "excludes": { + "skills": [ + "agentic", + "ant", + "artistic", + "basic", + "bento", + "bold", + "brutalism", + "cafe", + "claude", + "claymorphism", + "clean", + "codex", + "colorful", + "contemporary", + "corporate", + "cosmic", + "creative", + "dithered", + "doodle", + "dramatic", + "editorial", + "enterprise", + "expressive", + "fantasy", + "fiction", + "flat", + "friendly", + "futuristic", + "geometric", + "glassmorphism", + "gradient", + "immersive", + "impeccable", + "levels", + "lingo", + "material", + "matrix", + "minimal", + "modern", + "mono", + "neobrutalism", + "neon", + "pacman", + "paper", + "perspective", + "power", + "premium", + "professional", + "pulse", + "refined", + "retro", + "riso", + "roku", + "sega", + "shadcn", + "sketch", + "skeumorphism", + "sleek", + "spacious", + "square", + "stitch", + "storytelling", + "terracotta", + "tetris", + "vibrant", + "vintage" + ] + } +} diff --git a/.vscode/mcp.json b/.vscode/mcp.json new file mode 100644 index 0000000..84a8bd7 --- /dev/null +++ b/.vscode/mcp.json @@ -0,0 +1,9 @@ +{ + "servers": { + "tessl": { + "type": "stdio", + "command": "tessl", + "args": ["mcp", "start"] + } + } +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..3557afa --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "cmake.sourceDirectory": "/var/home/hellings/Documents/mistring/krita" +} diff --git a/.vscode/skills/tessl__neumorphism b/.vscode/skills/tessl__neumorphism new file mode 120000 index 0000000..55b2c18 --- /dev/null +++ b/.vscode/skills/tessl__neumorphism @@ -0,0 +1 @@ +../../.tessl/plugins/bergside/awesome-design-skills/skills/neumorphism \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..ea64155 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,5 @@ + + +# Agent Rules + +@.tessl/RULES.md follow the [instructions](.tessl/RULES.md) diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..41cc871 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,3 @@ +# Claude Code Instructions + +@AGENTS.md diff --git a/ENV.sh b/ENV.sh new file mode 100755 index 0000000..56b858d --- /dev/null +++ b/ENV.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +if [[ -f "${HOME}/.sdkman/bin/sdkman-init.sh" ]]; then + source "${HOME}/.sdkman/bin/sdkman-init.sh" +fi + +export JAVA_HOME="${SDKMAN_CANDIDATES_DIR:-${HOME}/.sdkman/candidates}/java/current" +export ANDROID_SDK_ROOT="${HOME}/android-sdk" +export KRITA_ANDROID_NDK_VERSION="28.2.13676358" +export ANDROID_NDK_ROOT="${ANDROID_SDK_ROOT}/ndk/${KRITA_ANDROID_NDK_VERSION}" + +if [[ ! -d "${ANDROID_NDK_ROOT}" ]]; then + printf 'Android NDK not found at %s\n' "${ANDROID_NDK_ROOT}" >&2 + return 1 2>/dev/null || exit 1 +fi diff --git a/README.md b/README.md new file mode 100644 index 0000000..591cc68 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# OpenMiInk + +`OpenMiInk` is a Xiaomi-focused reverse engineering of major mfr's E-Ink controller interfaces under Android. diff --git a/adbme/.flutter-plugins-dependencies b/adbme/.flutter-plugins-dependencies new file mode 100644 index 0000000..c41ffa8 --- /dev/null +++ b/adbme/.flutter-plugins-dependencies @@ -0,0 +1 @@ +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[],"android":[{"name":"flutter_bluetooth_serial","path":"/var/home/hellings/.pub-cache/hosted/pub.dev/flutter_bluetooth_serial-0.4.0/","native_build":true,"dependencies":[],"dev_dependency":false}],"macos":[],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"flutter_bluetooth_serial","dependencies":[]}],"date_created":"2026-10-14 22:19:44.154340","version":"3.44.2","swift_package_manager_enabled":{"ios":false,"macos":false}} \ No newline at end of file diff --git a/adbme/README.md b/adbme/README.md new file mode 100644 index 0000000..bb5c020 --- /dev/null +++ b/adbme/README.md @@ -0,0 +1,7 @@ +# ADBMe companion + +ADBMe is a Flutter companion application. It never receives ADB keys and cannot run ADB itself. A paired laptop-side companion performs the narrowly allowed ADB operations through `bun run adbme` after a locally visible confirmation. + +On production Xiaomi firmware, `WRITE_SETTINGS` can be enabled through the shell app-op. `CHANGE_CONFIGURATION` is signature or privileged and cannot be granted to a normal sideloaded Flutter application. A rooted device or an OEM-signed privileged APK is required for that permission. + +The laptop service and mobile transport are intentionally not enabled by the build script. It must be paired to a named device and a fresh secret before it can request an operation. diff --git a/adbme/lib/main.dart b/adbme/lib/main.dart new file mode 100644 index 0000000..24c4eeb --- /dev/null +++ b/adbme/lib/main.dart @@ -0,0 +1,65 @@ +import 'dart:convert'; +import 'dart:typed_data'; + +import 'package:flutter/material.dart'; +import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart'; + +void main() => runApp(const AdbMeApp()); + +class AdbMeApp extends StatelessWidget { + const AdbMeApp({super.key}); + + @override + Widget build(BuildContext context) => const MaterialApp(home: PairPage()); +} + +class PairPage extends StatefulWidget { + const PairPage({super.key}); + + @override + State createState() => _PairPageState(); +} + +class _PairPageState extends State { + final _token = TextEditingController(); + final _serial = TextEditingController(); + String _result = 'Pair a laptop running scripts/adbme_bluetooth_listener.py'; + + Future _status() async { + final devices = await FlutterBluetoothSerial.instance.getBondedDevices(); + final laptop = await showDialog( + context: context, + builder: (context) => SimpleDialog(children: [ + for (final device in devices) SimpleDialogOption( + onPressed: () => Navigator.pop(context, device), + child: Text(device.name ?? device.address), + ), + ]), + ); + if (laptop == null) return; + final connection = await BluetoothConnection.toAddress(laptop.address); + connection.output.add(Uint8List.fromList(utf8.encode(jsonEncode({ + 'token': _token.text.trim(), 'action': 'status', 'serial': _serial.text.trim(), + })))); + await connection.output.allSent; + final reply = await connection.input!.first; + setState(() => _result = utf8.decode(reply)); + await connection.close(); + } + + @override + Widget build(BuildContext context) => Scaffold( + appBar: AppBar(title: const Text('ADBMe')), + body: Padding( + padding: const EdgeInsets.all(16), + child: Column(children: [ + TextField(controller: _token, obscureText: true, decoration: const InputDecoration(labelText: 'Laptop pairing token')), + TextField(controller: _serial, decoration: const InputDecoration(labelText: 'ADB serial')), + const SizedBox(height: 12), + ElevatedButton(onPressed: _status, child: const Text('Check device status')), + const SizedBox(height: 12), + SelectableText(_result), + ]), + ), + ); +} diff --git a/adbme/pubspec.lock b/adbme/pubspec.lock new file mode 100644 index 0000000..ffa3907 --- /dev/null +++ b/adbme/pubspec.lock @@ -0,0 +1,64 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + characters: + dependency: transitive + description: + name: characters + sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b + url: "https://pub.dev" + source: hosted + version: "1.4.1" + collection: + dependency: transitive + description: + name: collection + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.dev" + source: hosted + version: "1.19.1" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_bluetooth_serial: + dependency: "direct main" + description: + name: flutter_bluetooth_serial + sha256: "85ae82c4099b2b1facdc54e75e1bcfa88dc7f719e55dc886bb0b648cb16636b1" + url: "https://pub.dev" + source: hosted + version: "0.4.0" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b" + url: "https://pub.dev" + source: hosted + version: "0.13.0" + meta: + dependency: transitive + description: + name: meta + sha256: "1741988757a65eb6b36abe716829688cf01910bbf91c34354ff7ec1c3de2b349" + url: "https://pub.dev" + source: hosted + version: "1.18.0" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b + url: "https://pub.dev" + source: hosted + version: "2.2.0" +sdks: + dart: ">=3.10.0-0 <4.0.0" + flutter: ">=1.17.0" diff --git a/adbme/pubspec.yaml b/adbme/pubspec.yaml new file mode 100644 index 0000000..67f29d3 --- /dev/null +++ b/adbme/pubspec.yaml @@ -0,0 +1,11 @@ +name: adbme +description: Paired Bluetooth companion for the local ADBMe bridge. +publish_to: none +environment: + sdk: ^3.3.0 +dependencies: + flutter: + sdk: flutter + flutter_bluetooth_serial: ^0.4.0 +flutter: + uses-material-design: true diff --git a/apk-parser.d.ts b/apk-parser.d.ts new file mode 100644 index 0000000..5e5d8a9 --- /dev/null +++ b/apk-parser.d.ts @@ -0,0 +1,78 @@ +/* +{ + "manifest": [ + { + "@package": "com.example.android.snake", + "uses-permission": [ + { + "@android:name": "android.permission.INTERNET" + } + ], + "application": [ + { + "@android:label": "Snake on a Phone", + "activity": [ + { + "@android:theme": "@0x1030006", + "@android:name": "Snake", + "@android:screenOrientation": 1, + "@android:configChanges": "(type 0x11)0xa0", + "intent-filter": [ + { + "action": [ + { + "@android:name": "android.intent.action.MAIN" + } + ], + "category": [ + { + "@android:name": "android.intent.category.LAUNCHER" + } + ] + } + ] + } + ] + } + ] + } + ] +} + */ + +declare module "apk-parser" { + export interface ApkParser { + parseApk(filePath: string): Promise; + } + + export interface AdoidManifest { + "@package": string; + "uses-permission": Array<{ + "@android:name": string; + }>; + application: Array<{ + "@android:label": string; + activity: Array<{ + "@android:theme": string; + "@android:name": string; + "@android:screenOrientation": number; + "@android:configChanges": string; + "intent-filter": Array<{ + action: Array<{ + "@android:name": string; + }>; + category: Array<{ + "@android:name": string; + }>; + }>; + }>; + }>; + } + + export interface ApkInfo { + manifest: AdoidManifest; + } + + const apkParser: ApkParser; + export default apkParser; +} diff --git a/apk_unpack b/apk_unpack new file mode 160000 index 0000000..b3cddac --- /dev/null +++ b/apk_unpack @@ -0,0 +1 @@ +Subproject commit b3cddac95df514e1b881732fbdd824b7680a231b diff --git a/apk_unpack.d.ts b/apk_unpack.d.ts new file mode 100644 index 0000000..008a356 --- /dev/null +++ b/apk_unpack.d.ts @@ -0,0 +1,11 @@ +declare module "apk_unpack" { + export interface ApkUnpacker { + init(config: { apk: string; java: boolean; dir: string }): void; + extract(cb: (success: boolean) => void): void; + decompile(onReady: () => void): void; + info(callback: (error: boolean, info: any) => void): void; + } + + const apkUnpacker: ApkUnpacker; + export default apkUnpacker; +} diff --git a/apkpatch/MoanLauncher.toml b/apkpatch/MoanLauncher.toml new file mode 100644 index 0000000..f281044 --- /dev/null +++ b/apkpatch/MoanLauncher.toml @@ -0,0 +1,25 @@ +[manifest] +packagePrefix = "rip.crit.ms" +ordinarySignature = true + +[resources] +overlay = "patches/moanlauncher/res" + +[resources.translation] +backend = "argos" +source = "zh" +target = "en" + +[[smaliPatches]] +targetFile = "rip/crit/ms/launcher/XiaomiProfile.smali" +injectFile = "patches/moanlauncher/smali/rip/crit/ms/launcher/XiaomiProfile.smali" + +[[smaliPatches]] +targetFile = "com/note/fragment/ApplicationFragment.smali" +search = " new-instance v2, Landroidx/recyclerview/widget/GridLayoutManager;\n\n invoke-virtual {p0}, Lcom/note/fragment/ApplicationFragment;->getActivity()Landroidx/fragment/app/FragmentActivity;\n\n move-result-object v3\n\n const/4 v4, 0x4\n\n invoke-direct {v2, v3, v4}, Landroidx/recyclerview/widget/GridLayoutManager;->(Landroid/content/Context;I)V\n\n .line 185\n .local v2, \"layoutManager\":Landroidx/recyclerview/widget/GridLayoutManager;" +replace = " new-instance v2, Landroidx/recyclerview/widget/LinearLayoutManager;\n\n invoke-virtual {p0}, Lcom/note/fragment/ApplicationFragment;->getActivity()Landroidx/fragment/app/FragmentActivity;\n\n move-result-object v3\n\n invoke-direct {v2, v3}, Landroidx/recyclerview/widget/LinearLayoutManager;->(Landroid/content/Context;)V\n\n .line 185\n .local v2, \"layoutManager\":Landroidx/recyclerview/widget/LinearLayoutManager;" + +[[smaliPatches]] +targetFile = "com/note/launcher/MainActivity.smali" +search = " invoke-virtual {p0, v0}, Lcom/note/launcher/MainActivity;->setContentView(I)V\n\n .line 87" +replace = " invoke-virtual {p0, v0}, Lcom/note/launcher/MainActivity;->setContentView(I)V\n\n invoke-static {p0}, Lrip/crit/ms/launcher/XiaomiProfile;->capture(Landroid/content/Context;)V\n\n .line 87" diff --git a/apkpatch/MoanNote.toml b/apkpatch/MoanNote.toml new file mode 100644 index 0000000..2c5a510 --- /dev/null +++ b/apkpatch/MoanNote.toml @@ -0,0 +1,65 @@ +[manifest] +packagePrefix = "rip.crit.ms" + +[resources] +overlay = "patches/moannotes/res" +assetOverlay = "patches/moannotes/assets" + +[resources.translation] +backend = "argos" +source = "zh" +target = "en" + +[generatedSmali] +sourceDir = "moannotes-native/build/smali/rip/crit/ms/moannotes/nativebridge" + +[[resources.xmlPatches]] +targetFile = "res/layout/note_edit.xml" +search = "android:src=\"@drawable/ic_noteview_stylus_ballpen\"" +replace = "android:src=\"@drawable/icp_pen\" android:contentDescription=\"Pen\"" + +[[resources.xmlPatches]] +targetFile = "res/layout/note_edit.xml" +search = "android:src=\"@drawable/ic_noteview_background\"" +replace = "android:src=\"@drawable/icp_palette\" android:contentDescription=\"Paper and monochrome ink\"" + +[[resources.xmlPatches]] +targetFile = "res/layout/note_edit.xml" +search = "android:src=\"@drawable/ic_noteview_more\"" +replace = "android:src=\"@drawable/icp_export\" android:contentDescription=\"Document actions and export\"" + +[[smaliPatches]] +targetFile = "com/moan/notes/LaunchActivity.smali" +search = " invoke-virtual {p0, p1}, Lg/b/c/e;->setContentView(I)V\n\n const p1, 0x7f0802a7" +replace = " invoke-virtual {p0, p1}, Lg/b/c/e;->setContentView(I)V\n\n invoke-static {p0}, Lrip/crit/ms/moannotes/FeatureRegistry;->install(Landroid/app/Activity;)V\n\n const p1, 0x7f0802a7" + +[[smaliPatches]] +targetFile = "rip/crit/ms/moannotes/FeatureRegistry.smali" +injectFile = "patches/moannotes/smali/rip/crit/ms/moannotes/FeatureRegistry.smali" + +[[smaliPatches]] +targetFile = "rip/crit/ms/moannotes/BackgroundCatalogPatch.smali" +injectFile = "patches/moannotes/smali/rip/crit/ms/moannotes/BackgroundCatalogPatch.smali" + +[[smaliPatches]] +targetFile = "rip/crit/ms/moannotes/SnapToLineTouchListener.smali" +injectFile = "patches/moannotes/smali/rip/crit/ms/moannotes/SnapToLineTouchListener.smali" + +[[smaliPatches]] +targetFile = "rip/crit/ms/moannotes/SnapToLineToggle.smali" +injectFile = "patches/moannotes/smali/rip/crit/ms/moannotes/SnapToLineToggle.smali" + +[[smaliPatches]] +targetFile = "h/f/b/m5/l.smali" +search = " invoke-virtual {v1, v0}, Ljava/util/ArrayList;->add(Ljava/lang/Object;)Z\n\n :cond_0" +replace = " invoke-virtual {v1, v0}, Ljava/util/ArrayList;->add(Ljava/lang/Object;)Z\n\n sget-object v0, Lh/f/b/m5/l;->a:Ljava/util/ArrayList;\n\n invoke-static {v0}, Lrip/crit/ms/moannotes/BackgroundCatalogPatch;->appendCollegeRuled(Ljava/util/ArrayList;)V\n\n :cond_0" + +[[smaliPatches]] +targetFile = "h/f/b/m5/j.smali" +search = " iget p2, p2, Lh/f/b/m5/l;->c:I\n\n invoke-virtual {p1, p2}, Landroid/widget/ImageView;->setImageResource(I)V" +replace = " iget-object v1, p2, Lh/f/b/m5/l;->d:Ljava/lang/String;\n\n iget p2, p2, Lh/f/b/m5/l;->c:I\n\n iget-object v0, p0, Lh/f/b/m5/j;->h:Landroid/content/Context;\n\n invoke-static {v0, v1, p2}, Lrip/crit/ms/moannotes/BackgroundCatalogPatch;->previewResource(Landroid/content/Context;Ljava/lang/String;I)I\n\n move-result p2\n\n invoke-virtual {p1, p2}, Landroid/widget/ImageView;->setImageResource(I)V" + +[[smaliPatches]] +targetFile = "com/moan/notes/NoteActivity.smali" +search = " invoke-virtual {p1, v0}, Lcom/moan/notes/hand/view/HandwriteView;->setObserver(Lcom/moan/notes/hand/view/HWViewStatus$IStatusReporter;)V\n\n :cond_0\n return-void" +replace = " invoke-virtual {p1, v0}, Lcom/moan/notes/hand/view/HandwriteView;->setObserver(Lcom/moan/notes/hand/view/HWViewStatus$IStatusReporter;)V\n\n invoke-static {p0}, Lrip/crit/ms/moannotes/FeatureRegistry;->installNote(Landroid/app/Activity;)V\n\n :cond_0\n return-void" diff --git a/biome.json b/biome.json new file mode 100644 index 0000000..2705749 --- /dev/null +++ b/biome.json @@ -0,0 +1,34 @@ +{ + "$schema": "https://biomejs.dev/schemas/2.5.15/schema.json", + "vcs": { + "enabled": true, + "clientKind": "git", + "useIgnoreFile": true + }, + "files": { + "ignoreUnknown": false + }, + "formatter": { + "enabled": true, + "indentStyle": "tab" + }, + "linter": { + "enabled": true, + "rules": { + "preset": "recommended" + } + }, + "javascript": { + "formatter": { + "quoteStyle": "double" + } + }, + "assist": { + "enabled": true, + "actions": { + "source": { + "organizeImports": "on" + } + } + } +} diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..d6fdcc6 --- /dev/null +++ b/build.gradle @@ -0,0 +1,27 @@ +plugins { + id 'java' + id 'com.gradleup.shadow' version '8.3.6' +} + +group = 'rip.crit.ms' +version = '1.0-SNAPSHOT' + +repositories { + google() + mavenCentral() +} + +dependencies { + implementation 'org.apktool:apktool-lib:2.9.3' + + implementation 'io.github.skylot:jadx-core:1.5.6' + implementation 'io.github.skylot:jadx-dex-input:1.5.6' + implementation 'io.github.skylot:jadx-cli:1.5.6' + + implementation 'org.slf4j:slf4j-api:2.0.13' + implementation 'ch.qos.logback:logback-classic:1.5.6' +} + +shadowJar { + archiveClassifier.set('all') +} \ No newline at end of file diff --git a/bun.lock b/bun.lock new file mode 100644 index 0000000..88f96dc --- /dev/null +++ b/bun.lock @@ -0,0 +1,333 @@ +{ + "lockfileVersion": 2, + "configVersion": 1, + "workspaces": { + "": { + "name": "mistring", + "dependencies": { + "apk-parser": "^0.1.7", + "apk_unpack": "^1.2.1", + "java-bridge": "^2.8.1", + "patch-package": "^8.0.1", + "toml": "^5.0.1", + }, + "devDependencies": { + "@biomejs/biome": "^2.5.15", + "@types/bun": "latest", + "prettier": "^3.9.10", + }, + "peerDependencies": { + "typescript": "^7", + }, + }, + }, + "trustedDependencies": [ + "java", + "apk-parser", + ], + "packages": { + "@biomejs/biome": ["@biomejs/biome@2.5.15", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.5.15", "@biomejs/cli-darwin-x64": "2.5.15", "@biomejs/cli-linux-arm64": "2.5.15", "@biomejs/cli-linux-arm64-musl": "2.5.15", "@biomejs/cli-linux-x64": "2.5.15", "@biomejs/cli-linux-x64-musl": "2.5.15", "@biomejs/cli-win32-arm64": "2.5.15", "@biomejs/cli-win32-x64": "2.5.15" }, "bin": { "biome": "bin/biome" } }, "sha512-WZTW4slm/pdkh92K6t/3aEN++44JD1PQ7squ7RCMLI1flHGl43DVOIGXvCjHiZgBMO1V4uYxoFNtqrIA4qGuIQ=="], + + "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.5.15", "", { "os": "darwin", "cpu": "arm64" }, "sha512-BZVzFhJ/mUvTLMYbc9x6el0o2Uv5zP7bACYyhFb6fSc1giroXm7PL0a5KqMJ9F+/BnkYRjagD/ROSDVOZ6eapg=="], + + "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.5.15", "", { "os": "darwin", "cpu": "x64" }, "sha512-V5Kw63V+fVGNFhFrizDxMbGXAzZCh8kYzJpy3GI6gTapWDg7bZK9oYC9CbVgQSEdTnupz0U5Efz8Ev+5vdBBXw=="], + + "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.5.15", "", { "os": "linux", "cpu": "arm64" }, "sha512-XaG7P7eeSLYETD3K9grfB0mQmpLQZjygdbsxekWBJAg4am79fGAtRpfRyNnTvXB2fZFNnJZG3nXm7HBat0+VUw=="], + + "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.5.15", "", { "os": "linux", "cpu": "arm64" }, "sha512-tGzZUTcJCV7tj5Adh/Gn6nR4MycqA3iohq2LEcrarAgRBkU0h0OKd2UzCRkOsOYOuUGaUJb4YmqRqyy2feGGSw=="], + + "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.5.15", "", { "os": "linux", "cpu": "x64" }, "sha512-xE4iEW/3LqlYj9GFgGrFsFSH51dEEpUbYWBfeOv0q87WkUDxK2o/HhreSb7qMJqck70RVM6Lg96hgedcAYcOkA=="], + + "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.5.15", "", { "os": "linux", "cpu": "x64" }, "sha512-IlxUcyxilVGPsE008x13pWdkTbU3nQpP2i9b5UrbOYj6goBkKsRX1XB7yJLcV+O1H9LBchIIm4adOaVLZBX0ZQ=="], + + "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.5.15", "", { "os": "win32", "cpu": "arm64" }, "sha512-2kPKzhNlm8C+Ru3GcO0Me2ODkCBLrVOUNuyi84RJyWDVKAA4+Kjj3jMjL938lF6BRfvltC4vB2nPY9SvN51Ovg=="], + + "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.5.15", "", { "os": "win32", "cpu": "x64" }, "sha512-yAzh4UqEImV6Hcy0zjUqNfJAsUhoD64FBQCdTG8Md/Z2wQeVP/ZmJ3XRYAs1g8J9fjTFyl2fCtc5FB5til47+g=="], + + "@types/bun": ["@types/bun@1.4.3", "", { "dependencies": { "bun-types": "1.4.3" } }, "sha512-N67Pqy8JXbAY/j0tNraS3V5mubGvc6rrrNDmDCtZLlFzccbUJPDb0tvgUBC5q4m8ybkP93Jcn1QB+RYQ6PvBhw=="], + + "@types/node": ["@types/node@26.6.5", "", { "dependencies": { "undici-types": "~8.9.0" } }, "sha512-uMzsv9stDdofIZBx4UGh4Z9ZgXnGC9seRDscilBcTHAeOFk67MZg/k9bWVfO+bk4qZmG+l52hRnLwUiH2LnJTg=="], + + "@typescript/typescript-aix-ppc64": ["@typescript/typescript-aix-ppc64@7.0.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ=="], + + "@typescript/typescript-darwin-arm64": ["@typescript/typescript-darwin-arm64@7.0.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA=="], + + "@typescript/typescript-darwin-x64": ["@typescript/typescript-darwin-x64@7.0.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA=="], + + "@typescript/typescript-freebsd-arm64": ["@typescript/typescript-freebsd-arm64@7.0.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ=="], + + "@typescript/typescript-freebsd-x64": ["@typescript/typescript-freebsd-x64@7.0.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw=="], + + "@typescript/typescript-linux-arm": ["@typescript/typescript-linux-arm@7.0.2", "", { "os": "linux", "cpu": "arm" }, "sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ=="], + + "@typescript/typescript-linux-arm64": ["@typescript/typescript-linux-arm64@7.0.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ=="], + + "@typescript/typescript-linux-loong64": ["@typescript/typescript-linux-loong64@7.0.2", "", { "os": "linux", "cpu": "none" }, "sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ=="], + + "@typescript/typescript-linux-mips64el": ["@typescript/typescript-linux-mips64el@7.0.2", "", { "os": "linux", "cpu": "none" }, "sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA=="], + + "@typescript/typescript-linux-ppc64": ["@typescript/typescript-linux-ppc64@7.0.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA=="], + + "@typescript/typescript-linux-riscv64": ["@typescript/typescript-linux-riscv64@7.0.2", "", { "os": "linux", "cpu": "none" }, "sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ=="], + + "@typescript/typescript-linux-s390x": ["@typescript/typescript-linux-s390x@7.0.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw=="], + + "@typescript/typescript-linux-x64": ["@typescript/typescript-linux-x64@7.0.2", "", { "os": "linux", "cpu": "x64" }, "sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A=="], + + "@typescript/typescript-netbsd-arm64": ["@typescript/typescript-netbsd-arm64@7.0.2", "", { "os": "none", "cpu": "arm64" }, "sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA=="], + + "@typescript/typescript-netbsd-x64": ["@typescript/typescript-netbsd-x64@7.0.2", "", { "os": "none", "cpu": "x64" }, "sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA=="], + + "@typescript/typescript-openbsd-arm64": ["@typescript/typescript-openbsd-arm64@7.0.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ=="], + + "@typescript/typescript-openbsd-x64": ["@typescript/typescript-openbsd-x64@7.0.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg=="], + + "@typescript/typescript-sunos-x64": ["@typescript/typescript-sunos-x64@7.0.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g=="], + + "@typescript/typescript-win32-arm64": ["@typescript/typescript-win32-arm64@7.0.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ=="], + + "@typescript/typescript-win32-x64": ["@typescript/typescript-win32-x64@7.0.2", "", { "os": "win32", "cpu": "x64" }, "sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g=="], + + "@yarnpkg/lockfile": ["@yarnpkg/lockfile@1.1.0", "", {}, "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ=="], + + "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + + "apk-parser": ["apk-parser@0.1.7", "", {}, "sha512-1ZbtTKD3RxdMfuCYe8qa3BVivH45S4N29q7/OERLElW7ENecI33YzBislNvBnZy2yBThtVx2Mf68j8/gvbmXuw=="], + + "apk_unpack": ["apk_unpack@1.2.1", "", { "dependencies": { "cheerio": "^0.22.0", "java": "^0.8.0", "line-reader": "^0.4.0", "yauzl": "^2.7.0" }, "bin": { "apk_unpack": "./cli" } }, "sha512-/fpBRnGPnpAuAwp+Gtih3PXG5ZzJboqYDp/+EtwYzXz00A/Ug8l1ZA1q9Kv/iVJPIlZMKXIPdCBwOX35xQlP/A=="], + + "async": ["async@2.0.1", "", { "dependencies": { "lodash": "^4.8.0" } }, "sha512-t7yBK5Pwp8Gq7q6LkAd6vyzLapJuuBhKDnDlgsNFR5KEG5XFzsXN2DFdoEz4qtxPoQFkTMNon73q6+Yn+P8Mcg=="], + + "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + + "boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="], + + "brace-expansion": ["brace-expansion@1.1.21", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw=="], + + "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], + + "buffer-crc32": ["buffer-crc32@0.2.13", "", {}, "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ=="], + + "bun-types": ["bun-types@1.4.3", "", { "dependencies": { "@types/node": "*", "undici-types": "*" } }, "sha512-tinRJNGOmUN+tEAsn2y2e942n9JHRHR42iUYzDH75NmhJqVBokGSQkkfSFdNWwsANIdrK6ACH9t01M452YyTwg=="], + + "call-bind": ["call-bind@1.0.9", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "get-intrinsic": "^1.3.0", "set-function-length": "^1.2.2" } }, "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ=="], + + "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], + + "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="], + + "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + + "cheerio": ["cheerio@0.22.0", "", { "dependencies": { "css-select": "~1.2.0", "dom-serializer": "~0.1.0", "entities": "~1.1.1", "htmlparser2": "^3.9.1", "lodash.assignin": "^4.0.9", "lodash.bind": "^4.1.4", "lodash.defaults": "^4.0.1", "lodash.filter": "^4.4.0", "lodash.flatten": "^4.2.0", "lodash.foreach": "^4.3.0", "lodash.map": "^4.4.0", "lodash.merge": "^4.4.0", "lodash.pick": "^4.2.1", "lodash.reduce": "^4.4.0", "lodash.reject": "^4.4.0", "lodash.some": "^4.4.0" } }, "sha512-8/MzidM6G/TgRelkzDG13y3Y9LxBjCb+8yOEZ9+wwq5gVF2w2pV0wmHvjfT0RvuxGyR7UEuK36r+yYMbT4uKgA=="], + + "ci-info": ["ci-info@3.9.0", "", {}, "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ=="], + + "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], + + "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + + "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], + + "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + + "css-select": ["css-select@1.2.0", "", { "dependencies": { "boolbase": "~1.0.0", "css-what": "2.1", "domutils": "1.5.1", "nth-check": "~1.0.1" } }, "sha512-dUQOBoqdR7QwV90WysXPLXG5LO7nhYBgiWVfxF80DKPF8zx1t/pUd2FYy73emg3zrjtM6dzmYgbHKfV2rxiHQA=="], + + "css-what": ["css-what@2.1.3", "", {}, "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg=="], + + "define-data-property": ["define-data-property@1.1.4", "", { "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", "gopd": "^1.0.1" } }, "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A=="], + + "dom-serializer": ["dom-serializer@0.1.1", "", { "dependencies": { "domelementtype": "^1.3.0", "entities": "^1.1.1" } }, "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA=="], + + "domelementtype": ["domelementtype@1.3.1", "", {}, "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w=="], + + "domhandler": ["domhandler@2.4.2", "", { "dependencies": { "domelementtype": "1" } }, "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA=="], + + "domutils": ["domutils@1.5.1", "", { "dependencies": { "dom-serializer": "0", "domelementtype": "1" } }, "sha512-gSu5Oi/I+3wDENBsOWBiRK1eoGxcywYSqg3rR960/+EfY0CF4EX1VPkgHOZ3WiS/Jg2DtliF6BhWcHlfpYUcGw=="], + + "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], + + "entities": ["entities@1.1.2", "", {}, "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w=="], + + "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], + + "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], + + "es-object-atoms": ["es-object-atoms@1.1.2", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw=="], + + "fd-slicer": ["fd-slicer@1.1.0", "", { "dependencies": { "pend": "~1.2.0" } }, "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g=="], + + "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], + + "find-java-home": ["find-java-home@0.1.3", "", { "dependencies": { "which": "~1.0.5" } }, "sha512-eJAuMyn9mF06BSlSaagh3OVF17us7NIvlnGmPyJUdO67gxnunUVGmim+l4Ja2O0FrRYLlBHmX4TwIyq+0Vsrvg=="], + + "find-yarn-workspace-root": ["find-yarn-workspace-root@2.0.0", "", { "dependencies": { "micromatch": "^4.0.2" } }, "sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ=="], + + "fs-extra": ["fs-extra@10.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ=="], + + "fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="], + + "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], + + "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], + + "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], + + "glob": ["glob@7.1.1", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.0.2", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-mRyN/EsN2SyNhKWykF3eEGhDpeNplMWaW18Bmh76tnOqk5TbELAVwFAYOCmKVssOYFrYvvLMguiA+NXO3ZTuVA=="], + + "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], + + "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], + + "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], + + "has-property-descriptors": ["has-property-descriptors@1.0.2", "", { "dependencies": { "es-define-property": "^1.0.0" } }, "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg=="], + + "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], + + "hasown": ["hasown@2.0.4", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A=="], + + "htmlparser2": ["htmlparser2@3.10.1", "", { "dependencies": { "domelementtype": "^1.3.1", "domhandler": "^2.3.0", "domutils": "^1.5.1", "entities": "^1.1.1", "inherits": "^2.0.1", "readable-stream": "^3.1.1" } }, "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ=="], + + "inflight": ["inflight@1.0.6", "", { "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA=="], + + "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], + + "is-docker": ["is-docker@2.2.1", "", { "bin": { "is-docker": "cli.js" } }, "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ=="], + + "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], + + "is-wsl": ["is-wsl@2.2.0", "", { "dependencies": { "is-docker": "^2.0.0" } }, "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww=="], + + "isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], + + "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + + "java": ["java@0.8.0", "", { "dependencies": { "async": "2.0.1", "find-java-home": "0.1.3", "glob": "7.1.1", "lodash": "4.16.4", "nan": "2.4.0" } }, "sha512-rz+rC6C7qQcGD69Vn49FKi8nnCM6QsUAKz5GNEmVdzQepnlIx6XKCGw84F/zVYrDSH3WhHoqwA29EqRD34xUGw=="], + + "java-bridge": ["java-bridge@2.8.1", "", { "optionalDependencies": { "java-bridge-darwin-arm64": "2.8.1", "java-bridge-darwin-x64": "2.8.1", "java-bridge-linux-arm64-gnu": "2.8.1", "java-bridge-linux-x64-gnu": "2.8.1", "java-bridge-linux-x64-musl": "2.8.1", "java-bridge-win32-ia32-msvc": "2.8.1", "java-bridge-win32-x64-msvc": "2.8.1" } }, "sha512-5z3c3r4cQaACk53UoLrTTJSm3gLtkz9/xOyd1gSWOcK+E7+qVwnA9hjuPUz7NrhfitavYs/eJX5//9q9Yiu5Pw=="], + + "java-bridge-darwin-arm64": ["java-bridge-darwin-arm64@2.8.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-29XDECsF7Qf1P+rbezTTetRUcl6ampsEFmOauyPzuZGZHmcw368s5c47LkQOVm2GxjnATMG41LhDPKK7TA+mXA=="], + + "java-bridge-darwin-x64": ["java-bridge-darwin-x64@2.8.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-DCDGZbetRnT/pMkT8zbjNorZGImpQUFXhqDXfLOFFlEfvE/SWz8rjcfIJP8f+T8EIlnaRDaNyEa9NvWhm9C4aQ=="], + + "java-bridge-linux-arm64-gnu": ["java-bridge-linux-arm64-gnu@2.8.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-j4xYKonqoydSUKFw4nLkdQSPSszIp2mHzX4nl24GnRmIhP+Dc1XZyh+KVDswMQdaNeYVb6ZEfaA3+DGe5o/bIg=="], + + "java-bridge-linux-x64-gnu": ["java-bridge-linux-x64-gnu@2.8.1", "", { "os": "linux", "cpu": "x64" }, "sha512-mbXiFSd3t3usmZXGQFYdiDM9K38DGyG72EMbFtaJ0bIfx7kK6T209G46sqGFnL5BR3KCTauQfFITyRyFjWVN6A=="], + + "java-bridge-linux-x64-musl": ["java-bridge-linux-x64-musl@2.8.1", "", { "os": "linux", "cpu": "x64" }, "sha512-hWdfMe2ndhCa7/40LbjtV14bUcxQd7IluT2XPOTvfhf46+u51QVbDTr2sjoxkPouGRYYtfCazukR7iUGRx1RiA=="], + + "java-bridge-win32-ia32-msvc": ["java-bridge-win32-ia32-msvc@2.8.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-gdPgVo61iSk0TuTky5551kgUbZEH4hgKpfpFg4UbJ7N1QaCNlpv8i6T9td1cHzwENuwqh/hb3YurFT+u2UqUvQ=="], + + "java-bridge-win32-x64-msvc": ["java-bridge-win32-x64-msvc@2.8.1", "", { "os": "win32", "cpu": "x64" }, "sha512-38+pgZ5uqQshjxVDDOuTSrYpXLLArA/p38p4qJ1K188pQUN2XdbO/No5duOKC6P6jwaRExrykhMrR3T9h9WYIQ=="], + + "json-stable-stringify": ["json-stable-stringify@1.3.0", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", "isarray": "^2.0.5", "jsonify": "^0.0.1", "object-keys": "^1.1.1" } }, "sha512-qtYiSSFlwot9XHtF9bD9c7rwKjr+RecWT//ZnPvSmEjpV5mmPOCN4j8UjY5hbjNkOwZ/jQv3J6R1/pL7RwgMsg=="], + + "jsonfile": ["jsonfile@6.2.1", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q=="], + + "jsonify": ["jsonify@0.0.1", "", {}, "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg=="], + + "klaw-sync": ["klaw-sync@6.0.0", "", { "dependencies": { "graceful-fs": "^4.1.11" } }, "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ=="], + + "line-reader": ["line-reader@0.4.0", "", {}, "sha512-AYJ8g+eE7v+Ba4s/cuYqzuNulH/WbjdKQ55fvx8fNVn8WQzTpioY6vI1MoxTuMgcHYX3VlmZWbVvnkIqkyJbCA=="], + + "lodash": ["lodash@4.16.4", "", {}, "sha512-nnaYhZqDvVKdmBJYqTAxIXxVUlRNwr8yfDKjKSpBEwoxi0Os+e5pU+/GtSO0mtTd06g49RCINYTmuixJR1Tz2w=="], + + "lodash.assignin": ["lodash.assignin@4.2.0", "", {}, "sha512-yX/rx6d/UTVh7sSVWVSIMjfnz95evAgDFdb1ZozC35I9mSFCkmzptOzevxjgbQUsc78NR44LVHWjsoMQXy9FDg=="], + + "lodash.bind": ["lodash.bind@4.2.1", "", {}, "sha512-lxdsn7xxlCymgLYo1gGvVrfHmkjDiyqVv62FAeF2i5ta72BipE1SLxw8hPEPLhD4/247Ijw07UQH7Hq/chT5LA=="], + + "lodash.defaults": ["lodash.defaults@4.2.0", "", {}, "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ=="], + + "lodash.filter": ["lodash.filter@4.6.0", "", {}, "sha512-pXYUy7PR8BCLwX5mgJ/aNtyOvuJTdZAo9EQFUvMIYugqmJxnrYaANvTbgndOzHSCSR0wnlBBfRXJL5SbWxo3FQ=="], + + "lodash.flatten": ["lodash.flatten@4.4.0", "", {}, "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g=="], + + "lodash.foreach": ["lodash.foreach@4.5.0", "", {}, "sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ=="], + + "lodash.map": ["lodash.map@4.6.0", "", {}, "sha512-worNHGKLDetmcEYDvh2stPCrrQRkP20E4l0iIS7F8EvzMqBBi7ltvFN5m1HvTf1P7Jk1txKhvFcmYsCr8O2F1Q=="], + + "lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="], + + "lodash.pick": ["lodash.pick@4.4.0", "", {}, "sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q=="], + + "lodash.reduce": ["lodash.reduce@4.6.0", "", {}, "sha512-6raRe2vxCYBhpBu+B+TtNGUzah+hQjVdu3E17wfusjyrXBka2nBS8OH/gjVZ5PvHOhWmIZTYri09Z6n/QfnNMw=="], + + "lodash.reject": ["lodash.reject@4.6.0", "", {}, "sha512-qkTuvgEzYdyhiJBx42YPzPo71R1aEr0z79kAv7Ixg8wPFEjgRgJdUsGMG3Hf3OYSF/kHI79XhNlt+5Ar6OzwxQ=="], + + "lodash.some": ["lodash.some@4.6.0", "", {}, "sha512-j7MJE+TuT51q9ggt4fSgVqro163BEFjAt3u97IqU+JA2DkWl80nFTrowzLpZ/BnpN7rrl0JA/593NAdd8p/scQ=="], + + "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], + + "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], + + "minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="], + + "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], + + "nan": ["nan@2.4.0", "", {}, "sha512-Ym8Mn5u8D8Fwo7fHWhD7xEyKe/y/J8Epkxp6iJfZhtgnRva+GN+dQddiWGE2cksWCV92K/HzdHlJWo7aZJDlFw=="], + + "nth-check": ["nth-check@1.0.2", "", { "dependencies": { "boolbase": "~1.0.0" } }, "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg=="], + + "object-keys": ["object-keys@1.1.1", "", {}, "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="], + + "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], + + "open": ["open@7.4.2", "", { "dependencies": { "is-docker": "^2.0.0", "is-wsl": "^2.1.1" } }, "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q=="], + + "patch-package": ["patch-package@8.0.1", "", { "dependencies": { "@yarnpkg/lockfile": "^1.1.0", "chalk": "^4.1.2", "ci-info": "^3.7.0", "cross-spawn": "^7.0.3", "find-yarn-workspace-root": "^2.0.0", "fs-extra": "^10.0.0", "json-stable-stringify": "^1.0.2", "klaw-sync": "^6.0.0", "minimist": "^1.2.6", "open": "^7.4.2", "semver": "^7.5.3", "slash": "^2.0.0", "tmp": "^0.2.4", "yaml": "^2.2.2" }, "bin": { "patch-package": "index.js" } }, "sha512-VsKRIA8f5uqHQ7NGhwIna6Bx6D9s/1iXlA1hthBVBEbkq+t4kXD0HHt+rJhf/Z+Ci0F/HCB2hvn0qLdLG+Qxlw=="], + + "path-is-absolute": ["path-is-absolute@1.0.1", "", {}, "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="], + + "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + + "pend": ["pend@1.2.0", "", {}, "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg=="], + + "picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="], + + "prettier": ["prettier@3.9.10", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-skGHTH1Yb9QvaTC4hWnRTzEYtCpApF0UMBPz+t/0ZPzP8ihefo/btKd+QA7pUE0fEwA1SbS/NmhyEcstdXOIdA=="], + + "readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], + + "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + + "semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], + + "set-function-length": ["set-function-length@1.2.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2" } }, "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg=="], + + "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + + "slash": ["slash@2.0.0", "", {}, "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A=="], + + "string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], + + "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + + "tmp": ["tmp@0.2.7", "", {}, "sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw=="], + + "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], + + "toml": ["toml@5.0.1", "", {}, "sha512-EqYNA/YvUNndrA2B3O2ojzLQoTQrBxeZ9UIjQwk8t10oe6n7dwclBwd9IdZQTOKwe6vWX+AXtl6IntXRbepdxQ=="], + + "typescript": ["typescript@7.0.2", "", { "optionalDependencies": { "@typescript/typescript-aix-ppc64": "7.0.2", "@typescript/typescript-darwin-arm64": "7.0.2", "@typescript/typescript-darwin-x64": "7.0.2", "@typescript/typescript-freebsd-arm64": "7.0.2", "@typescript/typescript-freebsd-x64": "7.0.2", "@typescript/typescript-linux-arm": "7.0.2", "@typescript/typescript-linux-arm64": "7.0.2", "@typescript/typescript-linux-loong64": "7.0.2", "@typescript/typescript-linux-mips64el": "7.0.2", "@typescript/typescript-linux-ppc64": "7.0.2", "@typescript/typescript-linux-riscv64": "7.0.2", "@typescript/typescript-linux-s390x": "7.0.2", "@typescript/typescript-linux-x64": "7.0.2", "@typescript/typescript-netbsd-arm64": "7.0.2", "@typescript/typescript-netbsd-x64": "7.0.2", "@typescript/typescript-openbsd-arm64": "7.0.2", "@typescript/typescript-openbsd-x64": "7.0.2", "@typescript/typescript-sunos-x64": "7.0.2", "@typescript/typescript-win32-arm64": "7.0.2", "@typescript/typescript-win32-x64": "7.0.2" }, "bin": { "tsc": "bin/tsc" } }, "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA=="], + + "undici-types": ["undici-types@8.12.1", "", {}, "sha512-nCiEcIx87oMw9u3Yzj2DuRBzv6p0e7akhy4HUPtpBiVWmAY3o6Phznst8QhmY1oLMttLgJ2tlAvsKuzCgBSoAw=="], + + "universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], + + "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], + + "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + + "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], + + "yaml": ["yaml@2.9.1", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw=="], + + "yauzl": ["yauzl@2.10.0", "", { "dependencies": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" } }, "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g=="], + + "@types/node/undici-types": ["undici-types@8.9.0", "", {}, "sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg=="], + + "find-java-home/which": ["which@1.0.9", "", { "bin": { "which": "./bin/which" } }, "sha512-E87fdQ/eRJr9W1X4wTPejNy9zTW3FI2vpCZSJ/HAY+TkjKVC0TUm1jk6vn2Z7qay0DQy0+RBGdXxj+RmmiGZKQ=="], + } +} diff --git a/cli b/cli new file mode 100755 index 0000000..0f6c95a --- /dev/null +++ b/cli @@ -0,0 +1,32 @@ +#!/usr/bin/env node +/* +apk_unpack CLI +Commandline utility to unpack an APK file resources +Usage: +node cli.js apkfile.apk outputdirectory +*/ +var apk = require("./apk_unpack"), // extract(apkfile, outputdir, onReadyCB) + args = process.argv.slice(2), + fs = require("fs"), + path = require("path"), + cur_dir = process.cwd(); +var _apk, _dir; + +console.log("APK unpacker"); + +if (args.length == 2) { + ((_apk = args[0]), (_dir = path.join(cur_dir, args[1]))); // assume output dir is subdir of current one. + if (args[1].charAt(0) == path.sep) { + _dir = args[1]; // if directory starts with a path separator, then we assume its an absolute directory. + } + apk.init({ apk: _apk, dir: _dir, java: true }); + apk.extract(function (err) { + //if (!err) console.log('ready!'); + console.log("apk_unpack -> decompiling classes.dex"); + apk.decompile(function () { + console.log("apk_unpack -> ready"); + }); + }); +} else { + console.log("Usage: apk_unpack apkfile.apk outputdirectory"); +} diff --git a/cppfmt.sh b/cppfmt.sh new file mode 100755 index 0000000..24df9c6 --- /dev/null +++ b/cppfmt.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +git ls-files -z | grep -z -E '\.(cpp|hpp|c|cc|cxx|hxx|ixx|h)$' | xargs -0 -r clang-format -i -style=file +echo "cpp/done" \ No newline at end of file diff --git a/deps/krita-android.lock.json b/deps/krita-android.lock.json new file mode 100644 index 0000000..da2202b --- /dev/null +++ b/deps/krita-android.lock.json @@ -0,0 +1,19 @@ +{ + "schema": 1, + "profile": "xiaomi-mi-reader-arm64-v8a", + "directSourceSubmodules": { + "krita": "2568c1a0ec2a5af697f89c15cc373a490ae7c70d", + "third_party/krita-deps-management": "aec874d026ac5a77b4bf09e26aa2ce86b2e8d489", + "third_party/krita-ci-utilities": "1f92316c6763380ac040db633674ed8a2467875a", + "third_party/kde-ci-utilities": "3f553a632a7022a8b3453c15c95afb789db25300", + "third_party/ci-notary-service": "4ff44b2cec28d1b80e2805c26c3cdcdc8bc5c29f" + }, + "generatedDependencySeed": "third_party/krita-deps-management/latest/krita-deps.yml", + "externalToolchains": { + "androidSdk": "set ANDROID_SDK_ROOT", + "androidNdk": "set ANDROID_NDK_ROOT", + "python": "Python 3 with venv support", + "java": "JDK required by the Android packaging step" + }, + "signing": "No Xiaomi key is required. Local builds are unsigned unless a separate ordinary signing step is requested." +} diff --git a/extracted/xiaomi-eink/README.md b/extracted/xiaomi-eink/README.md new file mode 100644 index 0000000..17ba5d9 --- /dev/null +++ b/extracted/xiaomi-eink/README.md @@ -0,0 +1,16 @@ +# Xiaomi Mi Reader E Ink compatibility library + +The extracted `libfakeRKEpdUtils.so` exposes an EBC overlay path on every +packaged ABI. `JniCall_CommitOverlay` accepts an Android bitmap, a source +rectangle and a destination point. The native implementation locks the bitmap +pixels, converts the selected RGBA region to Gray4 and commits that region to +the EBC overlay. It does not require an Android `View` redraw. + +Notable uses two paths. Live stylus samples are rasterized into the smallest +dirty bitmap and passed directly to `sCommitImage` once per display frame. On +pen-up, one delayed regional capture reconciles the overlay with Qt's retained +canvas. Full `View.draw()` capture is not used while the pen is moving. + +The relevant exported native functions are `obtain_ebc_target`, +`commit_overlay`, `convertRGBAtoGray4`, `set_overlay_commit`, +`set_overlay_bg_control`, `clearOverlayColor` and `release_ebc_target`. diff --git a/extracted/xiaomi-eink/SYMBOLS.md b/extracted/xiaomi-eink/SYMBOLS.md new file mode 100644 index 0000000..f1df8b6 --- /dev/null +++ b/extracted/xiaomi-eink/SYMBOLS.md @@ -0,0 +1,25 @@ +# Resolved symbol map + +| Original symbol | Resolved name | +| ------------------------- | ------------------------------------------- | +| EpdUtil.sInitEBC | XiaomiEinkRenderer constructor | +| EpdUtil.sRecycleEBC | XiaomiEinkRenderer.close | +| EpdUtil.sCommitImage | XiaomiEinkRenderer.commit | +| EpdUtil.sCommitColor | XiaomiEinkRenderer.clear | +| EpdUtil.sSetFastBgRefresh | XiaomiEinkRenderer.setFastBackgroundRefresh | +| EpdUtil.sSetFastHandWrite | XiaomiEinkRenderer.setFastHandwriting | +| EBCData | Native E Ink buffer handle | +| EBCCommitRequest | Image commit request | +| EBCCommitResult | Image commit result | + +## Native fast path + +| Export | Use | +| --- | --- | +| `obtain_ebc_target` | Acquires the hardware overlay and its bounds | +| `commit_overlay` | Writes a Gray4 region to the overlay target | +| `convertRGBAtoGray4` | Converts Android bitmap pixels for the panel | +| `set_overlay_commit` | Enables low-latency handwriting commits | +| `set_overlay_bg_control` | Selects fast background behavior | +| `clearOverlayColor` | Clears the overlay without a Qt redraw | +| `release_ebc_target` | Releases the mapped EBC target | diff --git a/extracted/xiaomi-eink/android/src/main/java/com/moan/fakerkepdlib/EpdUtil.java b/extracted/xiaomi-eink/android/src/main/java/com/moan/fakerkepdlib/EpdUtil.java new file mode 100644 index 0000000..9cb3b61 --- /dev/null +++ b/extracted/xiaomi-eink/android/src/main/java/com/moan/fakerkepdlib/EpdUtil.java @@ -0,0 +1,97 @@ +package com.moan.fakerkepdlib; + +import android.graphics.Bitmap; +import android.graphics.PointF; +import android.graphics.RectF; + +public final class EpdUtil { + static { + System.loadLibrary("fakeRKEpdUtils"); + } + + private EpdUtil() {} + + private static native int JniCall_ClearOverlayBuffer(int id, int color, int sendOsd); + + private static native int JniCall_CommitOverlay( + Bitmap bitmap, int id, float left, float top, float right, float bottom, float x, float y); + + private static native int JniCall_ObtainEBC(float[] bounds); + + private static native void JniCall_ReleaseEBC(int id); + + private static native int JniCall_SetOverLayBgControl(int id, int mode); + + private static native int JniCall_SetOverLayCommit(int id, int enabled); + + private static native int JniCall_test(int[] values); + + public static EBCData sInitEBC() { + float[] bounds = new float[4]; + int id = JniCall_ObtainEBC(bounds); + if (id < 0) return null; + EBCData data = new EBCData(); + data.mDataID = id; + data.mCommitBufRect.set(bounds[0], bounds[1], bounds[2], bounds[3]); + return data; + } + + public static void sRecycleEBC(EBCData data) { + if (data != null) JniCall_ReleaseEBC(data.mDataID); + } + + public static int sSetFastBgRefresh(EBCData data, boolean enabled) { + return JniCall_SetOverLayBgControl(data.mDataID, enabled ? 0 : 1); + } + + public static int sSetFastHandWrite(EBCData data, boolean enabled) { + return JniCall_SetOverLayCommit(data.mDataID, enabled ? 1 : 0); + } + + public static int sCommitColor(EBCData data, EBCCommitRequest request, EBCCommitResult result) { + return JniCall_ClearOverlayBuffer(data.mDataID, request.mCommitColor, request.mSendOsd); + } + + public static int sCommitImage(EBCData data, EBCCommitRequest request, EBCCommitResult result) { + int code = + request.mCommitType == EBCCommitRequest.COMMIT_CLEAR_COLOR + ? JniCall_ClearOverlayBuffer(data.mDataID, request.mCommitColor, request.mSendOsd) + : JniCall_CommitOverlay( + request.mCommitImg, + data.mDataID, + request.mCommitSrcRect.left, + request.mCommitSrcRect.top, + request.mCommitSrcRect.right, + request.mCommitSrcRect.bottom, + request.mCommitPt.x, + request.mCommitPt.y); + if (code > 0) result.mResultCode = 0; + return code; + } + + public static final class EBCData { + public int mDataID; + public final RectF mCommitBufRect = new RectF(); + + public int getEBCRect(RectF destination) { + destination.set(mCommitBufRect); + return 0; + } + } + + public static final class EBCCommitResult { + public int mResultCode; + } + + public static final class EBCCommitRequest { + public static final int COMMIT_NORMAL = 0, + COMMIT_WITH_SCALE = 1, + COMMIT_WITH_ROTATE = 2, + COMMIT_CLEAR_COLOR = 4; + public int mCommitColor, mCommitType, mSendOsd; + public final RectF mCommitDstRect = new RectF(); + public Bitmap mCommitImg; + public final PointF mCommitPt = new PointF(); + public final RectF mCommitSrcRect = new RectF(); + } +} diff --git a/extracted/xiaomi-eink/android/src/main/java/rip/crit/ms/eink/XiaomiEinkRenderer.java b/extracted/xiaomi-eink/android/src/main/java/rip/crit/ms/eink/XiaomiEinkRenderer.java new file mode 100644 index 0000000..ba59a0f --- /dev/null +++ b/extracted/xiaomi-eink/android/src/main/java/rip/crit/ms/eink/XiaomiEinkRenderer.java @@ -0,0 +1,131 @@ +package rip.crit.ms.eink; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.view.View; +import com.moan.fakerkepdlib.EpdUtil; +import rip.crit.ms.unote.Renderer; + +public final class XiaomiEinkRenderer implements Renderer { + private final EpdUtil.EBCData buffer; + private final View view; + // Panel coordinate compensation. The EBC overlay origin is the physical + // panel origin, while view coordinates exclude the status bar and any + // window insets, so commits must be translated by the view's screen + // position. Flip flags correct scan-direction mirroring per device. + private int manualDx; + private int manualDy; + private boolean flipX; + private boolean flipY; + + public XiaomiEinkRenderer(View view) { + this.view = view; + buffer = EpdUtil.sInitEBC(); + if (buffer == null) throw new IllegalStateException("The Xiaomi E Ink buffer is unavailable"); + setFastHandwriting(true); + setFastBackgroundRefresh(true); + } + + public void setFastHandwriting(boolean enabled) { + EpdUtil.sSetFastHandWrite(buffer, enabled); + } + + public void setFastBackgroundRefresh(boolean enabled) { + EpdUtil.sSetFastBgRefresh(buffer, enabled); + } + + /** Manual nudge on top of the automatic view-to-panel translation. */ + public void setManualOffset(int dx, int dy) { + manualDx = dx; + manualDy = dy; + } + + /** Enable when the panel scans mirrored; persists per renderer instance. */ + public void setMirror(boolean mirrorX, boolean mirrorY) { + flipX = mirrorX; + flipY = mirrorY; + } + + /** View origin in physical panel coordinates. */ + private android.graphics.Point panelOrigin() { + int[] loc = new int[2]; + try { + view.getLocationOnScreen(loc); + } catch (Exception e) { + loc[0] = 0; + loc[1] = 0; + } + return new android.graphics.Point(loc[0] + manualDx, loc[1] + manualDy); + } + + public int commit(Bitmap bitmap, Rect dirtyArea) { + android.graphics.Point origin = panelOrigin(); + EpdUtil.EBCCommitRequest request = new EpdUtil.EBCCommitRequest(); + Bitmap pixels = bitmap; + boolean recycled = false; + if (flipX || flipY) { + android.graphics.Matrix matrix = new android.graphics.Matrix(); + matrix.preScale(flipX ? -1f : 1f, flipY ? -1f : 1f); + matrix.postTranslate(flipX ? bitmap.getWidth() : 0, flipY ? bitmap.getHeight() : 0); + pixels = + Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false); + recycled = pixels != bitmap; + } + try { + request.mCommitImg = pixels; + request.mCommitSrcRect.set(0, 0, pixels.getWidth(), pixels.getHeight()); + request.mCommitPt.set(dirtyArea.left + origin.x, dirtyArea.top + origin.y); + return EpdUtil.sCommitImage(buffer, request, new EpdUtil.EBCCommitResult()); + } finally { + if (recycled) pixels.recycle(); + } + } + + public int commit(View view, Rect dirtyArea) { + Rect clipped = new Rect(dirtyArea); + clipped.intersect(0, 0, view.getWidth(), view.getHeight()); + if (clipped.isEmpty()) return 0; + Bitmap bitmap = Bitmap.createBitmap(clipped.width(), clipped.height(), Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + canvas.translate(-clipped.left, -clipped.top); + view.draw(canvas); + try { + return commit(bitmap, clipped); + } finally { + bitmap.recycle(); + } + } + + @Override + public boolean supportsPixels() { + return true; + } + + @Override + public boolean supportsRegions() { + return true; + } + + @Override + public boolean writePixels(Bitmap pixels, Rect region, Mode mode) { + return commit(pixels, region) >= 0; + } + + @Override + public boolean refresh(Rect region, Mode mode) { + return commit(view, region) >= 0; + } + + public int clear(int color) { + EpdUtil.EBCCommitRequest request = new EpdUtil.EBCCommitRequest(); + request.mCommitType = EpdUtil.EBCCommitRequest.COMMIT_CLEAR_COLOR; + request.mCommitColor = color; + return EpdUtil.sCommitColor(buffer, request, new EpdUtil.EBCCommitResult()); + } + + @Override + public void close() { + EpdUtil.sRecycleEBC(buffer); + } +} diff --git a/extracted/xiaomi-eink/android/src/main/jniLibs/arm64-v8a/libfakeRKEpdUtils.so b/extracted/xiaomi-eink/android/src/main/jniLibs/arm64-v8a/libfakeRKEpdUtils.so new file mode 100644 index 0000000..e730040 Binary files /dev/null and b/extracted/xiaomi-eink/android/src/main/jniLibs/arm64-v8a/libfakeRKEpdUtils.so differ diff --git a/extracted/xiaomi-eink/android/src/main/jniLibs/armeabi-v7a/libfakeRKEpdUtils.so b/extracted/xiaomi-eink/android/src/main/jniLibs/armeabi-v7a/libfakeRKEpdUtils.so new file mode 100644 index 0000000..e535303 Binary files /dev/null and b/extracted/xiaomi-eink/android/src/main/jniLibs/armeabi-v7a/libfakeRKEpdUtils.so differ diff --git a/extracted/xiaomi-eink/android/src/main/jniLibs/x86/libfakeRKEpdUtils.so b/extracted/xiaomi-eink/android/src/main/jniLibs/x86/libfakeRKEpdUtils.so new file mode 100644 index 0000000..6e8feaa Binary files /dev/null and b/extracted/xiaomi-eink/android/src/main/jniLibs/x86/libfakeRKEpdUtils.so differ diff --git a/extracted/xiaomi-eink/android/src/main/jniLibs/x86_64/libfakeRKEpdUtils.so b/extracted/xiaomi-eink/android/src/main/jniLibs/x86_64/libfakeRKEpdUtils.so new file mode 100644 index 0000000..0527d1e Binary files /dev/null and b/extracted/xiaomi-eink/android/src/main/jniLibs/x86_64/libfakeRKEpdUtils.so differ diff --git a/extractors/eink.ts b/extractors/eink.ts new file mode 100644 index 0000000..0dde1b4 --- /dev/null +++ b/extractors/eink.ts @@ -0,0 +1,189 @@ +import fs from "node:fs"; +import path from "node:path"; +import { spawnSync } from "node:child_process"; + +const root = path.resolve(import.meta.dir, ".."); +const apk = path.resolve( + process.argv[2] ?? path.join(root, "inputs", "MoanNote.apk"), +); +const output = path.resolve( + process.argv[3] ?? path.join(root, "extracted", "xiaomi-eink"), +); +const decoded = path.join(output, ".decoded"); +const apktool = path.join(root, "java", "apktool_2.4.1.jar"); + +function copyTree(source: string, destination: string): void { + fs.mkdirSync(destination, { recursive: true }); + for (const entry of fs.readdirSync(source, { withFileTypes: true })) { + const from = path.join(source, entry.name); + const to = path.join(destination, entry.name); + if (entry.isDirectory()) copyTree(from, to); + else fs.copyFileSync(from, to); + } +} + +function write(file: string, content: string): void { + fs.mkdirSync(path.dirname(file), { recursive: true }); + fs.writeFileSync(file, content.trimStart()); +} + +function main(): void { + if (!fs.existsSync(apk)) throw new Error(`APK not found at ${apk}`); + fs.rmSync(decoded, { recursive: true, force: true }); + fs.mkdirSync(output, { recursive: true }); + const result = spawnSync( + "java", + ["-jar", apktool, "d", "-f", "-r", apk, "-o", decoded], + { stdio: "inherit" }, + ); + if (result.status !== 0) + throw new Error(`Apktool decode failed with status ${result.status}`); + + const nativeSource = path.join(decoded, "lib"); + if (!fs.existsSync(nativeSource)) + throw new Error("MoanNote contains no native libraries"); + const jniLibs = path.join(output, "android", "src", "main", "jniLibs"); + for (const abi of fs.readdirSync(nativeSource)) { + const library = path.join(nativeSource, abi, "libfakeRKEpdUtils.so"); + if (!fs.existsSync(library)) continue; + fs.mkdirSync(path.join(jniLibs, abi), { recursive: true }); + fs.copyFileSync(library, path.join(jniLibs, abi, path.basename(library))); + } + const javaRoot = path.join(output, "android", "src", "main", "java"); + write( + path.join(javaRoot, "com/moan/fakerkepdlib/EpdUtil.java"), + nativeBinding, + ); + write( + path.join(javaRoot, "rip/crit/ms/eink/XiaomiEinkRenderer.java"), + facade, + ); + write(path.join(output, "SYMBOLS.md"), symbolMap); + write(path.join(output, "README.md"), extractedReadme); + fs.rmSync(decoded, { recursive: true, force: true }); + console.log(`[ok] Extracted E Ink compatibility library to ${output}`); +} + +const nativeBinding = String.raw` +package com.moan.fakerkepdlib; + +import android.graphics.Bitmap; +import android.graphics.PointF; +import android.graphics.RectF; + +public final class EpdUtil { + static { System.loadLibrary("fakeRKEpdUtils"); } + private EpdUtil() {} + private static native int JniCall_ClearOverlayBuffer(int id, int color, int sendOsd); + private static native int JniCall_CommitOverlay(Bitmap bitmap, int id, float left, float top, float right, float bottom, float x, float y); + private static native int JniCall_ObtainEBC(float[] bounds); + private static native void JniCall_ReleaseEBC(int id); + private static native int JniCall_SetOverLayBgControl(int id, int mode); + private static native int JniCall_SetOverLayCommit(int id, int enabled); + private static native int JniCall_test(int[] values); + + public static EBCData sInitEBC() { + float[] bounds = new float[4]; + int id = JniCall_ObtainEBC(bounds); + if (id < 0) return null; + EBCData data = new EBCData(); + data.mDataID = id; + data.mCommitBufRect.set(bounds[0], bounds[1], bounds[2], bounds[3]); + return data; + } + public static void sRecycleEBC(EBCData data) { if (data != null) JniCall_ReleaseEBC(data.mDataID); } + public static int sSetFastBgRefresh(EBCData data, boolean enabled) { return JniCall_SetOverLayBgControl(data.mDataID, enabled ? 0 : 1); } + public static int sSetFastHandWrite(EBCData data, boolean enabled) { return JniCall_SetOverLayCommit(data.mDataID, enabled ? 1 : 0); } + public static int sCommitColor(EBCData data, EBCCommitRequest request, EBCCommitResult result) { + return JniCall_ClearOverlayBuffer(data.mDataID, request.mCommitColor, request.mSendOsd); + } + public static int sCommitImage(EBCData data, EBCCommitRequest request, EBCCommitResult result) { + int code = request.mCommitType == EBCCommitRequest.COMMIT_CLEAR_COLOR + ? JniCall_ClearOverlayBuffer(data.mDataID, request.mCommitColor, request.mSendOsd) + : JniCall_CommitOverlay(request.mCommitImg, data.mDataID, request.mCommitSrcRect.left, + request.mCommitSrcRect.top, request.mCommitSrcRect.right, request.mCommitSrcRect.bottom, + request.mCommitPt.x, request.mCommitPt.y); + if (code > 0) result.mResultCode = 0; + return code; + } + public static final class EBCData { + public int mDataID; + public final RectF mCommitBufRect = new RectF(); + public int getEBCRect(RectF destination) { destination.set(mCommitBufRect); return 0; } + } + public static final class EBCCommitResult { public int mResultCode; } + public static final class EBCCommitRequest { + public static final int COMMIT_NORMAL = 0, COMMIT_WITH_SCALE = 1, COMMIT_WITH_ROTATE = 2, COMMIT_CLEAR_COLOR = 4; + public int mCommitColor, mCommitType, mSendOsd; + public final RectF mCommitDstRect = new RectF(); + public Bitmap mCommitImg; + public final PointF mCommitPt = new PointF(); + public final RectF mCommitSrcRect = new RectF(); + } +} +`; + +const facade = String.raw` +package rip.crit.ms.eink; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.view.View; +import com.moan.fakerkepdlib.EpdUtil; + +public final class XiaomiEinkRenderer implements AutoCloseable { + private final EpdUtil.EBCData buffer; + public XiaomiEinkRenderer() { + buffer = EpdUtil.sInitEBC(); + if (buffer == null) throw new IllegalStateException("The Xiaomi E Ink buffer is unavailable"); + } + public void setFastHandwriting(boolean enabled) { EpdUtil.sSetFastHandWrite(buffer, enabled); } + public void setFastBackgroundRefresh(boolean enabled) { EpdUtil.sSetFastBgRefresh(buffer, enabled); } + public int commit(Bitmap bitmap, Rect dirtyArea) { + EpdUtil.EBCCommitRequest request = new EpdUtil.EBCCommitRequest(); + request.mCommitImg = bitmap; + request.mCommitSrcRect.set(dirtyArea); + request.mCommitPt.set(dirtyArea.left, dirtyArea.top); + return EpdUtil.sCommitImage(buffer, request, new EpdUtil.EBCCommitResult()); + } + public int commit(View view, Rect dirtyArea) { + Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888); + view.draw(new Canvas(bitmap)); + try { return commit(bitmap, dirtyArea); } finally { bitmap.recycle(); } + } + public int clear(int color) { + EpdUtil.EBCCommitRequest request = new EpdUtil.EBCCommitRequest(); + request.mCommitType = EpdUtil.EBCCommitRequest.COMMIT_CLEAR_COLOR; + request.mCommitColor = color; + return EpdUtil.sCommitColor(buffer, request, new EpdUtil.EBCCommitResult()); + } + @Override public void close() { EpdUtil.sRecycleEBC(buffer); } +} +`; + +const symbolMap = `# Resolved symbol map + +The compatibility class keeps its original binary names because the JNI exports depend on them. New callers use the renamed facade. + +| Original symbol | Resolved name | +| --- | --- | +| EpdUtil.sInitEBC | XiaomiEinkRenderer constructor | +| EpdUtil.sRecycleEBC | XiaomiEinkRenderer.close | +| EpdUtil.sCommitImage | XiaomiEinkRenderer.commit | +| EpdUtil.sCommitColor | XiaomiEinkRenderer.clear | +| EpdUtil.sSetFastBgRefresh | XiaomiEinkRenderer.setFastBackgroundRefresh | +| EpdUtil.sSetFastHandWrite | XiaomiEinkRenderer.setFastHandwriting | +| EBCData | Native E Ink buffer handle | +| EBCCommitRequest | Image commit request | +| EBCCommitResult | Image commit result | +`; + +const extractedReadme = `# Xiaomi Mi Reader E Ink compatibility library + +This artifact is reconstructed from the supplied MoanNote APK. Copy the contents of \`android/src/main\` into an Android app module. The original JNI binding package is retained for binary compatibility. Application code should import \`rip.crit.ms.eink.XiaomiEinkRenderer\`. + +The native library is device-specific and should only be exercised on the intended Xiaomi Mi Reader firmware. +`; + +main(); diff --git a/extractors/index.ts b/extractors/index.ts new file mode 100644 index 0000000..64971b0 --- /dev/null +++ b/extractors/index.ts @@ -0,0 +1,362 @@ +import fs from "node:fs"; +import path from "node:path"; +import { spawnSync } from "node:child_process"; + +export interface SmaliPatch { + targetFile: string; + search?: string; + replace?: string; + injectFile?: string; +} + +interface TranslationConfig { + backend?: "argos" | "libre"; + source?: string; + target?: string; + url?: string; + apiKeyEnv?: string; +} + +interface XmlPatch { + targetFile: string; + search: string; + replace: string; +} + +interface ResourceConfig { + translation?: TranslationConfig; + overlay?: string; + assetOverlay?: string; + xmlPatches?: XmlPatch[]; +} + +interface GeneratedSmaliConfig { + sourceDir: string; +} + +export interface PatchConfig { + manifest: { + packagePrefix: string; + ordinarySignature?: boolean; + }; + resources?: ResourceConfig; + generatedSmali?: GeneratedSmaliConfig; + smaliPatches?: SmaliPatch[]; +} + +const cjk = /[\u3400-\u9fff]/; +const signaturePermissions = new Set([ + "android.permission.CHANGE_CONFIGURATION", + "android.permission.DELETE_PACKAGES", + "android.permission.FORCE_STOP_PACKAGES", + "android.permission.INTERACT_ACROSS_USERS", + "android.permission.MOUNT_UNMOUNT_FILESYSTEM", + "android.permission.READ_LOGS", + "android.permission.WRITE_SECURE_SETTINGS", +]); + +export function applyConfiguredTransforms( + workDir: string, + config: PatchConfig, + projectRoot: string, +): void { + const allowed = new Set([ + "manifest", + "resources", + "generatedSmali", + "smaliPatches", + ]); + const unsupported = Object.keys(config).filter((key) => !allowed.has(key)); + if (unsupported.length) + throw new Error( + `Unsupported patch sections: ${unsupported.join(", ")}. Code patches must be Smali patches.`, + ); + if (!config.manifest?.packagePrefix) + throw new Error("manifest.packagePrefix is required"); + renameManifestPackage( + workDir, + config.manifest.packagePrefix, + Boolean(config.manifest.ordinarySignature), + ); + if (config.resources?.translation) + createTranslatedStringOverlay( + workDir, + config.resources.translation, + projectRoot, + ); + if (config.resources?.overlay) + applyResourceOverlay(workDir, config.resources.overlay, projectRoot); + if (config.resources?.assetOverlay) + applyAssetOverlay(workDir, config.resources.assetOverlay, projectRoot); + applyXmlPatches(workDir, config.resources?.xmlPatches ?? []); + applyGeneratedSmali(workDir, config.generatedSmali, projectRoot); + applySmaliPatches(workDir, config.smaliPatches ?? [], projectRoot); +} + +function applyGeneratedSmali( + workDir: string, + config: GeneratedSmaliConfig | undefined, + projectRoot: string, +): void { + if (!config) return; + if ( + path.isAbsolute(config.sourceDir) || + config.sourceDir.split(/[\\/]/).includes("..") + ) + throw new Error("Generated Smali source must remain inside the repository"); + const source = path.join(projectRoot, config.sourceDir); + if (!fs.existsSync(source)) + throw new Error(`Generated Smali source not found: ${config.sourceDir}`); + const destination = path.join( + workDir, + "smali", + "rip", + "crit", + "ms", + "moannotes", + "nativebridge", + ); + fs.mkdirSync(destination, { recursive: true }); + fs.cpSync(source, destination, { recursive: true, force: true }); + console.log(` -> Applied generated Smali ${config.sourceDir}`); +} + +function applyAssetOverlay( + workDir: string, + overlay: string, + projectRoot: string, +): void { + if (path.isAbsolute(overlay) || overlay.split(/[\\/]/).includes("..")) + throw new Error("Asset overlay path must remain inside the repository"); + const source = path.join(projectRoot, overlay); + if (!fs.existsSync(source)) + throw new Error(`Asset overlay not found: ${overlay}`); + fs.cpSync(source, path.join(workDir, "assets"), { + recursive: true, + force: true, + }); + console.log(` -> Applied asset overlay ${overlay}`); +} + +function applyResourceOverlay( + workDir: string, + overlay: string, + projectRoot: string, +): void { + if (path.isAbsolute(overlay) || overlay.split(/[\\/]/).includes("..")) + throw new Error("Resource overlay path must remain inside the repository"); + const source = path.join(projectRoot, overlay); + if (!fs.existsSync(source)) + throw new Error(`Resource overlay not found: ${overlay}`); + fs.cpSync(source, path.join(workDir, "res"), { + recursive: true, + force: true, + }); + console.log(` -> Applied resource overlay ${overlay}`); +} + +function applyXmlPatches(workDir: string, patches: XmlPatch[]): void { + for (const [index, patch] of patches.entries()) { + if ( + path.isAbsolute(patch.targetFile) || + patch.targetFile.split(/[\\/]/).includes("..") || + !patch.targetFile.startsWith("res/") + ) + throw new Error(`XML patch ${index + 1} has an unsafe target path`); + const target = path.join(workDir, patch.targetFile); + if (!fs.existsSync(target)) + throw new Error( + `XML patch ${index + 1} target is missing: ${patch.targetFile}`, + ); + const source = fs.readFileSync(target, "utf8"); + const count = source.split(patch.search).length - 1; + if (count !== 1) + throw new Error( + `XML patch ${index + 1} expected one match, found ${count}`, + ); + fs.writeFileSync(target, source.replace(patch.search, patch.replace)); + } + if (patches.length) console.log(` -> Applied ${patches.length} XML patches`); +} + +function renameManifestPackage( + workDir: string, + prefix: string, + ordinarySignature: boolean, +): void { + const manifestPath = path.join(workDir, "AndroidManifest.xml"); + let xml = fs.readFileSync(manifestPath, "utf8"); + const match = xml.match(/\bpackage="([^"]+)"/); + if (!match) throw new Error("Manifest package attribute was not found"); + const original = match[1]!; + const renamed = original.startsWith(`${prefix}.`) + ? original + : `${prefix}.${original}`; + xml = xml.replace(`package="${original}"`, `package="${renamed}"`); + if (ordinarySignature) { + xml = xml.replace(/\s+android:sharedUserId="[^"]+"/, ""); + xml = xml.replace( + //g, + (element, permission: string) => + signaturePermissions.has(permission) ? "" : element, + ); + xml = xml.replaceAll( + `android:authorities="${original}`, + `android:authorities="${renamed}`, + ); + console.log(" -> Removed shared system UID and signature-only permissions"); + } + fs.writeFileSync(manifestPath, xml); + const apktoolPath = path.join(workDir, "apktool.yml"); + if (fs.existsSync(apktoolPath)) { + const yaml = fs + .readFileSync(apktoolPath, "utf8") + .replace( + /renameManifestPackage:.*$/m, + `renameManifestPackage: ${renamed}`, + ); + fs.writeFileSync(apktoolPath, yaml); + } + console.log(` -> Manifest package ${original} renamed to ${renamed}`); +} + +function createTranslatedStringOverlay( + workDir: string, + config: TranslationConfig, + projectRoot: string, +): void { + const sourcePath = path.join(workDir, "res", "values", "strings.xml"); + if (!fs.existsSync(sourcePath)) return; + const source = fs.readFileSync(sourcePath, "utf8"); + const entries: Array<{ name: string; attributes: string; value: string }> = + []; + const pattern = /]*)>([\s\S]*?)<\/string>/g; + for (const match of source.matchAll(pattern)) { + if (cjk.test(match[3]!)) + entries.push({ + name: match[1]!, + attributes: match[2]!, + value: match[3]!, + }); + } + if (!entries.length) return; + const apiKey = config.apiKeyEnv ? process.env[config.apiKeyEnv] : undefined; + const request = JSON.stringify({ + texts: entries.map((entry) => entry.value), + backend: config.backend ?? "argos", + source: config.source ?? "zh", + target: config.target ?? "en", + url: config.url, + apiKey, + }); + const bridge = path.join(projectRoot, "translator", "bridge.py"); + const localPython = path.join( + projectRoot, + ".venv-translator", + "bin", + "python", + ); + const python = + process.env.PYTHON ?? + (fs.existsSync(localPython) ? localPython : "python3"); + const result = spawnSync(python, [bridge], { + input: request, + encoding: "utf8", + maxBuffer: 16 * 1024 * 1024, + env: { + ...process.env, + ARGOS_PACKAGES_DIR: + process.env.ARGOS_PACKAGES_DIR ?? + path.join(projectRoot, ".argos-packages"), + XDG_DATA_HOME: path.join(projectRoot, ".argos-data"), + XDG_CONFIG_HOME: path.join(projectRoot, ".argos-config"), + XDG_CACHE_HOME: path.join(projectRoot, ".argos-cache"), + }, + }); + if (result.status !== 0) + throw new Error(`Translation bridge failed: ${result.stderr.trim()}`); + const response = JSON.parse(result.stdout) as { translations: string[] }; + if ( + !Array.isArray(response.translations) || + response.translations.length !== entries.length + ) + throw new Error("Translation bridge returned an invalid result count"); + const strings = entries.map( + (entry, index) => + ` ${escapeXmlText(response.translations[index]!)}`, + ); + const target = config.target ?? "en"; + const destination = path.join( + workDir, + "res", + `values-${target}`, + "strings.xml", + ); + fs.mkdirSync(path.dirname(destination), { recursive: true }); + fs.writeFileSync( + destination, + `\n\n${strings.join("\n")}\n\n`, + ); + console.log( + ` -> Added ${strings.length} ${target} translations through ${config.backend ?? "argos"}`, + ); +} + +function escapeXmlText(value: string): string { + return value + .replace(/&(?!#\d+;|#x[0-9A-Fa-f]+;|\w+;)/g, "&") + .replace(/<(?!\/?[A-Za-z][^>]*>)/g, "<") + .replace(/'/g, "\\'"); +} + +function applySmaliPatches( + workDir: string, + patches: SmaliPatch[], + projectRoot: string, +): void { + const smaliDirs = fs + .readdirSync(workDir) + .filter((name) => /^smali(?:_classes\d+)?$/.test(name)) + .sort(); + for (const [index, patch] of patches.entries()) { + if ( + path.isAbsolute(patch.targetFile) || + patch.targetFile.split(/[\\/]/).includes("..") + ) + throw new Error(`Smali patch ${index + 1} has an unsafe target path`); + if (!patch.targetFile.endsWith(".smali")) + throw new Error(`Smali patch ${index + 1} targets a non-Smali file`); + const existing = smaliDirs + .map((dir) => path.join(workDir, dir, patch.targetFile)) + .find(fs.existsSync); + const target = + existing ?? path.join(workDir, smaliDirs[0] ?? "smali", patch.targetFile); + if (patch.injectFile) { + const source = path.resolve(projectRoot, patch.injectFile); + if (!source.endsWith(".smali") || !fs.existsSync(source)) + throw new Error( + `Smali injection source not found for patch ${index + 1}`, + ); + fs.mkdirSync(path.dirname(target), { recursive: true }); + fs.copyFileSync(source, target); + continue; + } + if ( + patch.search === undefined || + patch.replace === undefined || + !fs.existsSync(target) + ) + throw new Error( + `Smali patch ${index + 1} is incomplete or its target is missing`, + ); + const content = fs.readFileSync(target, "utf8"); + const occurrences = content.split(patch.search).length - 1; + if (occurrences !== 1) + throw new Error( + `Smali patch ${index + 1} expected one match in ${patch.targetFile}, found ${occurrences}`, + ); + fs.writeFileSync(target, content.replace(patch.search, patch.replace)); + } + if (patches.length) + console.log(` -> Applied ${patches.length} Smali patches`); +} diff --git a/google-java-format-1.37.0-all-deps.jar b/google-java-format-1.37.0-all-deps.jar new file mode 100644 index 0000000..dcd2358 Binary files /dev/null and b/google-java-format-1.37.0-all-deps.jar differ diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..377538c --- /dev/null +++ b/gradle.properties @@ -0,0 +1,5 @@ +# This file was generated by the Gradle 'init' task. +# https://docs.gradle.org/current/userguide/build_environment.html#sec:gradle_configuration_properties + +org.gradle.configuration-cache=true + diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000..a1a7386 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,2 @@ +# This file was generated by the Gradle 'init' task. +# https://docs.gradle.org/current/userguide/version_catalogs.html#sec::toml-dependencies-format diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..eddabd2 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..ad7845b --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,9 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.1-bin.zip +networkTimeout=10000 +retries=0 +retryBackOffMs=500 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..249efbb --- /dev/null +++ b/gradlew @@ -0,0 +1,248 @@ +#!/bin/sh + +# +# Copyright © 2015 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# gradlew 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 gradlew +# +# 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/3d91ce3b8caaf77ad09f381f43615b715b53f72c/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 + + + +# 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" ) + + 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" \ + -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/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..a51ec4f --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,82 @@ +@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 gradlew startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables, and ensure extensions are enabled +setlocal EnableExtensions + +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 + +"%COMSPEC%" /c exit 1 + +: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 + +"%COMSPEC%" /c exit 1 + +:execute +@rem Setup the command line + + + +@rem Execute gradlew +@rem endlocal doesn't take effect until after the line is parsed and variables are expanded +@rem which allows us to clear the local environment before executing the java command +endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel + +:exitWithErrorLevel +@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts +"%COMSPEC%" /c exit %ERRORLEVEL% diff --git a/index.ts b/index.ts new file mode 100644 index 0000000..60ff29c --- /dev/null +++ b/index.ts @@ -0,0 +1,61 @@ +import fs from "node:fs"; +import path from "node:path"; +import { spawnSync } from "node:child_process"; +import TOML from "toml"; +import { applyConfiguredTransforms, type PatchConfig } from "./extractors"; + +const root = import.meta.dir; +const inputRoot = path.join(root, "inputs"); +const outputRoot = path.join(root, "outputs"); +const tempRoot = path.join(root, "temp"); +const apktoolJar = path.join(root, "java", "apktool_2.4.1.jar"); + +function run(command: string, args: string[]): void { + const result = spawnSync(command, args, { cwd: root, stdio: "inherit" }); + if (result.error) throw result.error; + if (result.status !== 0) + throw new Error(`${command} exited with status ${result.status}`); +} + +function processApp(file: string): void { + const input = path.join(inputRoot, file); + const appName = path.basename(file, path.extname(file)); + const workDir = path.join(tempRoot, appName); + const configPath = path.join(root, "apkpatch", `${appName}.toml`); + const output = path.join(outputRoot, `${appName}_patched.apk`); + + console.log(`[+] Processing ${file}`); + fs.rmSync(workDir, { recursive: true, force: true }); + run("java", ["-jar", apktoolJar, "d", "-f", input, "-o", workDir]); + if (!fs.existsSync(configPath)) + throw new Error(`Missing patch configuration ${configPath}`); + const config = TOML.parse(fs.readFileSync(configPath, "utf8")) as PatchConfig; + applyConfiguredTransforms(workDir, config, root); + fs.mkdirSync(outputRoot, { recursive: true }); + run("java", ["-jar", apktoolJar, "b", workDir, "-o", output]); + console.log(`[ok] Rebuilt ${output}`); +} + +function main(): void { + fs.mkdirSync(outputRoot, { recursive: true }); + fs.mkdirSync(tempRoot, { recursive: true }); + const requested = process.argv.slice(2); + const files = requested.length + ? requested.map((name) => (name.endsWith(".apk") ? name : `${name}.apk`)) + : fs + .readdirSync(inputRoot) + .filter((name) => name.endsWith(".apk")) + .sort(); + let failures = 0; + for (const file of files) { + try { + processApp(file); + } catch (error) { + failures++; + console.error(`[failed] ${file}`, error); + } + } + if (failures) process.exitCode = 1; +} + +main(); diff --git a/java/apktool_2.4.1.jar b/java/apktool_2.4.1.jar new file mode 100644 index 0000000..2eca808 Binary files /dev/null and b/java/apktool_2.4.1.jar differ diff --git a/java/jadx/android-29-clst.jar b/java/jadx/android-29-clst.jar new file mode 100644 index 0000000..5a4e2de Binary files /dev/null and b/java/jadx/android-29-clst.jar differ diff --git a/java/jadx/android-29-res.jar b/java/jadx/android-29-res.jar new file mode 100644 index 0000000..9baf62b Binary files /dev/null and b/java/jadx/android-29-res.jar differ diff --git a/java/jadx/animal-sniffer-annotations-1.18.jar b/java/jadx/animal-sniffer-annotations-1.18.jar new file mode 100644 index 0000000..3925273 Binary files /dev/null and b/java/jadx/animal-sniffer-annotations-1.18.jar differ diff --git a/java/jadx/annotations-18.0.0.jar b/java/jadx/annotations-18.0.0.jar new file mode 100644 index 0000000..cb85bb9 Binary files /dev/null and b/java/jadx/annotations-18.0.0.jar differ diff --git a/java/jadx/antlr-2.7.7.jar b/java/jadx/antlr-2.7.7.jar new file mode 100644 index 0000000..5e5f14b Binary files /dev/null and b/java/jadx/antlr-2.7.7.jar differ diff --git a/java/jadx/antlr-runtime-3.5.2.jar b/java/jadx/antlr-runtime-3.5.2.jar new file mode 100644 index 0000000..d48e3e8 Binary files /dev/null and b/java/jadx/antlr-runtime-3.5.2.jar differ diff --git a/java/jadx/apksig-3.5.2.jar b/java/jadx/apksig-3.5.2.jar new file mode 100644 index 0000000..d5b6883 Binary files /dev/null and b/java/jadx/apksig-3.5.2.jar differ diff --git a/java/jadx/asm-7.2.jar b/java/jadx/asm-7.2.jar new file mode 100644 index 0000000..5058db4 Binary files /dev/null and b/java/jadx/asm-7.2.jar differ diff --git a/java/jadx/baksmali-2.3.4.jar b/java/jadx/baksmali-2.3.4.jar new file mode 100644 index 0000000..2dfde94 Binary files /dev/null and b/java/jadx/baksmali-2.3.4.jar differ diff --git a/java/jadx/checker-qual-2.8.1.jar b/java/jadx/checker-qual-2.8.1.jar new file mode 100644 index 0000000..09269be Binary files /dev/null and b/java/jadx/checker-qual-2.8.1.jar differ diff --git a/java/jadx/commons-lang3-3.9.jar b/java/jadx/commons-lang3-3.9.jar new file mode 100644 index 0000000..0d89693 Binary files /dev/null and b/java/jadx/commons-lang3-3.9.jar differ diff --git a/java/jadx/commons-text-1.8.jar b/java/jadx/commons-text-1.8.jar new file mode 100644 index 0000000..f53b392 Binary files /dev/null and b/java/jadx/commons-text-1.8.jar differ diff --git a/java/jadx/dexlib2-2.3.4.jar b/java/jadx/dexlib2-2.3.4.jar new file mode 100644 index 0000000..0e5fdb6 Binary files /dev/null and b/java/jadx/dexlib2-2.3.4.jar differ diff --git a/java/jadx/dx-1.16.jar b/java/jadx/dx-1.16.jar new file mode 100644 index 0000000..6e468ce Binary files /dev/null and b/java/jadx/dx-1.16.jar differ diff --git a/java/jadx/error_prone_annotations-2.3.2.jar b/java/jadx/error_prone_annotations-2.3.2.jar new file mode 100644 index 0000000..bc2584d Binary files /dev/null and b/java/jadx/error_prone_annotations-2.3.2.jar differ diff --git a/java/jadx/failureaccess-1.0.1.jar b/java/jadx/failureaccess-1.0.1.jar new file mode 100644 index 0000000..9b56dc7 Binary files /dev/null and b/java/jadx/failureaccess-1.0.1.jar differ diff --git a/java/jadx/gson-2.8.6.jar b/java/jadx/gson-2.8.6.jar new file mode 100644 index 0000000..4765c4a Binary files /dev/null and b/java/jadx/gson-2.8.6.jar differ diff --git a/java/jadx/guava-28.1-jre.jar b/java/jadx/guava-28.1-jre.jar new file mode 100644 index 0000000..081cd11 Binary files /dev/null and b/java/jadx/guava-28.1-jre.jar differ diff --git a/java/jadx/image-viewer-1.2.3.jar b/java/jadx/image-viewer-1.2.3.jar new file mode 100644 index 0000000..073f756 Binary files /dev/null and b/java/jadx/image-viewer-1.2.3.jar differ diff --git a/java/jadx/j2objc-annotations-1.3.jar b/java/jadx/j2objc-annotations-1.3.jar new file mode 100644 index 0000000..a429c72 Binary files /dev/null and b/java/jadx/j2objc-annotations-1.3.jar differ diff --git a/java/jadx/jadx-cli-1.1.0.jar b/java/jadx/jadx-cli-1.1.0.jar new file mode 100644 index 0000000..15f28cc Binary files /dev/null and b/java/jadx/jadx-cli-1.1.0.jar differ diff --git a/java/jadx/jadx-core-1.1.0.jar b/java/jadx/jadx-core-1.1.0.jar new file mode 100644 index 0000000..921267d Binary files /dev/null and b/java/jadx/jadx-core-1.1.0.jar differ diff --git a/java/jadx/jadx-gui-1.1.0.jar b/java/jadx/jadx-gui-1.1.0.jar new file mode 100644 index 0000000..b67aa36 Binary files /dev/null and b/java/jadx/jadx-gui-1.1.0.jar differ diff --git a/java/jadx/jcommander-1.78.jar b/java/jadx/jcommander-1.78.jar new file mode 100644 index 0000000..1d58673 Binary files /dev/null and b/java/jadx/jcommander-1.78.jar differ diff --git a/java/jadx/jfontchooser-1.0.5.jar b/java/jadx/jfontchooser-1.0.5.jar new file mode 100644 index 0000000..3a9779f Binary files /dev/null and b/java/jadx/jfontchooser-1.0.5.jar differ diff --git a/java/jadx/jsr305-3.0.2.jar b/java/jadx/jsr305-3.0.2.jar new file mode 100644 index 0000000..59222d9 Binary files /dev/null and b/java/jadx/jsr305-3.0.2.jar differ diff --git a/java/jadx/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar b/java/jadx/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar new file mode 100644 index 0000000..45832c0 Binary files /dev/null and b/java/jadx/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar differ diff --git a/java/jadx/logback-classic-1.2.3.jar b/java/jadx/logback-classic-1.2.3.jar new file mode 100644 index 0000000..bed00c0 Binary files /dev/null and b/java/jadx/logback-classic-1.2.3.jar differ diff --git a/java/jadx/logback-core-1.2.3.jar b/java/jadx/logback-core-1.2.3.jar new file mode 100644 index 0000000..487b395 Binary files /dev/null and b/java/jadx/logback-core-1.2.3.jar differ diff --git a/java/jadx/reactive-streams-1.0.3.jar b/java/jadx/reactive-streams-1.0.3.jar new file mode 100644 index 0000000..b9b487c Binary files /dev/null and b/java/jadx/reactive-streams-1.0.3.jar differ diff --git a/java/jadx/rsyntaxtextarea-3.0.4.jar b/java/jadx/rsyntaxtextarea-3.0.4.jar new file mode 100644 index 0000000..df86c0a Binary files /dev/null and b/java/jadx/rsyntaxtextarea-3.0.4.jar differ diff --git a/java/jadx/rxjava-2.2.15.jar b/java/jadx/rxjava-2.2.15.jar new file mode 100644 index 0000000..1a019ad Binary files /dev/null and b/java/jadx/rxjava-2.2.15.jar differ diff --git a/java/jadx/rxjava2-swing-0.3.7.jar b/java/jadx/rxjava2-swing-0.3.7.jar new file mode 100644 index 0000000..db43fa6 Binary files /dev/null and b/java/jadx/rxjava2-swing-0.3.7.jar differ diff --git a/java/jadx/slf4j-api-1.7.29.jar b/java/jadx/slf4j-api-1.7.29.jar new file mode 100644 index 0000000..81ed475 Binary files /dev/null and b/java/jadx/slf4j-api-1.7.29.jar differ diff --git a/java/jadx/smali-2.3.4.jar b/java/jadx/smali-2.3.4.jar new file mode 100644 index 0000000..f499bfd Binary files /dev/null and b/java/jadx/smali-2.3.4.jar differ diff --git a/java/jadx/stringtemplate-3.2.1.jar b/java/jadx/stringtemplate-3.2.1.jar new file mode 100644 index 0000000..d0e11b7 Binary files /dev/null and b/java/jadx/stringtemplate-3.2.1.jar differ diff --git a/java/jadx/util-2.3.4.jar b/java/jadx/util-2.3.4.jar new file mode 100644 index 0000000..57cfd83 Binary files /dev/null and b/java/jadx/util-2.3.4.jar differ diff --git a/jfmt.sh b/jfmt.sh new file mode 100755 index 0000000..b7e92ad --- /dev/null +++ b/jfmt.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +git ls-files -co --exclude-standard | grep '\.java$' | xargs java \ + --add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \ + -jar google-java-format-1.37.0-all-deps.jar --replace + +echo "java/done" \ No newline at end of file diff --git a/jsfmt.sh b/jsfmt.sh new file mode 100755 index 0000000..9c7b047 --- /dev/null +++ b/jsfmt.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +biome format --fix &> /dev/null +echo "js/done" \ No newline at end of file diff --git a/justfile b/justfile new file mode 100644 index 0000000..e757e14 --- /dev/null +++ b/justfile @@ -0,0 +1,2 @@ +slim-archive: + git ls-files --cached --others --exclude-standard -z | grep -vFzxf <(git lfs ls-files -n) | tar -czvf archive.tar.gz --null -T - && make targz diff --git a/krita b/krita new file mode 160000 index 0000000..2568c1a --- /dev/null +++ b/krita @@ -0,0 +1 @@ +Subproject commit 2568c1a0ec2a5af697f89c15cc373a490ae7c70d diff --git a/krita-patches/xiaomi-eink.patch b/krita-patches/xiaomi-eink.patch new file mode 100644 index 0000000..d6771e2 --- /dev/null +++ b/krita-patches/xiaomi-eink.patch @@ -0,0 +1,1419 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 1f436c90cc..e0da6c7a1d 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -12,6 +12,17 @@ message(STATUS "Using CMake version: ${CMAKE_VERSION}") + # Select the Qt version we want to use + # Qt5 is the default, set QT_MAJOR_VERSION to 6 to look for Qt6 + option(BUILD_WITH_QT6 "Build against Qt 6" OFF) ++option(KRITA_EINK_SLIM "Build the light, monochrome E Ink painting configuration" OFF) ++option(KRITA_XIAOMI_EINK "Enable Xiaomi Mi Reader's optional EPD adapter" OFF) ++if(KRITA_EINK_SLIM) ++ set(BUILD_TESTING OFF CACHE BOOL "Tests are excluded from the E Ink build" FORCE) ++ set(ENABLE_UPDATERS OFF CACHE BOOL "Updaters are excluded from the E Ink build" FORCE) ++ set(FOUNDATION_BUILD OFF CACHE BOOL "Release extras are excluded from the E Ink build" FORCE) ++ add_compile_definitions(KRITA_EINK_SLIM=1) ++endif() ++if(KRITA_XIAOMI_EINK) ++ add_compile_definitions(KRITA_XIAOMI_EINK=1) ++endif() + + if (BUILD_WITH_QT6) + set(MIN_QT_VERSION 6.0.0) +diff --git a/libs/ui/KisApplication.cpp b/libs/ui/KisApplication.cpp +index a3bcdb2846..9b7eb6d33f 100644 +--- a/libs/ui/KisApplication.cpp ++++ b/libs/ui/KisApplication.cpp +@@ -549,7 +549,11 @@ bool KisApplication::start(const KisApplicationArguments &args) + KConfigGroup group(KSharedConfig::openConfig(), "theme"); + #ifndef Q_OS_HAIKU + Digikam::ThemeManager themeManager; ++#ifdef KRITA_EINK_SLIM ++ themeManager.setCurrentTheme("Krita light"); ++#else + themeManager.setCurrentTheme(group.readEntry("Theme", "Krita dark")); ++#endif + #endif + + ResetStarting resetStarting(d->splashScreen, args.filenames().count()); // remove the splash when done +diff --git a/libs/ui/KisMainWindow.cpp b/libs/ui/KisMainWindow.cpp +index d3a1e0afe8..a926a254f9 100644 +--- a/libs/ui/KisMainWindow.cpp ++++ b/libs/ui/KisMainWindow.cpp +@@ -377,7 +377,11 @@ KisMainWindow::KisMainWindow(QUuid uuid) + d->viewManager = new KisViewManager(this, actionCollection()); + KConfigGroup group( KSharedConfig::openConfig(), "theme"); + #ifndef Q_OS_HAIKU ++#ifdef KRITA_EINK_SLIM ++ d->themeManager = new Digikam::ThemeManager("Krita light", this); ++#else + d->themeManager = new Digikam::ThemeManager(group.readEntry("Theme", "Krita dark"), this); ++#endif + #endif + d->windowStateConfig = KSharedConfig::openConfig()->group("MainWindow"); + +@@ -2937,7 +2941,11 @@ void KisMainWindow::configChanged() + + KConfigGroup group( KSharedConfig::openConfig(), "theme"); + #ifndef Q_OS_HAIKU ++#ifdef KRITA_EINK_SLIM ++ d->themeManager->setCurrentTheme("Krita light"); ++#else + d->themeManager->setCurrentTheme(group.readEntry("Theme", "Krita dark")); ++#endif + #endif + d->actionManager()->updateGUI(); + +diff --git a/libs/ui/thememanager.cpp b/libs/ui/thememanager.cpp +index 81ca21e9c5..99e1a2a94d 100644 +--- a/libs/ui/thememanager.cpp ++++ b/libs/ui/thememanager.cpp +@@ -109,7 +109,11 @@ QString ThemeManager::currentThemeName() const + } + if (themeName.isEmpty()) { + //qDebug() << "\tfallback"; ++#ifdef KRITA_EINK_SLIM ++ themeName = "Krita light"; ++#else + themeName = "Krita dark"; ++#endif + } + //qDebug() << "\tresult" << themeName; + return themeName; +diff --git a/packaging/android/apk/AndroidManifest.xml b/packaging/android/apk/AndroidManifest.xml +index 553aff4c3d..e092710933 100644 +--- a/packaging/android/apk/AndroidManifest.xml ++++ b/packaging/android/apk/AndroidManifest.xml +@@ -1,5 +1,5 @@ + +- ++ + + + +diff --git a/packaging/android/apk/build.gradle b/packaging/android/apk/build.gradle +index be3b33441a..bd9ad0b8d7 100644 +--- a/packaging/android/apk/build.gradle ++++ b/packaging/android/apk/build.gradle +@@ -35,6 +35,7 @@ ext { + // tldr; at one time, either qt5AndroidDir or qtResPath is valid and points + // to the same files + qtResPath = System.getenv('KRITA_BUILD_APPBUNDLE') ? 'extra-bundle-deps/android/java' : "" ++ einkProfile = (System.getenv('KRITA_XIAOMI_EINK') ?: '0') in ['1', 'ON', 'true', 'TRUE'] + } + + tasks.register('configure') { +@@ -141,7 +142,7 @@ android { + * `package` attribute in the manifest, because androiddeployqt from Qt 5.15.x + * does not know how to fetch the package name from the Manifest + */ +- namespace = "org.krita" ++ namespace = "rip.crit.ms.org.krita" + + ndkPath ndkpath + +@@ -153,8 +154,10 @@ android { + + sourceSets { + main { ++ def uNoteSource = System.getenv('UNOTE_SOURCE_DIR') ++ def uNotePlusSource = System.getenv('UNOTE_PLUS_SOURCE_DIR') + manifest.srcFile 'AndroidManifest.xml' +- java.srcDirs = [qt5AndroidDir + '/src', qtResPath + '/src', 'src', 'java'] ++ java.srcDirs = [qt5AndroidDir + '/src', qtResPath + '/src', 'src', 'java'] + (uNoteSource ? [uNoteSource] : []) + (uNotePlusSource ? [uNotePlusSource] : []) + aidl.srcDirs = [qt5AndroidDir + '/src', qtResPath + '/src', 'src', 'aidl'] + res.srcDirs = [qt5AndroidDir + '/res', qtResPath + '/res', 'res'] + resources.srcDirs = ['src'] +@@ -170,8 +173,24 @@ android { + } + } + ++ signingConfigs { ++ release { ++ def releaseStore = System.getenv('MISSTRING_RELEASE_STORE_FILE') ++ if (releaseStore != null) { ++ storeFile file(releaseStore) ++ storePassword System.getenv('MISSTRING_RELEASE_STORE_PASSWORD') ++ keyAlias System.getenv('MISSTRING_RELEASE_KEY_ALIAS') ++ keyPassword System.getenv('MISSTRING_RELEASE_KEY_PASSWORD') ++ } ++ } ++ } ++ + buildTypes { + release { ++ if (System.getenv('MISSTRING_RELEASE_STORE_FILE') != null) { ++ signingConfig signingConfigs.release ++ } + minifyEnabled true + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), + 'proguard-rules.pro' +@@ -201,6 +220,10 @@ android { + def versionRelease = 0 + + defaultConfig { ++ applicationId "rip.crit.ms.org.krita" ++ if (einkProfile) { ++ ndk { abiFilters 'arm64-v8a' } ++ } + compileSdk androidCompileSdkVersion.toInteger() + + // even though buildToolsVersion is deprecated, +@@ -208,7 +231,8 @@ android { + // AGP will use the default one + buildToolsVersion "36.0.0" + +- ndkVersion "27.3.13750724" ++ // Keep AGP's declared NDK aligned with the NDK selected by ENV.sh or CI. ++ ndkVersion(System.getenv('KRITA_ANDROID_NDK_VERSION') ?: "28.2.13676358") + + targetSdkVersion 36 + minSdkVersion 24 +diff --git a/packaging/android/apk/proguard-rules.pro b/packaging/android/apk/proguard-rules.pro +index 91e3b04949..c671c1f36c 100644 +--- a/packaging/android/apk/proguard-rules.pro ++++ b/packaging/android/apk/proguard-rules.pro +@@ -8,3 +8,5 @@ + -keep class org.qtproject.qt5.android.** { *; } + -keep class org.krita.android.** { *; } + -keep class org.libsdl.app.** { *; } ++-keep class com.moan.fakerkepdlib.EpdUtil { *; } ++-keepclasseswithmembernames class * { native ; } +diff --git a/packaging/android/apk/src/org/krita/android/MainActivity.java b/packaging/android/apk/src/org/krita/android/MainActivity.java +index 093be86d51..611d322258 100644 +--- a/packaging/android/apk/src/org/krita/android/MainActivity.java ++++ b/packaging/android/apk/src/org/krita/android/MainActivity.java +@@ -30,8 +30,10 @@ import android.widget.Toast; + import androidx.annotation.RequiresApi; + + import java.util.List; ++import java.util.Optional; + +-import org.krita.R; ++import rip.crit.ms.org.krita.R; ++import rip.crit.ms.unote.UNoteEinkController; + import org.libsdl.app.SDLAudioManager; + import org.qtproject.qt5.android.QtNative; + import org.qtproject.qt5.android.bindings.QtActivity; +@@ -48,6 +50,8 @@ public class MainActivity extends QtActivity { + private boolean serviceStarted = false; + private boolean inFullScreen = false; + private DonationDialog mDonationDialog = null; ++ private XiaomiEinkController einkController = null; ++ private UNoteEinkController uNoteEinkController = null; + + @Override + @SuppressLint("MissingSuperCall") +@@ -71,6 +75,22 @@ public class MainActivity extends QtActivity { + Log.i(TAG, "LibsLoaded"); + haveLibsLoaded = true; + ++ // The Xiaomi EBC overlay is a private, panel-global resource. Do not acquire it ++ // automatically. A stale or competing overlay can make the whole display appear ++ // blank until the system compositor recovers. The adapter remains an explicit ++ // experimental opt-in while geometry and waveform calibration are device-verified. ++ final boolean xiaomiOverlayEnabled = getSharedPreferences("krita_eink", MODE_PRIVATE) ++ .getBoolean("xiaomi_overlay_experimental", false); ++ if (xiaomiOverlayEnabled) { ++ try { ++ einkController = new XiaomiEinkController(getWindow()); ++ Log.i(TAG, "Xiaomi E Ink overlay enabled by user preference"); ++ } catch (LinkageError | RuntimeException unavailable) { ++ Log.i(TAG, "Xiaomi E Ink overlay unavailable", unavailable); ++ } ++ } ++ ++ if (einkController == null && xiaomiOverlayEnabled) { ++ Optional controller = UNoteEinkController.create( ++ this, getWindow().getDecorView(), null); ++ if (controller.isPresent()) { ++ uNoteEinkController = controller.get(); ++ Log.i(TAG, "uNote E Ink provider enabled"); ++ } ++ } ++ + DonationHelper.getInstance(); + DonationProduct.initAllProducts(this); + } +@@ -165,9 +185,30 @@ public class MainActivity extends QtActivity { + Log.i(TAG, "[onDestroy]"); + startServiceGeneric(DocumentSaverService.KILL_PROCESS); + ++ if (einkController != null) { ++ einkController.close(); ++ einkController = null; ++ } ++ if (uNoteEinkController != null) { ++ uNoteEinkController.close(); ++ uNoteEinkController = null; ++ } + super.onDestroy(); + } + ++ @Override ++ public boolean dispatchTouchEvent(MotionEvent event) { ++ if (einkController != null && (event.isFromSource(InputDevice.SOURCE_STYLUS) ++ || event.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS)) { ++ einkController.onMotionEvent(event); ++ } ++ if (uNoteEinkController != null) { ++ uNoteEinkController.onMotionEvent(event); ++ } ++ // Qt receives the original event, including its untouched pressure and tilt axes. ++ return super.dispatchTouchEvent(event); ++ } ++ + @Override + public boolean onKeyUp(final int keyCode, final KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { +diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt +index 44d0867fb0..17726b2e35 100644 +--- a/plugins/CMakeLists.txt ++++ b/plugins/CMakeLists.txt +@@ -1,17 +1,24 @@ +-add_subdirectory( assistants ) + add_subdirectory( color ) + add_subdirectory( dockers ) +-add_subdirectory( extensions ) +-add_subdirectory( filters ) + add_subdirectory( flake ) +-add_subdirectory( generators ) ++add_subdirectory( filters ) + add_subdirectory( impex ) +-add_subdirectory( metadata ) + add_subdirectory( paintops ) + add_subdirectory( tools ) +-add_subdirectory( qt ) + +-if ((HAVE_PYQT5 OR HAVE_PYQT6) AND HAVE_SIP AND HAVE_PYTHONLIBS) ++if (NOT KRITA_EINK_SLIM) ++ add_subdirectory( assistants ) ++ add_subdirectory( extensions ) ++ add_subdirectory( generators ) ++ add_subdirectory( metadata ) ++ add_subdirectory( qt ) ++endif() ++ ++if(KRITA_EINK_SLIM) ++ add_subdirectory(extensions/einksync) ++endif() ++ ++if (NOT KRITA_EINK_SLIM AND (HAVE_PYQT5 OR HAVE_PYQT6) AND HAVE_SIP AND HAVE_PYTHONLIBS) + add_subdirectory( python ) + endif() + +diff --git a/plugins/dockers/CMakeLists.txt b/plugins/dockers/CMakeLists.txt +index f71b5b1042..de9ce3930d 100644 +--- a/plugins/dockers/CMakeLists.txt ++++ b/plugins/dockers/CMakeLists.txt +@@ -1,34 +1,40 @@ + add_subdirectory(layerdocker) +-if(HAVE_OPENEXR AND NOT ANDROID) +- add_subdirectory(smallcolorselector) +-endif() + add_subdirectory(specificcolorselector) +-add_subdirectory(digitalmixer) +-add_subdirectory(advancedcolorselector) + add_subdirectory(presetdocker) +-add_subdirectory(historydocker) +-add_subdirectory(channeldocker) +-add_subdirectory(artisticcolorselector) +-add_subdirectory(tasksetdocker) +-add_subdirectory(compositiondocker) +-add_subdirectory(patterndocker) +-add_subdirectory(griddocker) +-add_subdirectory(arrangedocker) +-if(HAVE_OCIO AND NOT ANDROID AND NOT HAIKU) +- add_subdirectory(lut) +-endif() +-add_subdirectory(overview) +-add_subdirectory(palettedocker) +-add_subdirectory(animation) +-add_subdirectory(presethistory) +-add_subdirectory(svgcollectiondocker) +-add_subdirectory(histogram) +-add_subdirectory(gamutmask) +-add_subdirectory(recorder) +-add_subdirectory(touchdocker) +-add_subdirectory(logdocker) +-add_subdirectory(snapshotdocker) +-add_subdirectory(storyboarddocker) +-add_subdirectory(widegamutcolorselector) + add_subdirectory(brushhud) +-add_subdirectory(textproperties) ++add_subdirectory(touchdocker) ++if(KRITA_EINK_SLIM) ++ add_subdirectory(einkmonochromeselector) ++endif() ++ ++if(NOT KRITA_EINK_SLIM) ++ if(HAVE_OPENEXR AND NOT ANDROID) ++ add_subdirectory(smallcolorselector) ++ endif() ++ add_subdirectory(digitalmixer) ++ add_subdirectory(advancedcolorselector) ++ add_subdirectory(historydocker) ++ add_subdirectory(channeldocker) ++ add_subdirectory(artisticcolorselector) ++ add_subdirectory(tasksetdocker) ++ add_subdirectory(compositiondocker) ++ add_subdirectory(patterndocker) ++ add_subdirectory(griddocker) ++ add_subdirectory(arrangedocker) ++ if(HAVE_OCIO AND NOT ANDROID AND NOT HAIKU) ++ add_subdirectory(lut) ++ endif() ++ add_subdirectory(overview) ++ add_subdirectory(palettedocker) ++ add_subdirectory(animation) ++ add_subdirectory(presethistory) ++ add_subdirectory(svgcollectiondocker) ++ add_subdirectory(histogram) ++ add_subdirectory(gamutmask) ++ add_subdirectory(recorder) ++ add_subdirectory(logdocker) ++ add_subdirectory(snapshotdocker) ++ add_subdirectory(storyboarddocker) ++ add_subdirectory(widegamutcolorselector) ++ add_subdirectory(textproperties) ++endif() +diff --git a/plugins/filters/CMakeLists.txt b/plugins/filters/CMakeLists.txt +index 91625abf9a..2d65b45fc4 100644 +--- a/plugins/filters/CMakeLists.txt ++++ b/plugins/filters/CMakeLists.txt +@@ -1,34 +1,37 @@ +-add_subdirectory( tests ) + add_subdirectory( blur ) + add_subdirectory( colors ) + add_subdirectory( colorsfilters ) + add_subdirectory( convolutionfilters ) +-add_subdirectory( gaussianhighpass) +-add_subdirectory( embossfilter ) +-add_subdirectory( example ) +-add_subdirectory( fastcolortransfer ) + add_subdirectory( imageenhancement ) +-add_subdirectory( noisefilter ) +-add_subdirectory( oilpaintfilter ) +-add_subdirectory( pixelizefilter ) +-add_subdirectory( raindropsfilter ) +-add_subdirectory( randompickfilter ) +-add_subdirectory( roundcorners ) +-add_subdirectory( smalltilesfilter ) + add_subdirectory( unsharp ) +-add_subdirectory( wavefilter ) + add_subdirectory( levelfilter ) +-add_subdirectory( dodgeburn ) +-add_subdirectory( phongbumpmap ) + add_subdirectory( posterize ) +-add_subdirectory( indexcolors ) + add_subdirectory( normalize ) +-add_subdirectory( gradientmap ) + add_subdirectory( threshold ) +-add_subdirectory( halftone ) + add_subdirectory( edgedetection ) +-add_subdirectory( convertheightnormalmap ) +-add_subdirectory( asccdl ) +-add_subdirectory( palettize ) +-add_subdirectory( resettransparent ) +-add_subdirectory( propagatecolors ) ++ ++if(NOT KRITA_EINK_SLIM) ++ add_subdirectory( tests ) ++ add_subdirectory( gaussianhighpass) ++ add_subdirectory( embossfilter ) ++ add_subdirectory( example ) ++ add_subdirectory( fastcolortransfer ) ++ add_subdirectory( noisefilter ) ++ add_subdirectory( oilpaintfilter ) ++ add_subdirectory( pixelizefilter ) ++ add_subdirectory( raindropsfilter ) ++ add_subdirectory( randompickfilter ) ++ add_subdirectory( roundcorners ) ++ add_subdirectory( smalltilesfilter ) ++ add_subdirectory( wavefilter ) ++ add_subdirectory( dodgeburn ) ++ add_subdirectory( phongbumpmap ) ++ add_subdirectory( indexcolors ) ++ add_subdirectory( gradientmap ) ++ add_subdirectory( halftone ) ++ add_subdirectory( convertheightnormalmap ) ++ add_subdirectory( asccdl ) ++ add_subdirectory( palettize ) ++ add_subdirectory( resettransparent ) ++ add_subdirectory( propagatecolors ) ++endif() +diff --git a/plugins/impex/CMakeLists.txt b/plugins/impex/CMakeLists.txt +index e2758ac756..1f15fb0c2e 100644 +--- a/plugins/impex/CMakeLists.txt ++++ b/plugins/impex/CMakeLists.txt +@@ -1,63 +1,54 @@ + project(kritafilters) + + add_subdirectory(libkra) +- + if(JPEG_FOUND AND HAVE_LCMS2) +- add_subdirectory(jpeg) +-endif() +- +-if(TIFF_FOUND AND JPEG_FOUND) +- add_subdirectory(tiff) ++ add_subdirectory(jpeg) + endif() +- + if(PNG_FOUND) + add_subdirectory(png) +- add_subdirectory(csv) +-endif() +- +-if(OpenEXR_FOUND) +- add_subdirectory(exr) + endif() +- +-if(Poppler_Qt${QT_MAJOR_VERSION}_FOUND) +- add_subdirectory(pdf) +-endif() +- +-if(OpenJPEG_FOUND AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD") +- add_subdirectory(jp2) +-endif() +- +-if(KF5KDcraw_FOUND OR KDcrawQt6_FOUND) +- add_subdirectory(raw) +-endif() +- +-add_subdirectory(svg) + add_subdirectory(qimageio) + add_subdirectory(ora) +-add_subdirectory(psd) +-add_subdirectory(qml) +-add_subdirectory(tga) +-add_subdirectory(heightmap) + add_subdirectory(brush) +-add_subdirectory(spriter) + add_subdirectory(kra) +- +-if (GIF_FOUND) +- add_subdirectory(gif) +-endif() +- +-if (HEIF_FOUND) +- add_subdirectory(heif) +-endif() +- + add_subdirectory(krz) + +-if (WebP_FOUND) +- add_subdirectory(webp) ++if(NOT KRITA_EINK_SLIM) ++ if(TIFF_FOUND AND JPEG_FOUND) ++ add_subdirectory(tiff) ++ endif() ++ if(PNG_FOUND) ++ add_subdirectory(csv) ++ endif() ++ if(OpenEXR_FOUND) ++ add_subdirectory(exr) ++ endif() ++ if(Poppler_Qt${QT_MAJOR_VERSION}_FOUND) ++ add_subdirectory(pdf) ++ endif() ++ if(OpenJPEG_FOUND AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD") ++ add_subdirectory(jp2) ++ endif() ++ if(KF5KDcraw_FOUND OR KDcrawQt6_FOUND) ++ add_subdirectory(raw) ++ endif() ++ add_subdirectory(svg) ++ add_subdirectory(psd) ++ add_subdirectory(qml) ++ add_subdirectory(tga) ++ add_subdirectory(heightmap) ++ add_subdirectory(spriter) ++ if(GIF_FOUND) ++ add_subdirectory(gif) ++ endif() ++ if(HEIF_FOUND) ++ add_subdirectory(heif) ++ endif() ++ if(WebP_FOUND) ++ add_subdirectory(webp) ++ endif() ++ if(JPEGXL_FOUND) ++ add_subdirectory(jxl) ++ endif() ++ add_subdirectory(rgbe) + endif() +- +-if (JPEGXL_FOUND) +- add_subdirectory(jxl) +-endif() +- +-add_subdirectory(rgbe) +diff --git a/plugins/paintops/CMakeLists.txt b/plugins/paintops/CMakeLists.txt +index ae0b64d5d9..1073b86054 100644 +--- a/plugins/paintops/CMakeLists.txt ++++ b/plugins/paintops/CMakeLists.txt +@@ -2,20 +2,23 @@ include_directories(libpaintop) + + add_subdirectory( libpaintop ) + add_subdirectory( defaultpaintops ) +-add_subdirectory( hairy ) +-add_subdirectory( deform ) +-add_subdirectory( curvebrush ) +-add_subdirectory( spray ) +-add_subdirectory( filterop ) +-add_subdirectory( experiment ) +-add_subdirectory( particle ) +-add_subdirectory( gridbrush ) +-add_subdirectory( hatching) +-add_subdirectory( sketch ) +-add_subdirectory( colorsmudge ) + add_subdirectory( roundmarker ) +-add_subdirectory( tangentnormal ) + +-if(LibMyPaint_FOUND) ++if (NOT KRITA_EINK_SLIM) ++ add_subdirectory( hairy ) ++ add_subdirectory( deform ) ++ add_subdirectory( curvebrush ) ++ add_subdirectory( spray ) ++ add_subdirectory( filterop ) ++ add_subdirectory( experiment ) ++ add_subdirectory( particle ) ++ add_subdirectory( gridbrush ) ++ add_subdirectory( hatching) ++ add_subdirectory( sketch ) ++ add_subdirectory( colorsmudge ) ++ add_subdirectory( tangentnormal ) ++endif() ++ ++if(NOT KRITA_EINK_SLIM AND LibMyPaint_FOUND) + add_subdirectory( mypaint ) + endif() +diff --git a/plugins/tools/CMakeLists.txt b/plugins/tools/CMakeLists.txt +index abf3ba2558..9549961fb0 100644 +--- a/plugins/tools/CMakeLists.txt ++++ b/plugins/tools/CMakeLists.txt +@@ -2,16 +2,19 @@ add_subdirectory( basictools ) + add_subdirectory( defaulttool ) + add_subdirectory( selectiontools ) + add_subdirectory( tool_crop ) +-add_subdirectory( tool_polygon ) +-add_subdirectory( tool_polyline ) + add_subdirectory( tool_transform2 ) +-add_subdirectory( tool_dyna ) +-add_subdirectory( karbonplugins ) +-add_subdirectory( tool_lazybrush ) +-add_subdirectory( tool_smart_patch ) +-add_subdirectory( svgtexttool ) +-add_subdirectory( tool_enclose_and_fill ) +-add_subdirectory( tool_knife ) ++ ++if (NOT KRITA_EINK_SLIM) ++ add_subdirectory( tool_polygon ) ++ add_subdirectory( tool_polyline ) ++ add_subdirectory( tool_dyna ) ++ add_subdirectory( karbonplugins ) ++ add_subdirectory( tool_lazybrush ) ++ add_subdirectory( tool_smart_patch ) ++ add_subdirectory( svgtexttool ) ++ add_subdirectory( tool_enclose_and_fill ) ++ add_subdirectory( tool_knife ) ++endif() + + + install( FILES +diff --git a/EINK_SLIM.md b/EINK_SLIM.md +new file mode 100644 +index 0000000000..d42a7c9760 +--- /dev/null ++++ b/EINK_SLIM.md +@@ -0,0 +1,17 @@ ++# E Ink slim build and Xiaomi adapter ++ ++Configure the general E Ink build with `-DKRITA_EINK_SLIM=ON`. It keeps the raster painting core, layers, the default and round-marker brush engines, brush presets, the freehand brush stabilizer, pressure and tilt events, selection, crop and transform tools, common blur and color filters, KRA, KRZ, ORA, PNG and JPEG support. It excludes tests, updates, assistants, Python, generators, animation, advanced brush engines, advanced dockers and uncommon importers. ++ ++The slim build forces Krita Light and replaces the advanced color selector with a 16-step monochrome selector. It includes continuous Syncthing export and Google Drive OAuth with PKCE. uNote preserves Android pressure and tilt data and aggregates partial-refresh damage. ++ ++`-DKRITA_XIAOMI_EINK=ON` packages optional Xiaomi hardware support but never acquires the panel-global EBC overlay automatically. It needs the explicit `krita_eink/xiaomi_overlay_experimental` preference after per-device geometry and waveform calibration. Stylus events continue to Qt unchanged, including pressure and tilt. The default path remains the normal Android compositor so a failed or conflicting private overlay cannot leave the panel in a broken state. ++ ++The Xiaomi adapter supports only `arm64-v8a` because the recovered vendor library is ARM64. The slim build itself remains usable without that adapter and falls back to normal Android rendering. ++ ++Krita's normal Android dependency toolchain is still required. Add this to the existing Android CMake arguments. ++ ++```text ++-DKRITA_EINK_SLIM=ON -DBUILD_TESTING=OFF -DENABLE_UPDATERS=OFF ++``` ++ ++Add `-DKRITA_XIAOMI_EINK=ON` and export `KRITA_XIAOMI_EINK=1` only for the Xiaomi Android package. Gradle then restricts the package to ARM64 and bundles the recovered native E Ink library from `packaging/android/apk/lib/arm64-v8a`. +diff --git a/packaging/android/apk/.gitignore b/packaging/android/apk/.gitignore +new file mode 100644 +index 0000000000..abc78ba75a +--- /dev/null ++++ b/packaging/android/apk/.gitignore +@@ -0,0 +1,2 @@ ++/.gradle/ ++/build/ +diff --git a/packaging/android/apk/settings.gradle b/packaging/android/apk/settings.gradle +new file mode 100644 +index 0000000000..8e0bdcbb55 +--- /dev/null ++++ b/packaging/android/apk/settings.gradle +@@ -0,0 +1,9 @@ ++pluginManagement { ++ repositories { ++ google() ++ mavenCentral() ++ gradlePluginPortal() ++ } ++} ++ ++rootProject.name = "krita-build-apk" +diff --git a/packaging/android/apk/lib/arm64-v8a/libfakeRKEpdUtils.so b/packaging/android/apk/lib/arm64-v8a/libfakeRKEpdUtils.so +new file mode 100644 +index 0000000000000000000000000000000000000000..e730040b53e0cb4eb6bdb443d069c4d550012a99 +GIT binary patch +literal 22592 +zcmeHvaa>bZmj8Kq0U}Y1fD +z-QqZA^w)GcyHlsFJBD^<=+>DrvpcI+r=NCqeyyEW>vU&+gQ#89w%QRX0m9wSdGFrv +z2%)y_=lA>L_v!KD=e_%V_uO;tx#ymHZ@Bk9xuSffisOJ055EFTb*9LOKtBj3mIFY5 +z0?>c}Q$a7~jT`a*Moxkn +zzIB&9R +zh-CnExf=j-0ALyb%u^^gk-ldEKstS&4*-b(l3yePKqdg(0|4UzAPGRS@oYsIS^%k? +zSY43j0KfzQm;wMZ03ZPXCIi4E0Js+b{ssW_0Fa?5Cl+D-(4GbW7)R^LD4V_*=`)Re +z0D!5AcSdvB3jj=4yw6g+Gnz?XXg8AVhm^`PL=n~t^P;}!vvJ^kiu39Wg@TTsy=OUg +zI<*F1uf`uAxA%?3R#qoqeeC(SpE%X`#&-@ibj^8s-}^sF`GG<8-QaxkVKS;mlS9|NzD>ZOGZG~jp8a{iH)zn2CF7MCwk +z{a>Y>T}}00MDy>7%8xM%>-kes09Z=<+}27*fzzmJyRK?CCvT7K>rcBrFrx6$(1 +zxP`G6<)&j`0Duj&91|^HgMl2!B|83nLGy2*_GIHFN6X(7W#`$noQ*gT0Kju}TzQ0+ +z(~SxMfR&d2HpQE$eOTOjXpDBjc0m0%V!#4`y;T1!+Fs=}2;W8JzDV`i9cBMcT22og +zl#a266vdit7O~duv^ebFvC*W(W7}r;z?zEHVx_a(WwCt)~ENj=Iu@)|7Qc4ufSG=XR*5;1EBsb~8{3t48aV9LjoB?Od^%ip^o`b^rZzk6b#6;jy}hP| +zA~p1Bb>NF=vsyeB5XI`27ObKh%@uhUMVhiXt0&hl@I +z!k?%4y-|1v#rH?yA5i?cDEvCbbri=XIUCcFG8H(kWf%zx9OwCrHYjj9luFd3z?Ey9 +zJqnyo9V9xWz?EwXohW}-spYjJqp1p<4Y^1L1x|-*i82+qavhbUz?Hu*6ew`EZbK3j +zxN`lxN`bRA8PZw>&ep9+8x%OMlNfDM;J6lLRIkA4)JLKw1x}k*qHPMC&9#uc3LMv| +zjP@vSTvIdJufTEr%;-4<&gRBQhZH!js~H_p;B;yzQHKJ@wLPO_3LMw+j7}(U_L~6G +zTMAsczCWYDajwkhyaLBHF{4feuKfL>TY)RrBR3Q{{szJ5#*X8G9Dx0k{;o8no4wR$ +zP-UFUFz{#Df9cyZr6FCh{7p*lD-G$Y73uGnhICIW($AKLbT2B>&zFXDZz$3~Dh=tn +z6zLaBLps&{l5DB`e@0yt>2{Q_NdFAwE7Jdh@)hY{qI^aA*C=0+{&$qGNWX#d9~hSZ +zCdyZ&e~0oF>32}RBK-%HuSlOm`HJ*MC|{BOKPX?3?n3#?hUI^Z@)hZ;C|{BO4CO1* +ze?|F-c<~$|L@xmT?3Qs3(;9&Nn)i}@vjO%Odl&gG +z@X+4LYuY~}L_aVwt*^h13-pPqK<|1!&{L@ngm=UR!X=z96`*@JT&+6(B7s3^HhM2X#gEx@EPs>{1oHVlKXsx%a-^CdY^dz^yVGMWcgFu +zyZCAC7kRyLFCqT7Ht#t0MLhUKUVlw9PNRKm^O9pv4H2_azb-z*sClp?gt}bfQ`=Ej +z{9XcHQ=|?PN1HJ1@0)1j}puest +z(8*^Q2NG8Hq0M{O|0d8=$pykYRDtj=@O8z(Q4I*83%sfwZHl&J_R7#f^EEX@>)Nil +zCEEtna1?D*Oo$(C>s9sTck)w=vkCG4MFk-Z2*F)anaqM9wMQk=e +z2gZqF0H5YtC83M7k6@oUF-R6)B1He}5b+b9fA3Zq>Yo@0@6ZOqr&K=knI&iUq{=c> +z0B2^MU*;<|fYf)6?3&ScXo&dn&myoJd_~|jVZVHAi1;t^V9W#PIMfb7;QAKRz9;h^ +zk@17MDPuW&!MAni#=XBEE>?Iob#=3=#j!?Lv^tJY=c{ +zuW63dwi)f0`Hc3WA>z+a!)q1}%t=x^2|@KxBo3ar$V0o-o|)r)C%|jEcZm28N$tV; +zPQpIZj96^}6QsPeSzDAvwZ*Xs5#6St&XrW>gGmuQ8SyHLZ<`pwCm_C_;$~e0PeA-J +ziqD%A!8yc5il!1xeUPkX?WPylASl`rM&Nli68q^VAr?$Fb-V+j6-FCp2{_WTV*%~ +zXBY|3OZ~eeO#I{&|K6Z$T%f-$G0-P!1HJ3V2YMD_-@3RFC3X3!Jh~de~8a8W`fr=(6A7GJ +zobgJ0duCF;DaH+9;?Gk>#j{njeA59^vcecUgt;8NN)O@`25LX<4QAeFONAw$yf^xYDk6DIymNkS0kA>9e`*sE28d4#Nv +zzmf9ZjlQUYAm(R2o-6Z*yZ}cr24VWiBnWl#$?Yqo`gtegm>byjsO0NK6VcZz0zH)v +z271?*2l~XaK!4quz@Te&fSi(jzFQ^h@gIZ4{A1XMV@iAfAn_Xp362ZQz%24_ia@#jI}XEtn$ +zlWaJghnDxjAn|7b>_ +zI*K*9k_;T +z0=`24xggCwivm5BZ%Ff{Oo06l +z;cs!?9Ai$%=2SQ3I6GX%?o4XqWFyWIR}T{ZO%3Gb0qlSMQ6Y3d14nBxjwyXloh9)+ +zFi8CMNkUMQ(3gMYQ6bdL!BLnX1P^h2`K%9QVIAf8Ff8+vd6M4QgE(i)Kp#rs!8>_` +zjH9xQnp6nhg>q8m{`m?AW{d@_k4_pS{u9x5*=>}{PaPzF4M56>a)r6lw~2$q|77aO +zxH5B4ic68Wf@v04<_{A8@kb$qV4-cY<5+RvCeFoAfiza5KWiQlLPv&(Wcy7+Bx3vD +z4G_N}+BVeo?+(cQusc?4q58gwc@l)+UkK5^g8K5@d%f$qK&-U}>b!~StXxN2(4o$< +zje6G?1=t#5F~I&09u-0dhsaTkE5Z=TzsYk(<~Kk565S7>9r+C7I2@y*<094FPi>8D +z|71KgW9;6Q3PJQAsUIG_S89{*4oLGNY5jMNkBXnKX8RVhew({M%KwxyzZ%S_JM%^7 +zfHdD38N+fGN_-djWTSh4_^Z@Waq*1Nhhwc2Tj{v7F;+RR&X1I{3Coek_u)R(nj`u3 +zBLl?$0wMYlKCfOR@tV-4;5A|FeIXTsVHz{MsSw1rF#lDKiQPlPF;TLWVjL(M7s +z7#MpTSUf=d2cySNIu87q5PhoTQ>yoF&BgU!d?36dArL;rMPe1M=Wx9zKwtjF==z>6 +zkm@^QK$`Ck+o7XS!u4`HMdrKQIP}BPKu_h$z^%D#zALY_u@6moLN?z6JKKMl6|Q?flhc%G!u%x7PIXnlC}bU)EQGj88sn;+ +z(e{mcHSw#i*8;T`>Q?7=eF9Bq~~M=KBXRF(yL*RKimiK_$sb*ln{uF?Q0k>_aG +zPSYO|LOa6bXuV!;rwL(VetnJ*{Ka%3i0$<@sLQTGTv_*g2xf9qw5z#f?W<4xBC+v_ +z*Au&cqRIN?R|#27ybx?xsmu1kl(Gg@T$wH&)@5+I2Hk7>({7YP(3&6we-6oI>mX5k +z8OD|ER>QhwoVp?FwcTkiaET4Qyvq2rN~>KE59^*e`AphzPTNqdhIOx;Y)i{fO=>s= +znzHj;qW0>~6S5Nj#h12>Q#EA0_H^3gkf;rDS}jpcZTK~e(_a0FCaaAHv&c_tDC5Cw +z=Y?QxvJmRxry4Kv(~S4*oZSI%*{mX>trvvQY@t@Lf7#+oq`=##}`04Fs{qj7t*ziCEyU3>+FYzfx +zlqbc36UuK>jhFao#>>3k_%WYmT*C7Fewl(FepU~7bWaEebZ;zZ``%72S*L=w&sv28^IC-i^H0ui(JP`GQ#R@#kW}&G*ED!%Z`)4r}7Ihc(ICVjbEN!MtxLmyGpT>zP@Vbuzo{ +zvz@|$cTVQCeHT<^?{Ls|mCrCch3oK7fwgM-}oPO%{2hFFk%hP7pa7TXis(!hbamV> +zYcy)@lhm%K0P<$Fs;g#=2h$%2(VyhJrZa@-XQhK_maasL-KcmLgIKR)}ZL;k`NXP9w-%tt@W%b7bpIgmuK$Dab6RdspVOEi3co +zoli?vuarok%;=3rC>G_ew6u7Z+gq9(Z08e<-tk4vJ>P2EI^R}Z6DtSq*)gyT2HZAe +zvl?*QS*=wvcp{XpFpDdSOT^-bR<2xOqFEAeUltZpy`@&PJ8NCpuG-obn}?PdL(!3H +zj9|4jS;a<|)pkeB^)`E5{hi5u+-{{V`E@JXWO3RYVhwKdyCbC^w>!mc3+|kC;T^MX +zzjLYE?^LSQQ!h3)-jT|3>wYQs3fzlkXtXpn*`0L;PrVJD%TO)t;WK33-I5ivanaw= +z?<=d8e{H|NL!XbZeO-T#Fn&E>kFb3$KaX(TfsaRczn*`OWc$iqHiGS|`}Ih+JCXMF +z{5c};EBG=FccV52M}wQ{%s3Uy62siG1^&2mxLQxN108I6JoWcMH+sZ5@Rrag$OfR8mqPqBY@Aw~+hB284bmQJLv2jf+g50v!RazMZ8odHz$p^m+UrAdY6CR7@e=hUBgy;^P~iw +ztjY;G;iX^Ld^D<-))voj5txX~ccU^=Gv40(+;n~kp5w!F1aEyn$nSCg|2aYi@qF`# +zgxtjejQ^03r5wQ24++7|5qEt^hy$PJ33-_VSaqI|(;R^2kA&da%R_%6M6CkYaDk9q +z6~M+WfX#R_ke^UV*>?Y(-DuBMLgpB6_(mx{v&kW{#M#xeg +zAonvu%sfEBXM{L-`Rp|k_Z<^(tuwjlg(xYr!d2lTv8h;){61PR%&UUVi%1<|<<8d1g0GvNdi1Hi&;(O6< +zX9;0>kr00w0RAls&qWLXI?fUzovGavB`bkPv@a1#mtFj{bf+3ddUSrpK)5VLGWlx)&~}X0q;t7B9+M +zn7er4ov?mG-_SSo4Shr3&^PoA{a+z=jy?L^I=w~&KBxDFuyiOY&Cap2?~~{xjHU5R +zJrYaLrD=8+)=AUsE-7}-9_N)v> +z4^6W(!0b#nEe86&Ez4!sogJeuY|hEfGP7%W3aEk%@1uu>sTv?qes)Hg$zx}$S-t@x +z*N53@h^Eie@<`P88#KL*eh<;K@(l3*3%WrM5&!@GWcTH<`x@B&42;;l4D22TM(q9t +zcHaUccFzL4CxH>WPazs-_a?A=5*V@j5!ihQj0howu44?Dix(}(&t05vz(1{64KAm_ +zy=ZaX;zbK;7GxP}92RGtVXMvEVs|+Wh1ogT1%}LekEf~SzWMXny&rWhSDnMw;@aY_ +zv1Q{X5Rc2{sHwNuo%0=zt&R6Kxm|d}kHMBxW3kzC3T%0`Ifd1W@^dW<^DT?>7h7|3 +z3-b$V3KrDXR4*u8SdeANjObEc{_umc+?K7*EP(8m`WBDdW2uI0r^{o@u5)h5uHIsI +zSnsu4K}ywITIwO&y4~5by-|L8-0~M%jS&ga4cTs+!-5R-t;ykmY>#c52eRER>8_G& +zTfJE8wlvzrdaHXlMO9#Cuv=|T4`kQcop#Y8-C~rD+*o|J+a;-DX|&fscAd*3e}e4l +zmKH#hH6rW(oG@--tYPsf@SCB8-LleK8imwZ=eGt9=2B!s|O<|VG1?c^|HiuClu@+& +z7XhUEKG=MN&3D*6q|DBYn0)s98LdC#XZH$q()(RmK1R{$f2H?(GJZC$vHM}!eXwjk +z#rTxrEbHXdpOv73pV5B<-THJ= + +literal 0 +HcmV?d00001 + +diff --git a/packaging/android/apk/src/com/moan/fakerkepdlib/EpdUtil.java b/packaging/android/apk/src/com/moan/fakerkepdlib/EpdUtil.java +new file mode 100644 +index 0000000000..694e122052 +--- /dev/null ++++ b/packaging/android/apk/src/com/moan/fakerkepdlib/EpdUtil.java +@@ -0,0 +1,57 @@ ++package com.moan.fakerkepdlib; ++ ++import android.graphics.Bitmap; ++import android.graphics.PointF; ++import android.graphics.RectF; ++ ++/** Binary-compatible binding reconstructed from MoanNote Smali. */ ++public final class EpdUtil { ++ static { System.loadLibrary("fakeRKEpdUtils"); } ++ private EpdUtil() {} ++ private static native int JniCall_ClearOverlayBuffer(int id, int color, int sendOsd); ++ private static native int JniCall_CommitOverlay(Bitmap bitmap, int id, float left, float top, float right, float bottom, float x, float y); ++ private static native int JniCall_ObtainEBC(float[] bounds); ++ private static native void JniCall_ReleaseEBC(int id); ++ private static native int JniCall_SetOverLayBgControl(int id, int mode); ++ private static native int JniCall_SetOverLayCommit(int id, int enabled); ++ private static native int JniCall_test(int[] values); ++ ++ public static EBCData sInitEBC() { ++ float[] bounds = new float[4]; ++ int id = JniCall_ObtainEBC(bounds); ++ if (id < 0) return null; ++ EBCData data = new EBCData(); ++ data.mDataID = id; ++ data.mCommitBufRect.set(bounds[0], bounds[1], bounds[2], bounds[3]); ++ return data; ++ } ++ public static void sRecycleEBC(EBCData data) { if (data != null) JniCall_ReleaseEBC(data.mDataID); } ++ public static int sSetFastBgRefresh(EBCData data, boolean enabled) { return JniCall_SetOverLayBgControl(data.mDataID, enabled ? 0 : 1); } ++ public static int sSetFastHandWrite(EBCData data, boolean enabled) { return JniCall_SetOverLayCommit(data.mDataID, enabled ? 1 : 0); } ++ public static int sCommitColor(EBCData data, EBCCommitRequest request, EBCCommitResult result) { ++ return JniCall_ClearOverlayBuffer(data.mDataID, request.mCommitColor, request.mSendOsd); ++ } ++ public static int sCommitImage(EBCData data, EBCCommitRequest request, EBCCommitResult result) { ++ int code = request.mCommitType == EBCCommitRequest.COMMIT_CLEAR_COLOR ++ ? JniCall_ClearOverlayBuffer(data.mDataID, request.mCommitColor, request.mSendOsd) ++ : JniCall_CommitOverlay(request.mCommitImg, data.mDataID, request.mCommitSrcRect.left, ++ request.mCommitSrcRect.top, request.mCommitSrcRect.right, request.mCommitSrcRect.bottom, ++ request.mCommitPt.x, request.mCommitPt.y); ++ if (code > 0) result.mResultCode = 0; ++ return code; ++ } ++ public static final class EBCData { ++ public int mDataID; ++ public final RectF mCommitBufRect = new RectF(); ++ public int getEBCRect(RectF destination) { destination.set(mCommitBufRect); return 0; } ++ } ++ public static final class EBCCommitResult { public int mResultCode; } ++ public static final class EBCCommitRequest { ++ public static final int COMMIT_NORMAL = 0, COMMIT_WITH_SCALE = 1, COMMIT_WITH_ROTATE = 2, COMMIT_CLEAR_COLOR = 4; ++ public int mCommitColor, mCommitType, mSendOsd; ++ public final RectF mCommitDstRect = new RectF(); ++ public Bitmap mCommitImg; ++ public final PointF mCommitPt = new PointF(); ++ public final RectF mCommitSrcRect = new RectF(); ++ } ++} +diff --git a/packaging/android/apk/src/org/krita/android/XiaomiEinkController.java b/packaging/android/apk/src/org/krita/android/XiaomiEinkController.java +new file mode 100644 +index 0000000000..7ef635c4ff +--- /dev/null ++++ b/packaging/android/apk/src/org/krita/android/XiaomiEinkController.java +@@ -0,0 +1,91 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++package org.krita.android; ++ ++import android.graphics.Bitmap; ++import android.graphics.Rect; ++import android.os.Handler; ++import android.os.HandlerThread; ++import android.util.Log; ++import android.view.MotionEvent; ++import android.view.PixelCopy; ++import android.view.Window; ++ ++import com.moan.fakerkepdlib.EpdUtil; ++import rip.crit.ms.unote.DamageTracker; ++import rip.crit.ms.unote.PenInput; ++import rip.crit.ms.unote.PenSample; ++ ++/** Sends pressure-aware dirty regions from Krita's Qt surface to Xiaomi's E Ink overlay. */ ++final class XiaomiEinkController implements AutoCloseable { ++ private static final String TAG = "krita.XiaomiEink"; ++ private final Window window; ++ private final HandlerThread worker = new HandlerThread("krita-eink-commit"); ++ private final Handler handler; ++ private final EpdUtil.EBCData buffer; ++ private final DamageTracker pending = new DamageTracker(); ++ private boolean captureScheduled; ++ private boolean closed; ++ ++ XiaomiEinkController(Window window) { ++ this.window = window; ++ worker.start(); ++ handler = new Handler(worker.getLooper()); ++ buffer = EpdUtil.sInitEBC(); ++ if (buffer == null) throw new IllegalStateException("Xiaomi E Ink buffer unavailable"); ++ EpdUtil.sSetFastBgRefresh(buffer, true); ++ EpdUtil.sSetFastHandWrite(buffer, true); ++ } ++ ++ void onMotionEvent(MotionEvent event) { ++ if (closed || event.getPointerCount() == 0) return; ++ final int index = event.getActionIndex(); ++ synchronized (pending) { ++ for (PenSample sample : PenInput.samples(event)) { ++ pending.add(sample, 18f, 42f, 8f); ++ } ++ if (!captureScheduled) { ++ captureScheduled = true; ++ handler.postDelayed(this::capture, event.getActionMasked() == MotionEvent.ACTION_UP ? 0 : 16); ++ } ++ } ++ } ++ ++ private void capture() { ++ final int width = window.getDecorView().getWidth(); ++ final int height = window.getDecorView().getHeight(); ++ if (closed || width <= 0 || height <= 0) return; ++ final Rect dirty; ++ synchronized (pending) { ++ dirty = pending.take(width, height); ++ captureScheduled = false; ++ } ++ if (dirty.isEmpty()) return; ++ final Bitmap frame = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); ++ PixelCopy.request(window, frame, result -> { ++ try { ++ if (result == PixelCopy.SUCCESS && !closed) commit(frame, dirty); ++ else Log.w(TAG, "PixelCopy failed with code " + result); ++ } finally { ++ frame.recycle(); ++ } ++ }, handler); ++ } ++ ++ private void commit(Bitmap frame, Rect dirty) { ++ EpdUtil.EBCCommitRequest request = new EpdUtil.EBCCommitRequest(); ++ request.mCommitImg = frame; ++ request.mCommitSrcRect.set(dirty); ++ request.mCommitPt.set(dirty.left, dirty.top); ++ int result = EpdUtil.sCommitImage(buffer, request, new EpdUtil.EBCCommitResult()); ++ if (result < 0) Log.w(TAG, "E Ink commit failed with code " + result); ++ } ++ ++ @Override public void close() { ++ if (closed) return; ++ closed = true; ++ EpdUtil.sSetFastHandWrite(buffer, false); ++ EpdUtil.sSetFastBgRefresh(buffer, false); ++ EpdUtil.sRecycleEBC(buffer); ++ worker.quitSafely(); ++ } ++} +diff --git a/plugins/dockers/einkmonochromeselector/CMakeLists.txt b/plugins/dockers/einkmonochromeselector/CMakeLists.txt +new file mode 100644 +index 0000000000..7a5d4f02b5 +--- /dev/null ++++ b/plugins/dockers/einkmonochromeselector/CMakeLists.txt +@@ -0,0 +1,3 @@ ++kis_add_library(kritaeinkmonochromeselector MODULE einkmonochromeselector.cpp) ++target_link_libraries(kritaeinkmonochromeselector kritaui) ++install(TARGETS kritaeinkmonochromeselector DESTINATION ${KRITA_PLUGIN_INSTALL_DIR}) +diff --git a/plugins/dockers/einkmonochromeselector/einkmonochromeselector.cpp b/plugins/dockers/einkmonochromeselector/einkmonochromeselector.cpp +new file mode 100644 +index 0000000000..dd7f50cb0d +--- /dev/null ++++ b/plugins/dockers/einkmonochromeselector/einkmonochromeselector.cpp +@@ -0,0 +1,73 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++class EinkMonochromeDock final : public QDockWidget, public KisMainwindowObserver ++{ ++ Q_OBJECT ++public: ++ EinkMonochromeDock() : QDockWidget(i18n("E Ink Grays")) { ++ auto *panel = new QWidget(this); ++ auto *layout = new QGridLayout(panel); ++ layout->setSpacing(3); ++ for (int step = 0; step < 16; ++step) { ++ const int gray = 255 - step * 17; ++ auto *button = new QPushButton(QString::number(step), panel); ++ button->setMinimumSize(44, 44); ++ button->setStyleSheet(QString("background:#%1%1%1;color:%2") ++ .arg(gray, 2, 16, QLatin1Char('0')).arg(gray < 128 ? "white" : "black")); ++ button->setAccessibleName(i18n("Gray level %1 of 15", step)); ++ connect(button, &QPushButton::clicked, this, [this, gray] { ++ if (!m_view) return; ++ KoColor color = m_view->canvasResourceProvider()->fgColor(); ++ color.fromQColor(QColor(gray, gray, gray)); ++ m_view->canvasResourceProvider()->slotSetFGColor(color); ++ }); ++ layout->addWidget(button, step / 4, step % 4); ++ } ++ setWidget(panel); ++ } ++ QString observerName() override { return QStringLiteral("EinkMonochromeDock"); } ++ void setCanvas(KoCanvasBase *canvas) override { setEnabled(canvas != nullptr); } ++ void unsetCanvas() override { setEnabled(false); } ++ void setViewManager(KisViewManager *view) override { m_view = view; } ++private: ++ KisViewManager *m_view = nullptr; ++}; ++ ++class EinkMonochromeFactory final : public KoDockFactoryBase ++{ ++public: ++ QString id() const override { return QStringLiteral("EinkMonochromeSelector"); } ++ Qt::DockWidgetArea defaultDockWidgetArea() const { return Qt::RightDockWidgetArea; } ++ QDockWidget *createDockWidget() override { ++ auto *dock = new EinkMonochromeDock(); ++ dock->setObjectName(id()); ++ return dock; ++ } ++ DockPosition defaultDockPosition() const override { return DockMinimized; } ++}; ++ ++class EinkMonochromePlugin final : public QObject ++{ ++ Q_OBJECT ++public: ++ EinkMonochromePlugin(QObject *parent, const QVariantList &) : QObject(parent) { ++ KoDockRegistry::instance()->add(new EinkMonochromeFactory()); ++ } ++}; ++ ++K_PLUGIN_FACTORY_WITH_JSON(EinkMonochromePluginFactory, "krita_einkmonochromeselector.json", registerPlugin();) ++#include "einkmonochromeselector.moc" +diff --git a/plugins/dockers/einkmonochromeselector/krita_einkmonochromeselector.json b/plugins/dockers/einkmonochromeselector/krita_einkmonochromeselector.json +new file mode 100644 +index 0000000000..494e2cfeed +--- /dev/null ++++ b/plugins/dockers/einkmonochromeselector/krita_einkmonochromeselector.json +@@ -0,0 +1,7 @@ ++{ ++ "Id": "EinkMonochromeSelector", ++ "Type": "Service", ++ "X-KDE-Library": "kritaeinkmonochromeselector", ++ "X-KDE-ServiceTypes": ["Krita/Dock"], ++ "X-Krita-Version": "28" ++} +diff --git a/plugins/extensions/einksync/CMakeLists.txt b/plugins/extensions/einksync/CMakeLists.txt +new file mode 100644 +index 0000000000..eaabbecb80 +--- /dev/null ++++ b/plugins/extensions/einksync/CMakeLists.txt +@@ -0,0 +1,5 @@ ++set(kritaeinksync_SOURCES EinkSyncPlugin.cpp) ++kis_add_library(kritaeinksync MODULE ${kritaeinksync_SOURCES}) ++target_link_libraries(kritaeinksync kritaui Qt${QT_MAJOR_VERSION}::Network) ++install(TARGETS kritaeinksync DESTINATION ${KRITA_PLUGIN_INSTALL_DIR}) ++install(FILES EinkSyncPlugin.action DESTINATION ${KDE_INSTALL_DATADIR}/krita/actions) +diff --git a/plugins/extensions/einksync/EinkSyncPlugin.action b/plugins/extensions/einksync/EinkSyncPlugin.action +new file mode 100644 +index 0000000000..b714a5941c +--- /dev/null ++++ b/plugins/extensions/einksync/EinkSyncPlugin.action +@@ -0,0 +1,13 @@ ++ ++ ++ ++ E Ink Sync ++ ++ E Ink Sync Settings... ++ Configure Syncthing folder and Google Drive export ++ ++ ++ Sync Current Document Now ++ ++ ++ +diff --git a/plugins/extensions/einksync/EinkSyncPlugin.cpp b/plugins/extensions/einksync/EinkSyncPlugin.cpp +new file mode 100644 +index 0000000000..3aaafe0b15 +--- /dev/null ++++ b/plugins/extensions/einksync/EinkSyncPlugin.cpp +@@ -0,0 +1,264 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++class EinkSyncPlugin final : public KisActionPlugin ++{ ++ Q_OBJECT ++public: ++ EinkSyncPlugin(QObject *parent, const QVariantList &) : KisActionPlugin(parent) { ++ connect(viewManager()->actionManager()->createAction("eink_sync_settings"), &QAction::triggered, ++ this, &EinkSyncPlugin::showSettings); ++ connect(viewManager()->actionManager()->createAction("eink_sync_now"), &QAction::triggered, ++ this, [this] { syncFile(viewManager()->document() ? viewManager()->document()->path() : QString()); }); ++ connect(KisPart::instance(), &KisPart::sigDocumentSaved, this, &EinkSyncPlugin::queueSync); ++ m_debounce.setSingleShot(true); ++ m_debounce.setInterval(1200); ++ connect(&m_debounce, &QTimer::timeout, this, [this] { syncFile(m_pendingPath); }); ++ } ++ ++private Q_SLOTS: ++ void queueSync(const QString &path) { ++ m_pendingPath = path; ++ m_debounce.start(); ++ } ++ ++ void showSettings() { ++ KConfigGroup cfg(KSharedConfig::openConfig(), "EinkSync"); ++ QDialog dialog(viewManager()->mainWindow()); ++ dialog.setWindowTitle(i18n("E Ink Continuous Sync")); ++ auto *layout = new QFormLayout(&dialog); ++ auto *enabled = new QCheckBox(i18n("Sync after every successful save"), &dialog); ++ enabled->setChecked(cfg.readEntry("Enabled", true)); ++ auto *folder = new QLineEdit(cfg.readEntry("SyncthingFolder", QString()), &dialog); ++ folder->setPlaceholderText(i18n("App-accessible Syncthing folder")); ++ auto *stUrl = new QLineEdit(cfg.readEntry("SyncthingUrl", "http://127.0.0.1:8384"), &dialog); ++ auto *stKey = new QLineEdit(cfg.readEntry("SyncthingApiKey", QString()), &dialog); ++ stKey->setEchoMode(QLineEdit::Password); ++ auto *client = new QLineEdit(cfg.readEntry("GoogleClientId", QString()), &dialog); ++ client->setPlaceholderText(i18n("Google OAuth desktop client ID")); ++ auto *google = new QPushButton(i18n("Authorize Google Drive"), &dialog); ++ layout->addRow(enabled); ++ layout->addRow(i18n("Syncthing folder"), folder); ++ layout->addRow(i18n("Syncthing address"), stUrl); ++ layout->addRow(i18n("Syncthing API key"), stKey); ++ layout->addRow(i18n("Google client ID"), client); ++ layout->addRow(google); ++ auto *buttons = new QDialogButtonBox(QDialogButtonBox::Save | QDialogButtonBox::Cancel, &dialog); ++ layout->addRow(buttons); ++ connect(google, &QPushButton::clicked, &dialog, [this, client] { beginGoogleLocalAuthorization(client->text()); }); ++ connect(buttons, &QDialogButtonBox::accepted, &dialog, &QDialog::accept); ++ connect(buttons, &QDialogButtonBox::rejected, &dialog, &QDialog::reject); ++ if (dialog.exec() == QDialog::Accepted) { ++ cfg.writeEntry("Enabled", enabled->isChecked()); ++ cfg.writeEntry("SyncthingFolder", folder->text().trimmed()); ++ cfg.writeEntry("SyncthingUrl", stUrl->text().trimmed()); ++ cfg.writeEntry("SyncthingApiKey", stKey->text().trimmed()); ++ cfg.writeEntry("GoogleClientId", client->text().trimmed()); ++ cfg.sync(); ++ } ++ } ++ ++private: ++ void syncFile(const QString &path) { ++ KConfigGroup cfg(KSharedConfig::openConfig(), "EinkSync"); ++ if (!cfg.readEntry("Enabled", true) || path.isEmpty() || !QFileInfo::exists(path)) return; ++ const QString folder = cfg.readEntry("SyncthingFolder", QString()); ++ if (!folder.isEmpty()) exportToSyncthing(path, folder); ++ const QString refreshToken = cfg.readEntry("GoogleRefreshToken", QString()); ++ if (!refreshToken.isEmpty()) refreshGoogleTokenAndUpload(path, refreshToken, cfg.readEntry("GoogleClientId", QString())); ++ } ++ ++ // Shared Syncthing contract (mirrors SyncthingHelper used by Notable ++ // and Share File): stage the file into the Syncthing folder, then ask ++ // the local Syncthing REST endpoint to rescan so peers converge. ++ void exportToSyncthing(const QString &source, const QString &folder) { ++ if (!QDir().mkpath(folder)) return; ++ QFile input(source); ++ QSaveFile output(QDir(folder).filePath(QFileInfo(source).fileName())); ++ if (!input.open(QIODevice::ReadOnly) || !output.open(QIODevice::WriteOnly)) return; ++ while (!input.atEnd()) output.write(input.read(1024 * 1024)); ++ if (!output.commit()) return; ++ KConfigGroup cfg(KSharedConfig::openConfig(), "EinkSync"); ++ const QString base = cfg.readEntry("SyncthingUrl", QStringLiteral("http://127.0.0.1:8384")); ++ QNetworkRequest scan{QUrl(base + QStringLiteral("/rest/db/scan?folder=") ++ + QString::fromUtf8(QUrl::toPercentEncoding(QFileInfo(source).fileName())))}; ++ const QString key = cfg.readEntry("SyncthingApiKey", QString()); ++ if (!key.isEmpty()) scan.setRawHeader("X-API-Key", key.toUtf8()); ++ auto *reply = m_network.post(scan, QByteArray()); ++ connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater); ++ } ++ ++ void beginGoogleLocalAuthorization(const QString &clientId) { ++ if (clientId.isEmpty()) return; ++ m_clientId = clientId; ++ delete m_oauthServer; ++ m_oauthServer = new QTcpServer(this); ++ if (!m_oauthServer->listen(QHostAddress::LocalHost, 0)) { ++ QMessageBox::warning(viewManager()->mainWindow(), i18n("Google Drive"), i18n("Could not open the local OAuth callback port")); ++ return; ++ } ++ m_oauthState = QUuid::createUuid().toString(QUuid::WithoutBraces); ++ m_pkceVerifier = QUuid::createUuid().toString(QUuid::WithoutBraces) ++ + QUuid::createUuid().toString(QUuid::WithoutBraces); ++ const QByteArray challenge = QCryptographicHash::hash(m_pkceVerifier.toUtf8(), QCryptographicHash::Sha256) ++ .toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals); ++ m_redirectUri = QString("http://127.0.0.1:%1/oauth2/callback").arg(m_oauthServer->serverPort()); ++ ++ connect(m_oauthServer, &QTcpServer::newConnection, this, [this] { ++ QTcpSocket *socket = m_oauthServer->nextPendingConnection(); ++ connect(socket, &QTcpSocket::readyRead, this, [this, socket] { ++ const QByteArray firstLine = socket->readLine(); ++ const QList parts = firstLine.split(' '); ++ QUrl callback(parts.size() > 1 ? QString("http://127.0.0.1") + QString::fromUtf8(parts[1]) : QString()); ++ QUrlQuery query(callback); ++ const bool valid = query.queryItemValue("state") == m_oauthState && !query.queryItemValue("code").isEmpty(); ++ const QByteArray message = valid ++ ? "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\nAuthorization complete. Return to Krita." ++ : "HTTP/1.1 400 Bad Request\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\nAuthorization failed. Return to Krita."; ++ socket->write(message); ++ socket->disconnectFromHost(); ++ m_oauthServer->close(); ++ if (!valid) return; ++ QUrlQuery form; ++ form.addQueryItem("client_id", m_clientId); ++ form.addQueryItem("code", query.queryItemValue("code")); ++ form.addQueryItem("code_verifier", m_pkceVerifier); ++ form.addQueryItem("redirect_uri", m_redirectUri); ++ form.addQueryItem("grant_type", "authorization_code"); ++ tokenRequest(form, [this](const QJsonObject &data) { ++ const QString refresh = data.value("refresh_token").toString(); ++ if (refresh.isEmpty()) { ++ QMessageBox::warning(viewManager()->mainWindow(), i18n("Google Drive"), i18n("Google returned no refresh token")); ++ return; ++ } ++ KConfigGroup cfg(KSharedConfig::openConfig(), "EinkSync"); ++ cfg.writeEntry("GoogleRefreshToken", refresh); ++ cfg.sync(); ++ QMessageBox::information(viewManager()->mainWindow(), i18n("Google Drive"), i18n("Authorization complete")); ++ }); ++ }); ++ }); ++ ++ QUrl authorization("https://accounts.google.com/o/oauth2/v2/auth"); ++ QUrlQuery query; ++ query.addQueryItem("client_id", clientId); ++ query.addQueryItem("redirect_uri", m_redirectUri); ++ query.addQueryItem("response_type", "code"); ++ query.addQueryItem("scope", "https://www.googleapis.com/auth/drive.file"); ++ query.addQueryItem("code_challenge", QString::fromLatin1(challenge)); ++ query.addQueryItem("code_challenge_method", "S256"); ++ query.addQueryItem("state", m_oauthState); ++ query.addQueryItem("access_type", "offline"); ++ query.addQueryItem("prompt", "consent"); ++ authorization.setQuery(query); ++ QDesktopServices::openUrl(authorization); ++ } ++ ++ void refreshGoogleTokenAndUpload(const QString &path, const QString &refreshToken, const QString &clientId) { ++ QUrlQuery form; ++ form.addQueryItem("client_id", clientId); ++ form.addQueryItem("refresh_token", refreshToken); ++ form.addQueryItem("grant_type", "refresh_token"); ++ tokenRequest(form, [this, path](const QJsonObject &data) { ++ const QString token = data.value("access_token").toString(); ++ if (!token.isEmpty()) uploadGoogleDrive(path, token); ++ }); ++ } ++ ++ void tokenRequest(const QUrlQuery &form, std::function callback) { ++ QNetworkRequest request{QUrl("https://oauth2.googleapis.com/token")}; ++ request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); ++ auto *reply = m_network.post(request, form.toString(QUrl::FullyEncoded).toUtf8()); ++ connect(reply, &QNetworkReply::finished, this, [reply, callback] { ++ const QJsonObject data = QJsonDocument::fromJson(reply->readAll()).object(); ++ reply->deleteLater(); ++ callback(data); ++ }); ++ } ++ ++ void uploadGoogleDrive(const QString &path, const QString &accessToken) { ++ auto *file = new QFile(path); ++ if (!file->open(QIODevice::ReadOnly)) { delete file; return; } ++ auto *body = new QHttpMultiPart(QHttpMultiPart::RelatedType); ++ QHttpPart metadata; ++ metadata.setHeader(QNetworkRequest::ContentTypeHeader, "application/json; charset=UTF-8"); ++ metadata.setBody(QJsonDocument(QJsonObject{{"name", QFileInfo(path).fileName()}}).toJson(QJsonDocument::Compact)); ++ QHttpPart media; ++ media.setHeader(QNetworkRequest::ContentTypeHeader, "application/octet-stream"); ++ media.setBodyDevice(file); ++ file->setParent(body); ++ body->append(metadata); ++ body->append(media); ++ KConfigGroup cfg(KSharedConfig::openConfig(), "EinkSync"); ++ const QString idKey = "GoogleFileId_" + QString::fromLatin1(QCryptographicHash::hash(path.toUtf8(), QCryptographicHash::Sha256).toHex()); ++ const QString fileId = cfg.readEntry(idKey, QString()); ++ const QString endpoint = fileId.isEmpty() ++ ? QStringLiteral("https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart") ++ : QStringLiteral("https://www.googleapis.com/upload/drive/v3/files/%1?uploadType=multipart").arg(fileId); ++ QNetworkRequest request{QUrl(endpoint)}; ++ request.setRawHeader("Authorization", QByteArray("Bearer ") + accessToken.toUtf8()); ++ QNetworkReply *reply = fileId.isEmpty() ++ ? m_network.post(request, body) ++ : m_network.sendCustomRequest(request, "PATCH", body); ++ body->setParent(reply); ++ connect(reply, &QNetworkReply::finished, this, [reply, idKey] { ++ const QJsonObject response = QJsonDocument::fromJson(reply->readAll()).object(); ++ const QString createdId = response.value("id").toString(); ++ if (!createdId.isEmpty()) { ++ KConfigGroup cfg(KSharedConfig::openConfig(), "EinkSync"); ++ cfg.writeEntry(idKey, createdId); ++ cfg.sync(); ++ } ++ reply->deleteLater(); ++ }); ++ } ++ ++ QNetworkAccessManager m_network; ++ QTimer m_debounce; ++ QString m_pendingPath; ++ QString m_clientId; ++ QString m_oauthState; ++ QString m_pkceVerifier; ++ QString m_redirectUri; ++ QTcpServer *m_oauthServer = nullptr; ++}; ++ ++K_PLUGIN_FACTORY_WITH_JSON(EinkSyncFactory, "kritaeinksync.json", registerPlugin();) ++#include "EinkSyncPlugin.moc" +diff --git a/plugins/extensions/einksync/kritaeinksync.json b/plugins/extensions/einksync/kritaeinksync.json +new file mode 100644 +index 0000000000..1ef752cd45 +--- /dev/null ++++ b/plugins/extensions/einksync/kritaeinksync.json +@@ -0,0 +1,7 @@ ++{ ++ "Id": "EinkSync", ++ "Type": "Service", ++ "X-KDE-Library": "kritaeinksync", ++ "X-KDE-ServiceTypes": ["Krita/ViewPlugin"], ++ "X-Krita-Version": "28" ++} diff --git a/moannotes-native/bin/main/rip/crit/ms/moannotes/nativebridge/KraExporter$1.class b/moannotes-native/bin/main/rip/crit/ms/moannotes/nativebridge/KraExporter$1.class new file mode 100644 index 0000000..81d276d Binary files /dev/null and b/moannotes-native/bin/main/rip/crit/ms/moannotes/nativebridge/KraExporter$1.class differ diff --git a/moannotes-native/bin/main/rip/crit/ms/moannotes/nativebridge/KraExporter$Layer.class b/moannotes-native/bin/main/rip/crit/ms/moannotes/nativebridge/KraExporter$Layer.class new file mode 100644 index 0000000..81f3751 Binary files /dev/null and b/moannotes-native/bin/main/rip/crit/ms/moannotes/nativebridge/KraExporter$Layer.class differ diff --git a/moannotes-native/bin/main/rip/crit/ms/moannotes/nativebridge/KraExporter.class b/moannotes-native/bin/main/rip/crit/ms/moannotes/nativebridge/KraExporter.class new file mode 100644 index 0000000..5accb01 Binary files /dev/null and b/moannotes-native/bin/main/rip/crit/ms/moannotes/nativebridge/KraExporter.class differ diff --git a/moannotes-native/bin/main/rip/crit/ms/moannotes/nativebridge/LayerPanel$1.class b/moannotes-native/bin/main/rip/crit/ms/moannotes/nativebridge/LayerPanel$1.class new file mode 100644 index 0000000..24696d7 Binary files /dev/null and b/moannotes-native/bin/main/rip/crit/ms/moannotes/nativebridge/LayerPanel$1.class differ diff --git a/moannotes-native/bin/main/rip/crit/ms/moannotes/nativebridge/LayerPanel$2.class b/moannotes-native/bin/main/rip/crit/ms/moannotes/nativebridge/LayerPanel$2.class new file mode 100644 index 0000000..1795194 Binary files /dev/null and b/moannotes-native/bin/main/rip/crit/ms/moannotes/nativebridge/LayerPanel$2.class differ diff --git a/moannotes-native/bin/main/rip/crit/ms/moannotes/nativebridge/LayerPanel.class b/moannotes-native/bin/main/rip/crit/ms/moannotes/nativebridge/LayerPanel.class new file mode 100644 index 0000000..bd4c7d9 Binary files /dev/null and b/moannotes-native/bin/main/rip/crit/ms/moannotes/nativebridge/LayerPanel.class differ diff --git a/moannotes-native/bin/main/rip/crit/ms/moannotes/nativebridge/LayerSettings.class b/moannotes-native/bin/main/rip/crit/ms/moannotes/nativebridge/LayerSettings.class new file mode 100644 index 0000000..f1b8b42 Binary files /dev/null and b/moannotes-native/bin/main/rip/crit/ms/moannotes/nativebridge/LayerSettings.class differ diff --git a/moannotes-native/bin/main/rip/crit/ms/moannotes/nativebridge/NativeFeatureHooks.class b/moannotes-native/bin/main/rip/crit/ms/moannotes/nativebridge/NativeFeatureHooks.class new file mode 100644 index 0000000..d6f308e Binary files /dev/null and b/moannotes-native/bin/main/rip/crit/ms/moannotes/nativebridge/NativeFeatureHooks.class differ diff --git a/moannotes-native/build.gradle b/moannotes-native/build.gradle new file mode 100644 index 0000000..be9f30c --- /dev/null +++ b/moannotes-native/build.gradle @@ -0,0 +1,47 @@ +plugins { + id 'java-library' +} + +repositories { + google() + mavenCentral() +} + +def androidHome = providers.environmentVariable('ANDROID_HOME') + .orElse(providers.environmentVariable('ANDROID_SDK_ROOT')) + .orElse('/var/home/hellings/android-sdk') +def androidJar = file("${androidHome.get()}/platforms/android-34/android.jar") + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } +} + +dependencies { + compileOnly files(androidJar) + runtimeOnly 'com.android.tools.smali:smali-baksmali:3.0.9' +} + +tasks.register('dexRelease', Exec) { + dependsOn tasks.named('jar') + def outputDir = layout.buildDirectory.dir('dex') + inputs.file(tasks.named('jar').flatMap { it.archiveFile }) + outputs.dir(outputDir) + doFirst { + outputDir.get().asFile.mkdirs() + commandLine "${androidHome.get()}/build-tools/34.0.0/d8", '--min-api', '23', '--lib', androidJar, + '--output', outputDir.get().asFile, tasks.named('jar').get().archiveFile.get().asFile + } +} + +tasks.register('smaliRelease', JavaExec) { + dependsOn tasks.named('dexRelease') + classpath = configurations.runtimeClasspath + mainClass = 'com.android.tools.smali.baksmali.Main' + args 'disassemble', layout.buildDirectory.file('dex/classes.dex').get().asFile, '-o', layout.buildDirectory.dir('smali').get().asFile +} + +tasks.named('build') { + dependsOn tasks.named('smaliRelease') +} diff --git a/moannotes-native/src/main/java/rip/crit/ms/moannotes/nativebridge/KraExporter.java b/moannotes-native/src/main/java/rip/crit/ms/moannotes/nativebridge/KraExporter.java new file mode 100644 index 0000000..654af25 --- /dev/null +++ b/moannotes-native/src/main/java/rip/crit/ms/moannotes/nativebridge/KraExporter.java @@ -0,0 +1,241 @@ +package rip.crit.ms.moannotes.nativebridge; + +import android.app.Activity; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Color; +import android.os.Handler; +import android.os.Looper; +import android.widget.Toast; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.nio.charset.StandardCharsets; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.Locale; +import java.util.TimeZone; +import java.util.UUID; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +/** Writes the documented legacy KRA tile stream so Krita receives editable paint layers. */ +public final class KraExporter { + private static final int TILE = 64; + + private KraExporter() {} + + public static void exportCurrentPage(final Activity activity, final Object handwriteView) { + Toast.makeText(activity, "Exporting KRA", Toast.LENGTH_SHORT).show(); + new Thread( + () -> { + try { + File output = export(activity, handwriteView); + new Handler(Looper.getMainLooper()) + .post( + () -> + Toast.makeText(activity, "Saved " + output.getName(), Toast.LENGTH_LONG) + .show()); + } catch (Exception error) { + new Handler(Looper.getMainLooper()) + .post( + () -> + Toast.makeText(activity, "KRA export failed", Toast.LENGTH_LONG) + .show()); + } + }, + "moannotes-kra-export") + .start(); + } + + public static File export(Activity activity, Object handwriteView) throws Exception { + Object pageConfig = field(handwriteView, "mPageConfigData"); + int page = intField(pageConfig, "mEditPage"); + Class layerClass = Class.forName("com.moan.notes.hand.data.config.LayerConfigData"); + Method load = + layerClass.getMethod( + "sLoadLayerConfig", + android.content.Context.class, + pageConfig.getClass(), + int.class, + layerClass); + Object config = load.invoke(null, activity, pageConfig, page, null); + if (config == null) throw new IOException("Page layers are unavailable"); + + int width = intField(config, "mLayerWidth"); + int height = intField(config, "mLayerHeight"); + if (width < 1 || height < 1) throw new IOException("Page has no canvas"); + @SuppressWarnings("unchecked") + ArrayList folders = (ArrayList) field(config, "mLayerDataFolders"); + @SuppressWarnings("unchecked") + ArrayList visible = (ArrayList) field(config, "mEditLayerVisible"); + String parent = (String) field(config, "mParentPath"); + + File directory = activity.getExternalFilesDir("exports"); + if (directory == null) directory = new File(activity.getFilesDir(), "exports"); + if (!directory.exists() && !directory.mkdirs()) + throw new IOException("Cannot create export folder"); + String stamp = new SimpleDateFormat("yyyyMMdd-HHmmss", Locale.US).format(new Date()); + File out = new File(directory, "MoanNotes-" + stamp + ".kra"); + + ArrayList layers = new ArrayList<>(); + for (int index = 0; index < folders.size(); index++) { + File image = new File(new File(parent, folders.get(index)), "scene_image.png"); + Bitmap bitmap = BitmapFactory.decodeFile(image.getAbsolutePath()); + if (bitmap != null) + layers.add( + new Layer( + index, + bitmap, + visible.get(index) != 0, + LayerSettings.opacity(activity, parent, index), + LayerSettings.blend(activity, parent, index))); + } + if (layers.isEmpty()) throw new IOException("No layer images were found"); + writeKra(out, width, height, layers); + for (Layer layer : layers) if (!layer.bitmap.isRecycled()) layer.bitmap.recycle(); + return out; + } + + private static void writeKra(File target, int width, int height, ArrayList layers) + throws IOException { + try (ZipOutputStream zip = new ZipOutputStream(new FileOutputStream(target))) { + entry(zip, "mimetype", "application/x-krita".getBytes(StandardCharsets.US_ASCII)); + entry( + zip, "maindoc.xml", documentXml(width, height, layers).getBytes(StandardCharsets.UTF_8)); + entry(zip, "documentinfo.xml", documentInfo().getBytes(StandardCharsets.UTF_8)); + Bitmap merged = merge(width, height, layers); + entry(zip, "mergedimage.png", png(merged)); + entry(zip, "preview.png", png(merged)); + merged.recycle(); + for (Layer layer : layers) { + String name = "note/layers/layer" + layer.index; + entry(zip, name, tileData(layer.bitmap, width, height)); + entry(zip, name + ".defaultpixel", new byte[] {0, 0, 0, 0}); + } + } + } + + private static String documentXml(int width, int height, ArrayList layers) { + StringBuilder xml = new StringBuilder("\n"); + xml.append("\n\n" + + "\n"); + for (int i = layers.size() - 1; i >= 0; i--) { + Layer layer = layers.get(i); + xml.append("\n"); + } + return xml.append( + "\n") + .toString(); + } + + private static String documentInfo() { + String now = + new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US) { + { + setTimeZone(TimeZone.getTimeZone("UTC")); + } + }.format(new Date()); + return "MoanNotes" + + now + + ""; + } + + private static Bitmap merge(int width, int height, ArrayList layers) { + Bitmap merged = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(merged); + for (Layer layer : layers) if (layer.visible) canvas.drawBitmap(layer.bitmap, 0, 0, null); + return merged; + } + + private static byte[] tileData(Bitmap bitmap, int width, int height) throws IOException { + int cols = (width + TILE - 1) / TILE; + int rows = (height + TILE - 1) / TILE; + ByteArrayOutputStream data = new ByteArrayOutputStream(16 + cols * rows * 32); + data.write((cols * rows + "\n").getBytes(StandardCharsets.US_ASCII)); + int[] pixels = new int[TILE * TILE]; + byte[] rgba = new byte[TILE * TILE * 4]; + for (int y = 0; y < rows; y++) + for (int x = 0; x < cols; x++) { + for (int n = 0; n < pixels.length; n++) pixels[n] = Color.TRANSPARENT; + int copyW = Math.min(TILE, Math.max(0, bitmap.getWidth() - x * TILE)); + int copyH = Math.min(TILE, Math.max(0, bitmap.getHeight() - y * TILE)); + if (copyW > 0 && copyH > 0) + bitmap.getPixels(pixels, 0, TILE, x * TILE, y * TILE, copyW, copyH); + for (int p = 0, offset = 0; p < pixels.length; p++) { + int color = pixels[p]; + rgba[offset++] = (byte) Color.red(color); + rgba[offset++] = (byte) Color.green(color); + rgba[offset++] = (byte) Color.blue(color); + rgba[offset++] = (byte) Color.alpha(color); + } + data.write((x * TILE + "," + y * TILE + ",64,64\n").getBytes(StandardCharsets.US_ASCII)); + data.write(rgba); + } + return data.toByteArray(); + } + + private static byte[] png(Bitmap bitmap) throws IOException { + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + if (!bitmap.compress(Bitmap.CompressFormat.PNG, 100, bytes)) + throw new IOException("PNG encoding failed"); + return bytes.toByteArray(); + } + + private static void entry(ZipOutputStream zip, String name, byte[] bytes) throws IOException { + zip.putNextEntry(new ZipEntry(name)); + zip.write(bytes); + zip.closeEntry(); + } + + private static Object field(Object object, String name) throws Exception { + Field f = object.getClass().getField(name); + return f.get(object); + } + + private static int intField(Object object, String name) throws Exception { + return ((Integer) field(object, name)).intValue(); + } + + private static final class Layer { + final int index; + final Bitmap bitmap; + final boolean visible; + final int opacity; + final String blend; + + Layer(int i, Bitmap b, boolean v, int o, String mode) { + index = i; + bitmap = b; + visible = v; + opacity = o; + blend = mode; + } + } +} diff --git a/moannotes-native/src/main/java/rip/crit/ms/moannotes/nativebridge/LayerPanel.java b/moannotes-native/src/main/java/rip/crit/ms/moannotes/nativebridge/LayerPanel.java new file mode 100644 index 0000000..6985317 --- /dev/null +++ b/moannotes-native/src/main/java/rip/crit/ms/moannotes/nativebridge/LayerPanel.java @@ -0,0 +1,188 @@ +package rip.crit.ms.moannotes.nativebridge; + +import android.app.Activity; +import android.graphics.Color; +import android.graphics.drawable.GradientDrawable; +import android.view.Gravity; +import android.view.View; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.LinearLayout; +import android.widget.PopupWindow; +import android.widget.ScrollView; +import android.widget.SeekBar; +import android.widget.Spinner; +import android.widget.TextView; +import java.lang.reflect.Field; +import java.util.ArrayList; + +public final class LayerPanel { + private LayerPanel() {} + + public static void show(Activity activity) { + try { + Object canvas = NativeFeatureHooks.findCanvas(activity); + if (canvas == null) return; + Object page = publicField(canvas, "mPageConfigData"); + int pageId = ((Integer) publicField(page, "mEditPage")).intValue(); + Class layerClass = Class.forName("com.moan.notes.hand.data.config.LayerConfigData"); + Object config = + layerClass + .getMethod( + "sLoadLayerConfig", + android.content.Context.class, + page.getClass(), + int.class, + layerClass) + .invoke(null, activity, page, pageId, null); + if (config == null) return; + popup(activity, canvas, config, layerClass); + } catch (Exception ignored) { + } + } + + private static void popup(Activity activity, Object canvas, Object config, Class layerClass) + throws Exception { + LinearLayout list = new LinearLayout(activity); + list.setOrientation(LinearLayout.VERTICAL); + list.setPadding(dp(activity, 16), dp(activity, 16), dp(activity, 16), dp(activity, 16)); + list.setBackgroundColor(Color.WHITE); + TextView title = new TextView(activity); + title.setText("Layers"); + title.setTextColor(Color.BLACK); + title.setTextSize(20); + list.addView(title); + @SuppressWarnings("unchecked") + ArrayList visible = (ArrayList) publicField(config, "mEditLayerVisible"); + String parent = (String) publicField(config, "mParentPath"); + for (int index = visible.size() - 1; index >= 0; index--) { + final int layer = index; + LinearLayout row = new LinearLayout(activity); + row.setGravity(Gravity.CENTER_VERTICAL); + Button eye = button(activity, visible.get(index) != 0 ? "Hide" : "Show"); + eye.setOnClickListener( + v -> { + try { + visible.set(layer, visible.get(layer) == 0 ? 1 : 0); + save(activity, config, layerClass); + refresh(canvas); + show(activity); + } catch (Exception ignored) { + } + }); + TextView name = new TextView(activity); + name.setText("Layer " + (index + 1)); + name.setTextColor(Color.BLACK); + name.setTextSize(16); + name.setPadding(dp(activity, 12), 0, dp(activity, 12), 0); + Button remove = button(activity, "Remove"); + remove.setEnabled(visible.size() > 1); + remove.setOnClickListener( + v -> { + try { + layerClass + .getMethod( + "sDeleteLayerFiles", android.content.Context.class, layerClass, int.class) + .invoke(null, activity, config, layer); + refresh(canvas); + show(activity); + } catch (Exception ignored) { + } + }); + row.addView(eye); + row.addView(name, new LinearLayout.LayoutParams(0, -2, 1)); + row.addView(remove); + list.addView(row); + SeekBar opacity = new SeekBar(activity); + opacity.setMax(255); + opacity.setProgress(LayerSettings.opacity(activity, parent, layer)); + opacity.setContentDescription("Layer opacity"); + opacity.setOnSeekBarChangeListener( + new SeekBar.OnSeekBarChangeListener() { + public void onProgressChanged(SeekBar bar, int value, boolean user) { + if (user) LayerSettings.opacity(activity, parent, layer, value); + } + + public void onStartTrackingTouch(SeekBar bar) {} + + public void onStopTrackingTouch(SeekBar bar) {} + }); + list.addView(opacity); + Spinner blend = new Spinner(activity); + String[] modes = {"normal", "multiply", "screen", "overlay", "darken", "lighten"}; + blend.setAdapter( + new ArrayAdapter<>(activity, android.R.layout.simple_spinner_dropdown_item, modes)); + String current = LayerSettings.blend(activity, parent, layer); + for (int mode = 0; mode < modes.length; mode++) + if (modes[mode].equals(current)) blend.setSelection(mode); + blend.setOnItemSelectedListener( + new android.widget.AdapterView.OnItemSelectedListener() { + public void onItemSelected( + android.widget.AdapterView p, View v, int position, long itemId) { + LayerSettings.blend(activity, parent, layer, modes[position]); + } + + public void onNothingSelected(android.widget.AdapterView p) {} + }); + list.addView(blend); + } + Button add = button(activity, "Add layer"); + add.setOnClickListener( + v -> { + try { + int count = ((ArrayList) publicField(config, "mLayerDataFolders")).size(); + layerClass + .getMethod("sAddLayerFiles", android.content.Context.class, layerClass, int.class) + .invoke(null, activity, config, count); + refresh(canvas); + show(activity); + } catch (Exception ignored) { + } + }); + list.addView(add); + ScrollView scroll = new ScrollView(activity); + scroll.addView(list); + PopupWindow window = new PopupWindow(scroll, dp(activity, 300), -2, true); + window.setBackgroundDrawable(surface()); + window.setElevation(dp(activity, 8)); + window.showAtLocation( + activity.getWindow().getDecorView(), + Gravity.RIGHT | Gravity.TOP, + dp(activity, 12), + dp(activity, 64)); + } + + private static void save(Activity activity, Object config, Class layerClass) throws Exception { + layerClass + .getMethod("sSaveLayerConfigData", android.content.Context.class, layerClass) + .invoke(null, activity, config); + } + + private static void refresh(Object canvas) throws Exception { + canvas.getClass().getMethod("refreshUILayer").invoke(canvas); + } + + private static Object publicField(Object o, String name) throws Exception { + Field f = o.getClass().getField(name); + return f.get(o); + } + + private static Button button(Activity a, String label) { + Button b = new Button(a); + b.setText(label); + b.setTextColor(Color.BLACK); + b.setAllCaps(false); + return b; + } + + private static int dp(Activity a, int value) { + return Math.round(value * a.getResources().getDisplayMetrics().density); + } + + private static GradientDrawable surface() { + GradientDrawable g = new GradientDrawable(); + g.setColor(Color.WHITE); + g.setCornerRadius(24); + return g; + } +} diff --git a/moannotes-native/src/main/java/rip/crit/ms/moannotes/nativebridge/LayerSettings.java b/moannotes-native/src/main/java/rip/crit/ms/moannotes/nativebridge/LayerSettings.java new file mode 100644 index 0000000..e8cca6e --- /dev/null +++ b/moannotes-native/src/main/java/rip/crit/ms/moannotes/nativebridge/LayerSettings.java @@ -0,0 +1,37 @@ +package rip.crit.ms.moannotes.nativebridge; + +import android.content.Context; + +final class LayerSettings { + private static final String STORE = "moannotes_layer_settings"; + + private LayerSettings() {} + + static int opacity(Context context, String parent, int layer) { + return context.getSharedPreferences(STORE, 0).getInt(key(parent, layer, "opacity"), 255); + } + + static String blend(Context context, String parent, int layer) { + return context.getSharedPreferences(STORE, 0).getString(key(parent, layer, "blend"), "normal"); + } + + static void opacity(Context context, String parent, int layer, int value) { + context + .getSharedPreferences(STORE, 0) + .edit() + .putInt(key(parent, layer, "opacity"), Math.max(0, Math.min(255, value))) + .apply(); + } + + static void blend(Context context, String parent, int layer, String value) { + context + .getSharedPreferences(STORE, 0) + .edit() + .putString(key(parent, layer, "blend"), value) + .apply(); + } + + private static String key(String parent, int layer, String suffix) { + return parent + "#" + layer + "#" + suffix; + } +} diff --git a/moannotes-native/src/main/java/rip/crit/ms/moannotes/nativebridge/NativeFeatureHooks.java b/moannotes-native/src/main/java/rip/crit/ms/moannotes/nativebridge/NativeFeatureHooks.java new file mode 100644 index 0000000..f53ef13 --- /dev/null +++ b/moannotes-native/src/main/java/rip/crit/ms/moannotes/nativebridge/NativeFeatureHooks.java @@ -0,0 +1,72 @@ +package rip.crit.ms.moannotes.nativebridge; + +import android.app.Activity; +import android.graphics.Color; +import android.view.View; +import android.widget.ImageButton; +import android.widget.LinearLayout; + +public final class NativeFeatureHooks { + private NativeFeatureHooks() {} + + public static void install(Activity activity) { + LinearLayout bar = findBar(activity); + if (bar == null || activity.findViewById(id(activity, "moannotes_kra_export_button")) != null) + return; + add( + activity, + bar, + "moannotes_layers_button", + "icp_layers", + "Layers", + v -> LayerPanel.show(activity)); + add( + activity, + bar, + "moannotes_kra_export_button", + "icp_kra_export", + "Export KRA", + v -> { + Object canvas = findCanvas(activity); + if (canvas != null) KraExporter.exportCurrentPage(activity, canvas); + }); + } + + static Object findCanvas(Activity activity) { + try { + return activity.getClass().getField("g").get(activity); + } catch (Exception ignored) { + return null; + } + } + + private static LinearLayout findBar(Activity activity) { + View view = activity.findViewById(id(activity, "edit_button_bar")); + return view instanceof LinearLayout ? (LinearLayout) view : null; + } + + private static void add( + Activity a, + LinearLayout bar, + String idName, + String drawable, + String description, + View.OnClickListener action) { + ImageButton button = new ImageButton(a); + button.setId(id(a, idName)); + button.setContentDescription(description); + button.setBackgroundColor(Color.TRANSPARENT); + button.setImageResource(id(a, drawable)); + int size = Math.round(48 * a.getResources().getDisplayMetrics().density); + button.setLayoutParams(new LinearLayout.LayoutParams(size, -1)); + button.setOnClickListener(action); + bar.addView(button); + } + + static int id(Activity activity, String name) { + return activity + .getResources() + .getIdentifier( + name, name.startsWith("icp_") ? "drawable" : "id", activity.getPackageName()); + } +} diff --git a/moannotes/FEATURE_CHECKLIST.md b/moannotes/FEATURE_CHECKLIST.md new file mode 100644 index 0000000..963dd56 --- /dev/null +++ b/moannotes/FEATURE_CHECKLIST.md @@ -0,0 +1,32 @@ +# MoanNotes feature checklist + +This list is the acceptance gate for the Smali-patched MoanNotes build. A box is checked only after it is exercised on the Xiaomi device without a full-panel side effect. + +## Core writing + +- [ ] Pen, pencil, marker, highlighter, and eraser retain strokes after release and reopen. +- [ ] Brush width, opacity, pressure response, and configurable stabilization are saved per tool. +- [ ] Shape assist can be enabled or disabled and does not alter ordinary freehand strokes. +- [ ] Undo and redo retain page and layer boundaries. +- [ ] Partial refresh stays confined to the changed region and safely releases on exit. + +## Document structure + +- [ ] Notes support multiple pages and a selectable paper or reference background, including the bundled monochrome college-ruled sheet. +- [ ] Layers can be created, renamed, reordered, hidden, locked, and assigned independent opacity. +- [ ] Blend modes expose Normal, Multiply, Screen, and Overlay where the native renderer supports them. +- [ ] The monochromatic selector offers white, black, and named greys with a persistent default. +- [ ] Handwriting mode can persistently snap a stylus stroke to its nearest ruled baseline without changing its internal letter shape. +- [ ] PDF and image import remain scrollable beneath handwriting. + +## Interchange + +- [ ] Export provides PDF, PNG, and `.kra` choices before writing a file. +- [ ] `.kra` preserves paint layers, visibility, opacity, stroke appearance, and supported blend modes. +- [ ] Export failure leaves the original note untouched and reports a specific error. + +## Patch quality + +- [ ] IconPark pen, paper, and export glyphs render at 24 dp with readable contrast. +- [ ] Touch targets remain at least 44 dp without hiding drawing tools in an overflow menu. +- [ ] The APK is rebuilt from the original input and installed with `reinstall:moannotes`. diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..6e6837e --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1277 @@ +{ + "name": "mistring", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "mistring", + "hasInstallScript": true, + "dependencies": { + "apk_unpack": "^1.2.1", + "apk-parser": "^0.1.7", + "java-bridge": "^2.8.1", + "patch-package": "^8.0.1" + }, + "devDependencies": { + "@types/bun": "latest" + }, + "peerDependencies": { + "typescript": "^7" + } + }, + "node_modules/@types/bun": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@types/bun/-/bun-1.4.3.tgz", + "integrity": "sha512-N67Pqy8JXbAY/j0tNraS3V5mubGvc6rrrNDmDCtZLlFzccbUJPDb0tvgUBC5q4m8ybkP93Jcn1QB+RYQ6PvBhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bun-types": "1.4.3" + } + }, + "node_modules/@types/node": { + "version": "26.6.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.6.5.tgz", + "integrity": "sha512-uMzsv9stDdofIZBx4UGh4Z9ZgXnGC9seRDscilBcTHAeOFk67MZg/k9bWVfO+bk4qZmG+l52hRnLwUiH2LnJTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~8.9.0" + } + }, + "node_modules/@types/node/node_modules/undici-types": { + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.9.0.tgz", + "integrity": "sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript/typescript-linux-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-x64/-/typescript-linux-x64-7.0.2.tgz", + "integrity": "sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "license": "BSD-2-Clause" + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/apk_unpack": { + "version": "1.2.1", + "license": "Apache-2.0", + "dependencies": { + "cheerio": "^0.22.0", + "java": "^0.8.0", + "line-reader": "^0.4.0", + "yauzl": "^2.7.0" + }, + "bin": { + "apk_unpack": "cli" + } + }, + "node_modules/apk-parser": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/apk-parser/-/apk-parser-0.1.7.tgz", + "integrity": "sha512-1ZbtTKD3RxdMfuCYe8qa3BVivH45S4N29q7/OERLElW7ENecI33YzBislNvBnZy2yBThtVx2Mf68j8/gvbmXuw==", + "hasInstallScript": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/async": { + "version": "2.0.1", + "license": "MIT", + "dependencies": { + "lodash": "^4.8.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "license": "ISC" + }, + "node_modules/brace-expansion": { + "version": "1.1.21", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/bun-types": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/bun-types/-/bun-types-1.4.3.tgz", + "integrity": "sha512-tinRJNGOmUN+tEAsn2y2e942n9JHRHR42iUYzDH75NmhJqVBokGSQkkfSFdNWwsANIdrK6ACH9t01M452YyTwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "undici-types": "*" + } + }, + "node_modules/call-bind": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz", + "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "get-intrinsic": "^1.3.0", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/cheerio": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz", + "integrity": "sha512-8/MzidM6G/TgRelkzDG13y3Y9LxBjCb+8yOEZ9+wwq5gVF2w2pV0wmHvjfT0RvuxGyR7UEuK36r+yYMbT4uKgA==", + "license": "MIT", + "dependencies": { + "css-select": "~1.2.0", + "dom-serializer": "~0.1.0", + "entities": "~1.1.1", + "htmlparser2": "^3.9.1", + "lodash.assignin": "^4.0.9", + "lodash.bind": "^4.1.4", + "lodash.defaults": "^4.0.1", + "lodash.filter": "^4.4.0", + "lodash.flatten": "^4.2.0", + "lodash.foreach": "^4.3.0", + "lodash.map": "^4.4.0", + "lodash.merge": "^4.4.0", + "lodash.pick": "^4.2.1", + "lodash.reduce": "^4.4.0", + "lodash.reject": "^4.4.0", + "lodash.some": "^4.4.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cross-spawn/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cross-spawn/node_modules/which/node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/css-select": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", + "integrity": "sha512-dUQOBoqdR7QwV90WysXPLXG5LO7nhYBgiWVfxF80DKPF8zx1t/pUd2FYy73emg3zrjtM6dzmYgbHKfV2rxiHQA==", + "license": "BSD-like", + "dependencies": { + "boolbase": "~1.0.0", + "css-what": "2.1", + "domutils": "1.5.1", + "nth-check": "~1.0.1" + } + }, + "node_modules/css-what": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", + "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==", + "license": "BSD-2-Clause", + "engines": { + "node": "*" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/dom-serializer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", + "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", + "license": "MIT", + "dependencies": { + "domelementtype": "^1.3.0", + "entities": "^1.1.1" + } + }, + "node_modules/domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", + "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "1" + } + }, + "node_modules/domutils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha512-gSu5Oi/I+3wDENBsOWBiRK1eoGxcywYSqg3rR960/+EfY0CF4EX1VPkgHOZ3WiS/Jg2DtliF6BhWcHlfpYUcGw==", + "dependencies": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", + "license": "BSD-2-Clause" + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "license": "MIT", + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-java-home": { + "version": "0.1.3", + "license": "Apache 2.0", + "dependencies": { + "which": "~1.0.5" + } + }, + "node_modules/find-java-home/node_modules/which": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/which/-/which-1.0.9.tgz", + "integrity": "sha512-E87fdQ/eRJr9W1X4wTPejNy9zTW3FI2vpCZSJ/HAY+TkjKVC0TUm1jk6vn2Z7qay0DQy0+RBGdXxj+RmmiGZKQ==", + "license": "ISC", + "bin": { + "which": "bin/which" + } + }, + "node_modules/find-yarn-workspace-root": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz", + "integrity": "sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==", + "license": "Apache-2.0", + "dependencies": { + "micromatch": "^4.0.2" + } + }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "license": "ISC" + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob": { + "version": "7.1.1", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.2", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/htmlparser2": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", + "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", + "license": "MIT", + "dependencies": { + "domelementtype": "^1.3.1", + "domhandler": "^2.3.0", + "domutils": "^1.5.1", + "entities": "^1.1.1", + "inherits": "^2.0.1", + "readable-stream": "^3.1.1" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "license": "MIT" + }, + "node_modules/java": { + "version": "0.8.0", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "async": "2.0.1", + "find-java-home": "0.1.3", + "glob": "7.1.1", + "lodash": "4.16.4", + "nan": "2.4.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/java-bridge": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/java-bridge/-/java-bridge-2.8.1.tgz", + "integrity": "sha512-5z3c3r4cQaACk53UoLrTTJSm3gLtkz9/xOyd1gSWOcK+E7+qVwnA9hjuPUz7NrhfitavYs/eJX5//9q9Yiu5Pw==", + "license": "MIT", + "engines": { + "node": ">= 15" + }, + "optionalDependencies": { + "java-bridge-darwin-arm64": "2.8.1", + "java-bridge-darwin-x64": "2.8.1", + "java-bridge-linux-arm64-gnu": "2.8.1", + "java-bridge-linux-x64-gnu": "2.8.1", + "java-bridge-linux-x64-musl": "2.8.1", + "java-bridge-win32-ia32-msvc": "2.8.1", + "java-bridge-win32-x64-msvc": "2.8.1" + } + }, + "node_modules/java-bridge-linux-x64-gnu": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/java-bridge-linux-x64-gnu/-/java-bridge-linux-x64-gnu-2.8.1.tgz", + "integrity": "sha512-mbXiFSd3t3usmZXGQFYdiDM9K38DGyG72EMbFtaJ0bIfx7kK6T209G46sqGFnL5BR3KCTauQfFITyRyFjWVN6A==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/java-bridge-linux-x64-musl": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/java-bridge-linux-x64-musl/-/java-bridge-linux-x64-musl-2.8.1.tgz", + "integrity": "sha512-hWdfMe2ndhCa7/40LbjtV14bUcxQd7IluT2XPOTvfhf46+u51QVbDTr2sjoxkPouGRYYtfCazukR7iUGRx1RiA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 15" + } + }, + "node_modules/json-stable-stringify": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.3.0.tgz", + "integrity": "sha512-qtYiSSFlwot9XHtF9bD9c7rwKjr+RecWT//ZnPvSmEjpV5mmPOCN4j8UjY5hbjNkOwZ/jQv3J6R1/pL7RwgMsg==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "isarray": "^2.0.5", + "jsonify": "^0.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz", + "integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==", + "license": "Public Domain", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/klaw-sync": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", + "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.11" + } + }, + "node_modules/line-reader": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/line-reader/-/line-reader-0.4.0.tgz", + "integrity": "sha512-AYJ8g+eE7v+Ba4s/cuYqzuNulH/WbjdKQ55fvx8fNVn8WQzTpioY6vI1MoxTuMgcHYX3VlmZWbVvnkIqkyJbCA==", + "license": "MIT" + }, + "node_modules/lodash": { + "version": "4.16.4", + "license": "MIT" + }, + "node_modules/lodash.assignin": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz", + "integrity": "sha512-yX/rx6d/UTVh7sSVWVSIMjfnz95evAgDFdb1ZozC35I9mSFCkmzptOzevxjgbQUsc78NR44LVHWjsoMQXy9FDg==", + "license": "MIT" + }, + "node_modules/lodash.bind": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/lodash.bind/-/lodash.bind-4.2.1.tgz", + "integrity": "sha512-lxdsn7xxlCymgLYo1gGvVrfHmkjDiyqVv62FAeF2i5ta72BipE1SLxw8hPEPLhD4/247Ijw07UQH7Hq/chT5LA==", + "license": "MIT" + }, + "node_modules/lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", + "license": "MIT" + }, + "node_modules/lodash.filter": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.filter/-/lodash.filter-4.6.0.tgz", + "integrity": "sha512-pXYUy7PR8BCLwX5mgJ/aNtyOvuJTdZAo9EQFUvMIYugqmJxnrYaANvTbgndOzHSCSR0wnlBBfRXJL5SbWxo3FQ==", + "license": "MIT" + }, + "node_modules/lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", + "license": "MIT" + }, + "node_modules/lodash.foreach": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz", + "integrity": "sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ==", + "license": "MIT" + }, + "node_modules/lodash.map": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz", + "integrity": "sha512-worNHGKLDetmcEYDvh2stPCrrQRkP20E4l0iIS7F8EvzMqBBi7ltvFN5m1HvTf1P7Jk1txKhvFcmYsCr8O2F1Q==", + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "license": "MIT" + }, + "node_modules/lodash.pick": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", + "integrity": "sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q==", + "license": "MIT" + }, + "node_modules/lodash.reduce": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.reduce/-/lodash.reduce-4.6.0.tgz", + "integrity": "sha512-6raRe2vxCYBhpBu+B+TtNGUzah+hQjVdu3E17wfusjyrXBka2nBS8OH/gjVZ5PvHOhWmIZTYri09Z6n/QfnNMw==", + "license": "MIT" + }, + "node_modules/lodash.reject": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.reject/-/lodash.reject-4.6.0.tgz", + "integrity": "sha512-qkTuvgEzYdyhiJBx42YPzPo71R1aEr0z79kAv7Ixg8wPFEjgRgJdUsGMG3Hf3OYSF/kHI79XhNlt+5Ar6OzwxQ==", + "license": "MIT" + }, + "node_modules/lodash.some": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz", + "integrity": "sha512-j7MJE+TuT51q9ggt4fSgVqro163BEFjAt3u97IqU+JA2DkWl80nFTrowzLpZ/BnpN7rrl0JA/593NAdd8p/scQ==", + "license": "MIT" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.5", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/nan": { + "version": "2.4.0", + "license": "MIT" + }, + "node_modules/nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "~1.0.0" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/once": { + "version": "1.4.0", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/open": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", + "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/patch-package": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/patch-package/-/patch-package-8.0.1.tgz", + "integrity": "sha512-VsKRIA8f5uqHQ7NGhwIna6Bx6D9s/1iXlA1hthBVBEbkq+t4kXD0HHt+rJhf/Z+Ci0F/HCB2hvn0qLdLG+Qxlw==", + "license": "MIT", + "dependencies": { + "@yarnpkg/lockfile": "^1.1.0", + "chalk": "^4.1.2", + "ci-info": "^3.7.0", + "cross-spawn": "^7.0.3", + "find-yarn-workspace-root": "^2.0.0", + "fs-extra": "^10.0.0", + "json-stable-stringify": "^1.0.2", + "klaw-sync": "^6.0.0", + "minimist": "^1.2.6", + "open": "^7.4.2", + "semver": "^7.5.3", + "slash": "^2.0.0", + "tmp": "^0.2.4", + "yaml": "^2.2.2" + }, + "bin": { + "patch-package": "index.js" + }, + "engines": { + "node": ">=14", + "npm": ">5" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "license": "MIT" + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tmp": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.7.tgz", + "integrity": "sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==", + "license": "MIT", + "engines": { + "node": ">=14.14" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/typescript": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz", + "integrity": "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==", + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc" + }, + "engines": { + "node": ">=16.20.0" + }, + "optionalDependencies": { + "@typescript/typescript-aix-ppc64": "7.0.2", + "@typescript/typescript-darwin-arm64": "7.0.2", + "@typescript/typescript-darwin-x64": "7.0.2", + "@typescript/typescript-freebsd-arm64": "7.0.2", + "@typescript/typescript-freebsd-x64": "7.0.2", + "@typescript/typescript-linux-arm": "7.0.2", + "@typescript/typescript-linux-arm64": "7.0.2", + "@typescript/typescript-linux-loong64": "7.0.2", + "@typescript/typescript-linux-mips64el": "7.0.2", + "@typescript/typescript-linux-ppc64": "7.0.2", + "@typescript/typescript-linux-riscv64": "7.0.2", + "@typescript/typescript-linux-s390x": "7.0.2", + "@typescript/typescript-linux-x64": "7.0.2", + "@typescript/typescript-netbsd-arm64": "7.0.2", + "@typescript/typescript-netbsd-x64": "7.0.2", + "@typescript/typescript-openbsd-arm64": "7.0.2", + "@typescript/typescript-openbsd-x64": "7.0.2", + "@typescript/typescript-sunos-x64": "7.0.2", + "@typescript/typescript-win32-arm64": "7.0.2", + "@typescript/typescript-win32-x64": "7.0.2" + } + }, + "node_modules/undici-types": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.12.1.tgz", + "integrity": "sha512-nCiEcIx87oMw9u3Yzj2DuRBzv6p0e7akhy4HUPtpBiVWmAY3o6Phznst8QhmY1oLMttLgJ2tlAvsKuzCgBSoAw==", + "dev": true, + "license": "MIT" + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/wrappy": { + "version": "1.0.2", + "license": "ISC" + }, + "node_modules/yaml": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.1.tgz", + "integrity": "sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..7631031 --- /dev/null +++ b/package.json @@ -0,0 +1,47 @@ +{ + "name": "mistring", + "module": "index.ts", + "type": "module", + "private": true, + "devDependencies": { + "@biomejs/biome": "^2.5.15", + "@types/bun": "latest", + "prettier": "^3.9.10" + }, + "peerDependencies": { + "typescript": "^7" + }, + "dependencies": { + "apk-parser": "^0.1.7", + "apk_unpack": "^1.2.1", + "java-bridge": "^2.8.1", + "patch-package": "^8.0.1", + "toml": "^5.0.1" + }, + "scripts": { + "postinstall": "patch-package", + "pp": "git submodule update --init --recursive && mkdir -p java/ && cp -r apk_unpack/java/* java/ && cp -r apk_unpack/cli . && patch-package apk_unpack", + "format": "./jsfmt.sh && ./jfmt.sh && ./qmlfmt.sh && ./cppfmt.sh && ./rustfmt.sh", + "patch-apks": "bun run index.ts", + "extract-eink": "bun run extractors/eink.ts", + "kr": "bun run scripts/krita-patch.ts", + "kr:generate": "bun run scripts/krita-patch.ts --generate", + "krita:sync": "bun run scripts/krita-unified-build.ts sync", + "krita:bootstrap": "bun run scripts/krita-unified-build.ts bootstrap", + "krita:deps": "bun run scripts/krita-unified-build.ts deps", + "krita:build": "bun run scripts/krita-unified-build.ts build", + "krita:build:release": "bun run scripts/krita-unified-build.ts release", + "build:moannotes-native": "GRADLE_USER_HOME=$PWD/.gradle-user /var/home/hellings/.sdkman/candidates/gradle/9.7.1/bin/gradle :moannotes-native:smaliRelease --no-daemon --no-configuration-cache", + "sign:moannotes": "bun run scripts/sign-moannotes.ts", + "patch:moannotes": "bun run build:moannotes-native && bun run patch-apks MoanNote && bun run sign:moannotes", + "sign:moanlauncher": "bun run scripts/sign-moannotes.ts MoanLauncher", + "patch:moanlauncher": "bun run patch-apks MoanLauncher && bun run sign:moanlauncher", + "reinstall:moannotes": "bun run scripts/reinstall-moannotes.ts", + "adbme": "bun run scripts/adbme.ts", + "translator:test": "python3 -m unittest discover -s translator -p 'test_*.py'" + }, + "trustedDependencies": [ + "apk-parser", + "java" + ] +} diff --git a/patches/apk_unpack+1.2.1.patch b/patches/apk_unpack+1.2.1.patch new file mode 100644 index 0000000..443fbdd --- /dev/null +++ b/patches/apk_unpack+1.2.1.patch @@ -0,0 +1,274 @@ +diff --git a/node_modules/apk_unpack/apk_unpack.js b/node_modules/apk_unpack/apk_unpack.js +index e05cc3f..8cb2ed4 100644 +--- a/node_modules/apk_unpack/apk_unpack.js ++++ b/node_modules/apk_unpack/apk_unpack.js +@@ -1,132 +1,83 @@ +-// APK Asset unpack - uses apktool. +-// helper for cli.js +-var fs = require('fs'), +- lineReader = require('line-reader'), +- java = require('java'), +- path = require('path'), +- _last = { dir:'' }, +- cwd = process.cwd(), +- _config = { +- apk : '', +- java : true, +- dir : '' +- }; +- +-// capture console out +-/*var access = fs.createWriteStream(cwd + path.sep + 'apk_unpack.log'); +-process.stdout.write = process.stderr.write = access.write.bind(access);*/ +- +-// add classes for JADX and apktool +-java.classpath.pushDir(__dirname+path.sep+'java/jadx/'); +-java.classpath.pushDir(__dirname+path.sep+'java/'); +-java.options.push('-Xrs'); // reduce signal os signals +-// +- +-var classes = { +- ApkDecoder : java.import('brut.androlib.ApkDecoder'), +- libResources : java.import('brut.androlib.res.AndrolibResources'), +- ExtFile : java.import('brut.directory.ExtFile'), +- File : java.import('java.io.File'), +- //jadx +- _jadx : java.import('jadx.api.JadxDecompiler'), +- _jadx_args : java.import('jadx.cli.JadxCLIArgs'), +- _javalog : java.import('java.util.logging.LogManager'), +- _jadx_javaclass : java.import('jadx.api.JavaClass'), +- _jadx_classnode : java.import('jadx.core.dex.nodes.ClassNode'), ++const fs = require('fs'); ++const path = require('path'); ++const { execSync } = require('child_process'); ++const yauzl = require('yauzl'); ++const cheerio = require('cheerio'); ++ ++const cwd = process.cwd(); ++const _config = { ++ apk: '', ++ dir: '' + }; ++const _last = { dir: '' }; ++ ++ ++const APKTOOL_JAR = path.join(__dirname, 'java', 'apktool_2.4.1.jar'); ++const JADX_CLI_JAR = path.join(__dirname, 'java', 'jadx', 'jadx-cli.jar'); + +-var init = function(config) { ++var init = function (config) { + for (var i in config) { + _config[i] = config[i]; + } +- // prepare apk and outputdir location +- var _apk = _config.apk, _outd = _config.dir; +- if (_config.apk.charAt(0)!=path.sep && _config.apk.charAt(0)!='~') { +- _config.full_apk = path.join(cwd,_config.apk); ++ if (_config.apk.charAt(0) !== path.sep && _config.apk.charAt(0) !== '~') { ++ _config.full_apk = path.join(cwd, _config.apk); + } +- if (_config.dir.charAt(_config.dir.length-1)!=path.sep) { +- // if outputdir doesn't end in / or path separator, add it. +- _config.full_dir = _config.dir+''+path.sep; ++ if (_config.dir.charAt(_config.dir.length - 1) !== path.sep) { ++ _config.full_dir = _config.dir + '' + path.sep; + } +- // turn standard java logger off +- classes._javalog.getLogManagerSync().resetSync(); + }; + +-var extractAPK = function(cb) { ++var extractAPK = function (cb) { + if (fileExists(_config.apk)) { + _last.dir = _config.full_dir; +- var decoder = new classes.ApkDecoder(); +- var _apkfile = new classes.File(_config.full_apk); +- decoder.setForceDeleteSync(true); +- decoder.setDecodeResourcesSync(java.newShort(256)); // exclude resources +- decoder.setOutDirSync(new classes.File(_config.full_dir)); +- decoder.setApkFileSync(_apkfile); +- decoder.decodeSync(); +- // try to decrypt manifest +- // get Resources Table +- var _res = decoder.getResTableSync(); +- var _ext = new classes.ExtFile(_apkfile); +- var _lib = new classes.libResources(); +- _lib.decodeManifest(_res, _ext, new classes.File(_config.full_dir), function() { ++ ++ ++ ++ ++ try { ++ const cmd = `java -jar "${APKTOOL_JAR}" d -f -o "${_config.full_dir}" "${_config.full_apk}"`; ++ execSync(cmd, { stdio: 'inherit' }); + cb(true); +- }); ++ } catch (err) { ++ console.error('Apktool extraction failed:', err); ++ cb(false); ++ } + } else { + cb(false); + } + }; + +-var decompile = function(onReady) { +- // extract classes.dex into output +- extract_dex(function() { +- // decrypt dex into src, using jadx +- var _dir = new classes.File(_last.dir + 'src' + path.sep); +- var _dex = new classes.File(_last.dir + 'classes.dex'); +- var _dexs = java.newInstanceSync("java.util.ArrayList"); +- _dexs.addSync(_dex); +- var _args = new classes._jadx_args(); +- _args.setOutputDir(_dir); +- var jadx = new classes._jadx(_args); +- jadx.setOutputDir(_dir); +- //get sources manually, to avoid threads +- /*jadx.loadFiles(_dexs, function() { +- console.log('requesting classes:'); +- var _j_classes = jadx.getClassesSync(); +- console.log('got classes:',_j_classes); +- for (var _o in _j_classes) { +- //var _cl_node = new classes._jadx_classnode(); +- var cls = new classes._jadx_javaclass(_j_classes[_o], jadx); +- console.log(cls); +- //.decompile(function(){ +- // console.log('decompiling class:'+_o); +- //}); +- } +- });*/ +- /**/ +- jadx.loadFiles(_dexs, function() { +- jadx.save(function() { +- onReady(); +- }); +- });/**/ ++var decompile = function (onReady) { ++ extract_dex(function () { ++ var srcDir = path.join(_last.dir, 'src'); ++ var dexFile = path.join(_last.dir, 'classes.dex'); ++ ++ ++ ++ try { ++ const cmd = `java -jar "${JADX_CLI_JAR}" -d "${srcDir}" "${dexFile}"`; ++ execSync(cmd, { stdio: 'inherit' }); ++ onReady(); ++ } catch (err) { ++ console.error('JADX decompilation failed:', err); ++ onReady(); ++ } + }); + }; + +-var extract_dex = function(onReady) { +- // extract classes.dex from apk into outputdir. +- var yauzl = require('yauzl'); +- yauzl.open(_config.apk, { lazyEntries: false }, function(err,zipfile) { ++var extract_dex = function (onReady) { ++ yauzl.open(_config.apk, { lazyEntries: false }, function (err, zipfile) { + if (err) throw err; +- // zipfile.readEntry(); +- zipfile.on('entry', function(entry) { ++ zipfile.on('entry', function (entry) { + if (!/\/$/.test(entry.fileName)) { +- // file +- zipfile.openReadStream(entry, function(err2, readStream) { +- //if (err2) throw err2; +- if (entry.fileName=='classes.dex') { +- readStream.pipe(fs.createWriteStream(_last.dir + entry.fileName)); ++ zipfile.openReadStream(entry, function (err2, readStream) { ++ if (entry.fileName === 'classes.dex') { ++ const writeStream = fs.createWriteStream(path.join(_last.dir, entry.fileName)); ++ readStream.pipe(writeStream); + zipfile.close(); +- setTimeout(function(){ +- onReady(); +- }, 350); // delay for zip to release lock on dex ++ writeStream.on('finish', function () { ++ setTimeout(onReady, 350); ++ }); + } + }); + } +@@ -134,51 +85,42 @@ var extract_dex = function(onReady) { + }); + }; + +-var info = function(callback) { +- // to be called after 'extractAPK', gets info about APK from decoded AndroidManifest.xml +- var cheerio = require('cheerio'); +- var reply = {}; +- var _manifest = _last.dir + 'AndroidManifest.xml'; ++var info = function (callback) { ++ var _manifest = path.join(_last.dir, 'AndroidManifest.xml'); + if (fileExists(_manifest)) { +- fs.readFile(_manifest, function(err,_data) { +- if (err) callback(true,{}); +- var $ = cheerio.load(_data, { xmlMode:true }); +- reply['package'] = $('manifest[package]').attr('package'); +- reply['versionCode'] = $('manifest').attr('android\:versionCode'); +- reply['versionName'] = $('manifest').attr('android\:versionName'); +- reply['appName'] = $('manifest application').attr('android\:label'); +- reply['_dir'] = _last.dir; ++ fs.readFile(_manifest, function (err, _data) { ++ if (err) return callback(true, {}); ++ var $ = cheerio.load(_data, { xmlMode: true }); ++ var reply = { ++ 'package': $('manifest[package]').attr('package'), ++ 'versionCode': $('manifest').attr('android:versionCode'), ++ 'versionName': $('manifest').attr('android:versionName'), ++ 'appName': $('manifest application').attr('android:label'), ++ '_dir': _last.dir ++ }; + callback(false, reply); + }); + } else { + console.log('apk_unpack -> run \'extract\' method before \'info\'.'); +- callback(true, {}) ++ callback(true, {}); ++ } ++}; ++ ++var fileExists = function (filePath) { ++ try { ++ return fs.statSync(filePath).isFile(); ++ } catch (err) { ++ return false; + } + }; + +-var fileExists = function(filePath) +-{ +- try +- { +- return fs.statSync(filePath).isFile(); +- } +- catch (err) +- { +- return false; +- } +-} +- +-var dirExists = function(filePath) +-{ +- try +- { +- return fs.statSync(filePath).isDirectory(); +- } +- catch (err) +- { +- return false; +- } +-} ++var dirExists = function (filePath) { ++ try { ++ return fs.statSync(filePath).isDirectory(); ++ } catch (err) { ++ return false; ++ } ++}; + + exports.init = init; + exports.extract = extractAPK; diff --git a/patches/moanlauncher/res/layout/activity_main.xml b/patches/moanlauncher/res/layout/activity_main.xml new file mode 100644 index 0000000..e2e134d --- /dev/null +++ b/patches/moanlauncher/res/layout/activity_main.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/patches/moanlauncher/res/layout/home_card_app.xml b/patches/moanlauncher/res/layout/home_card_app.xml new file mode 100644 index 0000000..93a18e9 --- /dev/null +++ b/patches/moanlauncher/res/layout/home_card_app.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/patches/moanlauncher/res/layout/home_card_app_item.xml b/patches/moanlauncher/res/layout/home_card_app_item.xml new file mode 100644 index 0000000..6708b54 --- /dev/null +++ b/patches/moanlauncher/res/layout/home_card_app_item.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/patches/moanlauncher/res/layout/item_apps.xml b/patches/moanlauncher/res/layout/item_apps.xml new file mode 100644 index 0000000..daa4b1a --- /dev/null +++ b/patches/moanlauncher/res/layout/item_apps.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/patches/moanlauncher/smali/rip/crit/ms/launcher/XiaomiProfile.smali b/patches/moanlauncher/smali/rip/crit/ms/launcher/XiaomiProfile.smali new file mode 100644 index 0000000..e3dd859 --- /dev/null +++ b/patches/moanlauncher/smali/rip/crit/ms/launcher/XiaomiProfile.smali @@ -0,0 +1,36 @@ +.class public final Lrip/crit/ms/launcher/XiaomiProfile; +.super Ljava/lang/Object; + +.method public static capture(Landroid/content/Context;)V + .locals 4 + + const-string v0, "xiaomi_profile" + const/4 v1, 0x0 + invoke-virtual {p0, v0, v1}, Landroid/content/Context;->getSharedPreferences(Ljava/lang/String;I)Landroid/content/SharedPreferences; + move-result-object v0 + invoke-interface {v0}, Landroid/content/SharedPreferences;->edit()Landroid/content/SharedPreferences$Editor; + move-result-object v0 + + const-string v1, "manufacturer" + sget-object v2, Landroid/os/Build;->MANUFACTURER:Ljava/lang/String; + invoke-interface {v0, v1, v2}, Landroid/content/SharedPreferences$Editor;->putString(Ljava/lang/String;Ljava/lang/String;)Landroid/content/SharedPreferences$Editor; + move-result-object v0 + const-string v1, "model" + sget-object v2, Landroid/os/Build;->MODEL:Ljava/lang/String; + invoke-interface {v0, v1, v2}, Landroid/content/SharedPreferences$Editor;->putString(Ljava/lang/String;Ljava/lang/String;)Landroid/content/SharedPreferences$Editor; + move-result-object v0 + const-string v1, "device" + sget-object v2, Landroid/os/Build;->DEVICE:Ljava/lang/String; + invoke-interface {v0, v1, v2}, Landroid/content/SharedPreferences$Editor;->putString(Ljava/lang/String;Ljava/lang/String;)Landroid/content/SharedPreferences$Editor; + move-result-object v0 + const-string v1, "product" + sget-object v2, Landroid/os/Build;->PRODUCT:Ljava/lang/String; + invoke-interface {v0, v1, v2}, Landroid/content/SharedPreferences$Editor;->putString(Ljava/lang/String;Ljava/lang/String;)Landroid/content/SharedPreferences$Editor; + move-result-object v0 + const-string v1, "build" + sget-object v2, Landroid/os/Build$VERSION;->INCREMENTAL:Ljava/lang/String; + invoke-interface {v0, v1, v2}, Landroid/content/SharedPreferences$Editor;->putString(Ljava/lang/String;Ljava/lang/String;)Landroid/content/SharedPreferences$Editor; + move-result-object v0 + invoke-interface {v0}, Landroid/content/SharedPreferences$Editor;->apply()V + return-void +.end method diff --git a/patches/moannotes/assets/background/template_college_ruled.png b/patches/moannotes/assets/background/template_college_ruled.png new file mode 100644 index 0000000..58e895a Binary files /dev/null and b/patches/moannotes/assets/background/template_college_ruled.png differ diff --git a/patches/moannotes/res/drawable-nodpi/template_college_ruled.png b/patches/moannotes/res/drawable-nodpi/template_college_ruled.png new file mode 100644 index 0000000..58e895a Binary files /dev/null and b/patches/moannotes/res/drawable-nodpi/template_college_ruled.png differ diff --git a/patches/moannotes/res/drawable/icp_export.xml b/patches/moannotes/res/drawable/icp_export.xml new file mode 100644 index 0000000..a1e1a9b --- /dev/null +++ b/patches/moannotes/res/drawable/icp_export.xml @@ -0,0 +1,3 @@ + + + diff --git a/patches/moannotes/res/drawable/icp_kra_export.xml b/patches/moannotes/res/drawable/icp_kra_export.xml new file mode 100644 index 0000000..01b1b7f --- /dev/null +++ b/patches/moannotes/res/drawable/icp_kra_export.xml @@ -0,0 +1 @@ + diff --git a/patches/moannotes/res/drawable/icp_layers.xml b/patches/moannotes/res/drawable/icp_layers.xml new file mode 100644 index 0000000..14e18b8 --- /dev/null +++ b/patches/moannotes/res/drawable/icp_layers.xml @@ -0,0 +1 @@ + diff --git a/patches/moannotes/res/drawable/icp_palette.xml b/patches/moannotes/res/drawable/icp_palette.xml new file mode 100644 index 0000000..a536aac --- /dev/null +++ b/patches/moannotes/res/drawable/icp_palette.xml @@ -0,0 +1,3 @@ + + + diff --git a/patches/moannotes/res/drawable/icp_pen.xml b/patches/moannotes/res/drawable/icp_pen.xml new file mode 100644 index 0000000..e3465a6 --- /dev/null +++ b/patches/moannotes/res/drawable/icp_pen.xml @@ -0,0 +1,3 @@ + + + diff --git a/patches/moannotes/res/drawable/icp_snap_line.xml b/patches/moannotes/res/drawable/icp_snap_line.xml new file mode 100644 index 0000000..d25fc81 --- /dev/null +++ b/patches/moannotes/res/drawable/icp_snap_line.xml @@ -0,0 +1,7 @@ + + + diff --git a/patches/moannotes/res/values/moannotes_patch_ids.xml b/patches/moannotes/res/values/moannotes_patch_ids.xml new file mode 100644 index 0000000..ccd18e5 --- /dev/null +++ b/patches/moannotes/res/values/moannotes_patch_ids.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/patches/moannotes/smali/rip/crit/ms/moannotes/BackgroundCatalogPatch.smali b/patches/moannotes/smali/rip/crit/ms/moannotes/BackgroundCatalogPatch.smali new file mode 100644 index 0000000..af6ec2e --- /dev/null +++ b/patches/moannotes/smali/rip/crit/ms/moannotes/BackgroundCatalogPatch.smali @@ -0,0 +1,69 @@ +.class public final Lrip/crit/ms/moannotes/BackgroundCatalogPatch; +.super Ljava/lang/Object; + +.method public static appendCollegeRuled(Ljava/util/ArrayList;)V + .locals 4 + + new-instance v0, Lh/f/b/m5/l; + + invoke-direct {v0}, Lh/f/b/m5/l;->()V + + const-string v1, "background" + + invoke-static {v1}, Lh/a/a/a/a;->m(Ljava/lang/String;)Ljava/lang/StringBuilder; + + move-result-object v1 + + sget-object v2, Ljava/io/File;->separator:Ljava/lang/String; + + const-string v3, "template_college_ruled.png" + + invoke-static {v1, v2, v3}, Lh/a/a/a/a;->j(Ljava/lang/StringBuilder;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; + + move-result-object v1 + + iput-object v1, v0, Lh/f/b/m5/l;->b:Ljava/lang/String; + + const/4 v1, 0x0 + + iput v1, v0, Lh/f/b/m5/l;->c:I + + const-string v1, "College ruled" + + iput-object v1, v0, Lh/f/b/m5/l;->d:Ljava/lang/String; + + invoke-virtual {p0, v0}, Ljava/util/ArrayList;->add(Ljava/lang/Object;)Z + + return-void +.end method + +.method public static previewResource(Landroid/content/Context;Ljava/lang/String;I)I + .locals 4 + + const-string v0, "College ruled" + + invoke-virtual {v0, p1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z + + move-result v0 + + if-eqz v0, :cond_0 + + invoke-virtual {p0}, Landroid/content/Context;->getResources()Landroid/content/res/Resources; + + move-result-object v0 + + const-string v1, "template_college_ruled" + + const-string v2, "drawable" + + invoke-virtual {p0}, Landroid/content/Context;->getPackageName()Ljava/lang/String; + + move-result-object v3 + + invoke-virtual {v0, v1, v2, v3}, Landroid/content/res/Resources;->getIdentifier(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I + + move-result p2 + + :cond_0 + return p2 +.end method diff --git a/patches/moannotes/smali/rip/crit/ms/moannotes/FeatureRegistry.smali b/patches/moannotes/smali/rip/crit/ms/moannotes/FeatureRegistry.smali new file mode 100644 index 0000000..43629f9 --- /dev/null +++ b/patches/moannotes/smali/rip/crit/ms/moannotes/FeatureRegistry.smali @@ -0,0 +1,210 @@ +.class public final Lrip/crit/ms/moannotes/FeatureRegistry; +.super Ljava/lang/Object; + +.method public static install(Landroid/app/Activity;)V + .locals 3 + + const-string v0, "moannotes_patch" + + const/4 v1, 0x0 + + invoke-virtual {p0, v0, v1}, Landroid/app/Activity;->getSharedPreferences(Ljava/lang/String;I)Landroid/content/SharedPreferences; + + move-result-object v0 + + invoke-interface {v0}, Landroid/content/SharedPreferences;->edit()Landroid/content/SharedPreferences$Editor; + + move-result-object v0 + + const-string v1, "feature_manifest_version" + + const/4 v2, 0x1 + + invoke-interface {v0, v1, v2}, Landroid/content/SharedPreferences$Editor;->putInt(Ljava/lang/String;I)Landroid/content/SharedPreferences$Editor; + + move-result-object v0 + + invoke-interface {v0}, Landroid/content/SharedPreferences$Editor;->apply()V + + return-void +.end method + +.method private static dp(Landroid/content/Context;I)I + .locals 2 + + invoke-virtual {p0}, Landroid/content/Context;->getResources()Landroid/content/res/Resources; + + move-result-object p0 + + invoke-virtual {p0}, Landroid/content/res/Resources;->getDisplayMetrics()Landroid/util/DisplayMetrics; + + move-result-object p0 + + iget p0, p0, Landroid/util/DisplayMetrics;->density:F + + int-to-float p1, p1 + + mul-float/2addr p0, p1 + + invoke-static {p0}, Ljava/lang/Math;->round(F)I + + move-result p0 + + return p0 +.end method + +.method public static installNote(Landroid/app/Activity;)V + .locals 12 + + invoke-virtual {p0}, Landroid/app/Activity;->getResources()Landroid/content/res/Resources; + + move-result-object v0 + + const-string v1, "moannotes_snap_line_button" + + const-string v2, "id" + + invoke-virtual {p0}, Landroid/app/Activity;->getPackageName()Ljava/lang/String; + + move-result-object v3 + + invoke-virtual {v0, v1, v2, v3}, Landroid/content/res/Resources;->getIdentifier(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I + + move-result v1 + + invoke-virtual {p0, v1}, Landroid/app/Activity;->findViewById(I)Landroid/view/View; + + move-result-object v1 + + if-eqz v1, :cond_0 + + return-void + + :cond_0 + const-string v1, "note_handwrite_view" + + const-string v2, "id" + + invoke-virtual {p0}, Landroid/app/Activity;->getPackageName()Ljava/lang/String; + + move-result-object v3 + + invoke-virtual {v0, v1, v2, v3}, Landroid/content/res/Resources;->getIdentifier(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I + + move-result v1 + + invoke-virtual {p0, v1}, Landroid/app/Activity;->findViewById(I)Landroid/view/View; + + move-result-object v1 + + if-eqz v1, :cond_2 + + const-string v2, "moannotes_patch" + + const/4 v3, 0x0 + + invoke-virtual {p0, v2, v3}, Landroid/app/Activity;->getSharedPreferences(Ljava/lang/String;I)Landroid/content/SharedPreferences; + + move-result-object v2 + + const-string v4, "snap_to_line_enabled" + + invoke-interface {v2, v4, v3}, Landroid/content/SharedPreferences;->getBoolean(Ljava/lang/String;Z)Z + + move-result v4 + + new-instance v5, Lrip/crit/ms/moannotes/SnapToLineTouchListener; + + invoke-direct {v5, p0, v4}, Lrip/crit/ms/moannotes/SnapToLineTouchListener;->(Landroid/content/Context;Z)V + + invoke-virtual {v1, v5}, Landroid/view/View;->setOnTouchListener(Landroid/view/View$OnTouchListener;)V + + const-string v1, "edit_button_bar" + + const-string v6, "id" + + invoke-virtual {p0}, Landroid/app/Activity;->getPackageName()Ljava/lang/String; + + move-result-object v7 + + invoke-virtual {v0, v1, v6, v7}, Landroid/content/res/Resources;->getIdentifier(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I + + move-result v1 + + invoke-virtual {p0, v1}, Landroid/app/Activity;->findViewById(I)Landroid/view/View; + + move-result-object v1 + + instance-of v6, v1, Landroid/widget/LinearLayout; + + if-eqz v6, :cond_2 + + check-cast v1, Landroid/widget/LinearLayout; + + new-instance v6, Landroid/widget/ImageButton; + + invoke-direct {v6, p0}, Landroid/widget/ImageButton;->(Landroid/content/Context;)V + + invoke-virtual {v6, v3}, Landroid/widget/ImageButton;->setBackgroundColor(I)V + + const/16 v7, 0x30 + + invoke-static {p0, v7}, Lrip/crit/ms/moannotes/FeatureRegistry;->dp(Landroid/content/Context;I)I + + move-result v7 + + new-instance v8, Landroid/widget/LinearLayout$LayoutParams; + + const/4 v9, -0x1 + + invoke-direct {v8, v7, v9}, Landroid/widget/LinearLayout$LayoutParams;->(II)V + + invoke-virtual {v6, v8}, Landroid/widget/ImageButton;->setLayoutParams(Landroid/view/ViewGroup$LayoutParams;)V + + const-string v7, "icp_snap_line" + + const-string v8, "drawable" + + invoke-virtual {p0}, Landroid/app/Activity;->getPackageName()Ljava/lang/String; + + move-result-object v9 + + invoke-virtual {v0, v7, v8, v9}, Landroid/content/res/Resources;->getIdentifier(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I + + move-result v0 + + invoke-virtual {v6, v0}, Landroid/widget/ImageButton;->setImageResource(I)V + + const-string v0, "Handwriting snap to line" + + invoke-virtual {v6, v0}, Landroid/widget/ImageButton;->setContentDescription(Ljava/lang/CharSequence;)V + + invoke-virtual {v6, v1}, Landroid/widget/ImageButton;->setId(I)V + + if-eqz v4, :cond_1 + + const/high16 v0, 0x3f800000 # 1.0f + + goto :goto_0 + + :cond_1 + const v0, 0x3ee66666 # 0.45f + + :goto_0 + invoke-virtual {v6, v0}, Landroid/widget/ImageButton;->setAlpha(F)V + + new-instance v0, Lrip/crit/ms/moannotes/SnapToLineToggle; + + invoke-direct {v0, v5, v2, v6}, Lrip/crit/ms/moannotes/SnapToLineToggle;->(Lrip/crit/ms/moannotes/SnapToLineTouchListener;Landroid/content/SharedPreferences;Landroid/widget/ImageButton;)V + + invoke-virtual {v6, v0}, Landroid/widget/ImageButton;->setOnClickListener(Landroid/view/View$OnClickListener;)V + + const/4 v0, 0x7 + + invoke-virtual {v1, v6, v0}, Landroid/widget/LinearLayout;->addView(Landroid/view/View;I)V + + invoke-static {p0}, Lrip/crit/ms/moannotes/nativebridge/NativeFeatureHooks;->install(Landroid/app/Activity;)V + + :cond_2 + return-void +.end method diff --git a/patches/moannotes/smali/rip/crit/ms/moannotes/SnapToLineToggle.smali b/patches/moannotes/smali/rip/crit/ms/moannotes/SnapToLineToggle.smali new file mode 100644 index 0000000..0d78239 --- /dev/null +++ b/patches/moannotes/smali/rip/crit/ms/moannotes/SnapToLineToggle.smali @@ -0,0 +1,74 @@ +.class public final Lrip/crit/ms/moannotes/SnapToLineToggle; +.super Ljava/lang/Object; + +.implements Landroid/view/View$OnClickListener; + +.field private final button:Landroid/widget/ImageButton; + +.field private final listener:Lrip/crit/ms/moannotes/SnapToLineTouchListener; + +.field private final preferences:Landroid/content/SharedPreferences; + +.method public constructor (Lrip/crit/ms/moannotes/SnapToLineTouchListener;Landroid/content/SharedPreferences;Landroid/widget/ImageButton;)V + .locals 0 + + invoke-direct {p0}, Ljava/lang/Object;->()V + + iput-object p1, p0, Lrip/crit/ms/moannotes/SnapToLineToggle;->listener:Lrip/crit/ms/moannotes/SnapToLineTouchListener; + + iput-object p2, p0, Lrip/crit/ms/moannotes/SnapToLineToggle;->preferences:Landroid/content/SharedPreferences; + + iput-object p3, p0, Lrip/crit/ms/moannotes/SnapToLineToggle;->button:Landroid/widget/ImageButton; + + return-void +.end method + +.method public onClick(Landroid/view/View;)V + .locals 4 + + iget-object p1, p0, Lrip/crit/ms/moannotes/SnapToLineToggle;->listener:Lrip/crit/ms/moannotes/SnapToLineTouchListener; + + invoke-virtual {p1}, Lrip/crit/ms/moannotes/SnapToLineTouchListener;->isEnabled()Z + + move-result v0 + + xor-int/lit8 v0, v0, 0x1 + + invoke-virtual {p1, v0}, Lrip/crit/ms/moannotes/SnapToLineTouchListener;->setEnabled(Z)V + + iget-object p1, p0, Lrip/crit/ms/moannotes/SnapToLineToggle;->preferences:Landroid/content/SharedPreferences; + + invoke-interface {p1}, Landroid/content/SharedPreferences;->edit()Landroid/content/SharedPreferences$Editor; + + move-result-object p1 + + const-string v1, "snap_to_line_enabled" + + invoke-interface {p1, v1, v0}, Landroid/content/SharedPreferences$Editor;->putBoolean(Ljava/lang/String;Z)Landroid/content/SharedPreferences$Editor; + + move-result-object p1 + + invoke-interface {p1}, Landroid/content/SharedPreferences$Editor;->apply()V + + iget-object p1, p0, Lrip/crit/ms/moannotes/SnapToLineToggle;->button:Landroid/widget/ImageButton; + + if-eqz v0, :cond_0 + + const/high16 v1, 0x3f800000 # 1.0f + + const-string v2, "Handwriting snap to line on" + + goto :goto_0 + + :cond_0 + const v1, 0x3ee66666 # 0.45f + + const-string v2, "Handwriting snap to line off" + + :goto_0 + invoke-virtual {p1, v1}, Landroid/widget/ImageButton;->setAlpha(F)V + + invoke-virtual {p1, v2}, Landroid/widget/ImageButton;->setContentDescription(Ljava/lang/CharSequence;)V + + return-void +.end method diff --git a/patches/moannotes/smali/rip/crit/ms/moannotes/SnapToLineTouchListener.smali b/patches/moannotes/smali/rip/crit/ms/moannotes/SnapToLineTouchListener.smali new file mode 100644 index 0000000..4f98a8c --- /dev/null +++ b/patches/moannotes/smali/rip/crit/ms/moannotes/SnapToLineTouchListener.smali @@ -0,0 +1,152 @@ +.class public final Lrip/crit/ms/moannotes/SnapToLineTouchListener; +.super Ljava/lang/Object; + +.implements Landroid/view/View$OnTouchListener; + +.field private enabled:Z + +.field private offset:F + +.field private final spacing:F + +.method public constructor (Landroid/content/Context;Z)V + .locals 3 + + invoke-direct {p0}, Ljava/lang/Object;->()V + + iput-boolean p2, p0, Lrip/crit/ms/moannotes/SnapToLineTouchListener;->enabled:Z + + invoke-virtual {p1}, Landroid/content/Context;->getResources()Landroid/content/res/Resources; + + move-result-object p1 + + invoke-virtual {p1}, Landroid/content/res/Resources;->getDisplayMetrics()Landroid/util/DisplayMetrics; + + move-result-object p1 + + iget p1, p1, Landroid/util/DisplayMetrics;->density:F + + const/high16 v0, 0x42600000 # 56.0f + + mul-float/2addr p1, v0 + + iput p1, p0, Lrip/crit/ms/moannotes/SnapToLineTouchListener;->spacing:F + + const/4 p1, 0x0 + + iput p1, p0, Lrip/crit/ms/moannotes/SnapToLineTouchListener;->offset:F + + return-void +.end method + +.method public isEnabled()Z + .locals 1 + + iget-boolean v0, p0, Lrip/crit/ms/moannotes/SnapToLineTouchListener;->enabled:Z + + return v0 +.end method + +.method public setEnabled(Z)V + .locals 0 + + iput-boolean p1, p0, Lrip/crit/ms/moannotes/SnapToLineTouchListener;->enabled:Z + + return-void +.end method + +.method public onTouch(Landroid/view/View;Landroid/view/MotionEvent;)Z + .locals 6 + + iget-boolean p1, p0, Lrip/crit/ms/moannotes/SnapToLineTouchListener;->enabled:Z + + if-eqz p1, :cond_5 + + const/4 p1, 0x0 + + invoke-virtual {p2, p1}, Landroid/view/MotionEvent;->getToolType(I)I + + move-result v0 + + const/4 v1, 0x2 + + if-ne v0, v1, :cond_5 + + invoke-virtual {p2}, Landroid/view/MotionEvent;->getActionMasked()I + + move-result v0 + + if-ne v0, p1, :cond_0 + + invoke-virtual {p2}, Landroid/view/MotionEvent;->getY()F + + move-result v1 + + iget v2, p0, Lrip/crit/ms/moannotes/SnapToLineTouchListener;->spacing:F + + div-float v3, v1, v2 + + invoke-static {v3}, Ljava/lang/Math;->round(F)I + + move-result v3 + + int-to-float v3, v3 + + mul-float/2addr v3, v2 + + sub-float/2addr v3, v1 + + iput v3, p0, Lrip/crit/ms/moannotes/SnapToLineTouchListener;->offset:F + + :cond_0 + const/4 v1, 0x1 + + if-eq v0, p1, :cond_1 + + if-eq v0, v1, :cond_1 + + const/4 p1, 0x2 + + if-eq v0, p1, :cond_1 + + const/4 p1, 0x3 + + if-ne v0, p1, :cond_5 + + :cond_1 + invoke-virtual {p2}, Landroid/view/MotionEvent;->getX()F + + move-result p1 + + invoke-virtual {p2}, Landroid/view/MotionEvent;->getY()F + + move-result v2 + + iget v3, p0, Lrip/crit/ms/moannotes/SnapToLineTouchListener;->offset:F + + add-float/2addr v2, v3 + + invoke-virtual {p2, p1, v2}, Landroid/view/MotionEvent;->setLocation(FF)V + + if-ne v0, v1, :cond_3 + + :cond_2 + const/4 p1, 0x0 + + iput p1, p0, Lrip/crit/ms/moannotes/SnapToLineTouchListener;->offset:F + + goto :goto_0 + + :cond_3 + const/4 p1, 0x3 + + if-ne v0, p1, :cond_5 + + goto :cond_2 + + :cond_5 + :goto_0 + const/4 p1, 0x0 + + return p1 +.end method diff --git a/qmlfmt.sh b/qmlfmt.sh new file mode 100755 index 0000000..b455803 --- /dev/null +++ b/qmlfmt.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +git ls-files -z --cached --others --exclude-standard | grep -zE '\.(qml|js)$' | xargs -0 qmlformat -i +echo "qml/done" \ No newline at end of file diff --git a/requirements-adbme.txt b/requirements-adbme.txt new file mode 100644 index 0000000..73dc2d8 --- /dev/null +++ b/requirements-adbme.txt @@ -0,0 +1 @@ +pybluez2>=0.46 diff --git a/requirements-translator.txt b/requirements-translator.txt new file mode 100644 index 0000000..7290837 --- /dev/null +++ b/requirements-translator.txt @@ -0,0 +1,5 @@ +--index-url https://download.pytorch.org/whl/cu130 +torch==2.13.0 +torchvision==0.28.0 +torchaudio +argostranslate>=1.9,<2 \ No newline at end of file diff --git a/rustfmt.sh b/rustfmt.sh new file mode 100755 index 0000000..bfffb81 --- /dev/null +++ b/rustfmt.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +git ls-files -co --exclude-standard | grep '\.rs$' | xargs rustfmt --edition 2021 +echo "rust/done" \ No newline at end of file diff --git a/scripts/__pycache__/adbme_bluetooth_listener.cpython-313.pyc b/scripts/__pycache__/adbme_bluetooth_listener.cpython-313.pyc new file mode 100644 index 0000000..09215f0 Binary files /dev/null and b/scripts/__pycache__/adbme_bluetooth_listener.cpython-313.pyc differ diff --git a/scripts/adbme.ts b/scripts/adbme.ts new file mode 100644 index 0000000..0d1d616 --- /dev/null +++ b/scripts/adbme.ts @@ -0,0 +1,126 @@ +import { spawnSync } from "node:child_process"; +import path from "node:path"; + +const root = path.resolve(import.meta.dir, ".."); +const adb = process.env.ADB ?? "adb"; +const args = process.argv.slice(2); +const command = args[0] ?? "help"; + +function option(name: string): string | undefined { + const index = args.indexOf(name); + return index >= 0 ? args[index + 1] : undefined; +} + +function options(name: string): string[] { + const values: string[] = []; + for (let index = 0; index < args.length; index += 1) { + const value = args[index + 1]; + if (args[index] === name && value) values.push(value); + } + return values; +} + +function requireSerial(): string { + const serial = option("--serial"); + if (!serial) + throw new Error("Specify exactly one target with --serial "); + return serial; +} + +function run(serial: string, commandArgs: string[]): void { + const result = spawnSync(adb, ["-s", serial, ...commandArgs], { + stdio: "inherit", + }); + if (result.error) throw result.error; + if (result.status !== 0) + throw new Error(`adb ${commandArgs.join(" ")} failed`); +} + +function confirm(flag: string): void { + if (!args.includes(flag)) + throw new Error(`Refusing this device-changing operation without ${flag}`); +} + +function replacePackages( + serial: string, + launcher: string, + note: string, + uninstall: string[], +): void { + if (uninstall.length !== 2) { + throw new Error("Provide exactly two explicit --uninstall package names"); + } + for (const packageName of uninstall) run(serial, ["uninstall", packageName]); + run(serial, ["install", "-r", launcher]); + run(serial, ["install", "-r", note]); +} + +function packageFromApk(file: string): string { + const result = spawnSync("apkanalyzer", ["manifest", "print", file], { + encoding: "utf8", + }); + if (result.error) throw result.error; + const match = result.stdout.match(/\bpackage="([^"]+)"/); + if (result.status !== 0 || !match) + throw new Error(`Could not infer the package name from ${file}`); + return match[1]!; +} + +if (command === "help") { + console.log(`ADBMe guarded deployment commands + + bun run adbme status --serial SERIAL + bun run adbme grant-settings --serial SERIAL --app rip.crit.ms.adbme --confirm-permissions + bun run adbme set-language --serial SERIAL --confirm-system-changes + bun run adbme patch-and-replace --serial SERIAL --confirm-replace + bun run adbme replace --serial SERIAL --uninstall OLD_LAUNCHER --uninstall OLD_NOTE --launcher APK --note APK --confirm-replace + +CHANGE_CONFIGURATION cannot be granted to an ordinary APK on stock Android. It requires a privileged or OEM-signed app.`); +} else if (command === "status") { + run(requireSerial(), ["get-state"]); +} else if (command === "grant-settings") { + const serial = requireSerial(); + const app = option("--app"); + if (!app) + throw new Error("Specify the installed companion app with --app "); + confirm("--confirm-permissions"); + run(serial, ["shell", "appops", "set", app, "WRITE_SETTINGS", "allow"]); + console.log( + "[ok] WRITE_SETTINGS app-op enabled. CHANGE_CONFIGURATION was not attempted because stock Android rejects it for ordinary apps.", + ); +} else if (command === "set-language") { + const serial = requireSerial(); + confirm("--confirm-system-changes"); + run(serial, ["shell", "cmd", "locale", "set", "en-US"]); +} else if (command === "replace") { + const serial = requireSerial(); + const launcher = option("--launcher"); + const note = option("--note"); + const uninstall = options("--uninstall"); + if (!launcher || !note) + throw new Error("Provide --launcher APK and --note APK"); + confirm("--confirm-replace"); + replacePackages(serial, launcher, note, uninstall); +} else if (command === "patch-and-replace") { + const serial = requireSerial(); + confirm("--confirm-replace"); + const patched = spawnSync("bun", ["run", "patch-apks"], { + cwd: root, + stdio: "inherit", + }); + if (patched.error) throw patched.error; + if (patched.status !== 0) throw new Error("APK patching failed"); + const oldLauncher = packageFromApk( + path.join(root, "inputs", "MoanLauncher.apk"), + ); + const oldNote = packageFromApk(path.join(root, "inputs", "MoanNote.apk")); + console.log(`[ok] Inferred original packages: ${oldLauncher}, ${oldNote}`); + replacePackages( + serial, + path.join(root, "outputs", "MoanLauncher_patched.apk"), + path.join(root, "outputs", "MoanNote_patched.apk"), + [oldLauncher, oldNote], + ); +} else { + throw new Error(`Unknown ADBMe command: ${command}`); +} diff --git a/scripts/adbme_bluetooth_listener.py b/scripts/adbme_bluetooth_listener.py new file mode 100644 index 0000000..fc1909b --- /dev/null +++ b/scripts/adbme_bluetooth_listener.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +"""Opt-in authenticated Bluetooth Classic bridge for the ADBMe Flutter app.""" +import argparse +import hmac +import json +import os +import secrets +import subprocess +from pathlib import Path + +from bluetooth import BluetoothSocket, RFCOMM, PORT_ANY, SERIAL_PORT_CLASS, SERIAL_PORT_PROFILE, advertise_service + +ROOT = Path(__file__).resolve().parents[1] +SERVICE_UUID = "7c2bb2bf-0c66-4c76-8eec-36e7012fcf80" +TOKEN_FILE = ROOT / "build" / "adbme" / "pairing-token" + +def pairing_token() -> str: + TOKEN_FILE.parent.mkdir(parents=True, exist_ok=True) + if not TOKEN_FILE.exists(): + TOKEN_FILE.write_text(secrets.token_urlsafe(32) + "\n", encoding="utf-8") + TOKEN_FILE.chmod(0o600) + return TOKEN_FILE.read_text(encoding="utf-8").strip() + +def main() -> None: + parser = argparse.ArgumentParser() + parser.add_argument("--allow-device-mutation", action="store_true") + parsed = parser.parse_args() + token = pairing_token() + print(f"ADBMe pairing token: {token}") + print("Keep this listener local. It will only serve status unless --allow-device-mutation is present.") + listener = BluetoothSocket(RFCOMM) + listener.bind(("", PORT_ANY)) + listener.listen(1) + advertise_service(listener, "ADBMe", service_id=SERVICE_UUID, + service_classes=[SERVICE_UUID, SERIAL_PORT_CLASS], + profiles=[SERIAL_PORT_PROFILE]) + while True: + client, _ = listener.accept() + with client: + request = json.loads(client.recv(4096).decode("utf-8")) + if not hmac.compare_digest(str(request.get("token", "")), token): + client.send(b'{"error":"unauthorized"}\n') + continue + action = request.get("action") + serial = request.get("serial") + if action == "status" and serial: + result = subprocess.run(["bun", "run", "adbme", "status", "--serial", serial], cwd=ROOT, text=True, capture_output=True) + client.send(json.dumps({"code": result.returncode, "output": result.stdout + result.stderr}).encode() + b"\n") + elif parsed.allow_device_mutation: + client.send(b'{"error":"Device-changing requests must be run locally with bun run adbme"}\n') + else: + client.send(b'{"error":"mutation disabled"}\n') + +if __name__ == "__main__": + main() diff --git a/scripts/krita-patch.ts b/scripts/krita-patch.ts new file mode 100644 index 0000000..b8ffd85 --- /dev/null +++ b/scripts/krita-patch.ts @@ -0,0 +1,111 @@ +import fs from "node:fs"; +import path from "node:path"; +import { spawnSync } from "node:child_process"; + +const root = path.resolve(import.meta.dir, ".."); +const krita = path.join(root, "krita"); +const patchDir = path.join(root, "krita-patches"); +const patchFile = path.join(patchDir, "xiaomi-eink.patch"); +// Keep generated patches limited to this project. The nested Krita checkout may carry +// line-ending or formatter changes that are not part of the E Ink product patch. +const patchPaths = [ + "CMakeLists.txt", + "libs/ui/KisApplication.cpp", + "libs/ui/KisMainWindow.cpp", + "libs/ui/thememanager.cpp", + "packaging/android/apk/AndroidManifest.xml", + "packaging/android/apk/build.gradle", + "packaging/android/apk/proguard-rules.pro", + "packaging/android/apk/src/org/krita/android/MainActivity.java", + "plugins/CMakeLists.txt", + "plugins/dockers/CMakeLists.txt", + "plugins/filters/CMakeLists.txt", + "plugins/impex/CMakeLists.txt", + "plugins/paintops/CMakeLists.txt", + "plugins/tools/CMakeLists.txt", +]; +const untrackedPatchPaths = [ + "EINK_SLIM.md", + "packaging/android/apk/.gitignore", + "packaging/android/apk/settings.gradle", + "packaging/android/apk/lib/arm64-v8a/libfakeRKEpdUtils.so", + "packaging/android/apk/src/com/moan/fakerkepdlib/EpdUtil.java", + "packaging/android/apk/src/org/krita/android/XiaomiEinkController.java", + "plugins/dockers/einkmonochromeselector/CMakeLists.txt", + "plugins/dockers/einkmonochromeselector/einkmonochromeselector.cpp", + "plugins/dockers/einkmonochromeselector/krita_einkmonochromeselector.json", + "plugins/extensions/einksync/CMakeLists.txt", + "plugins/extensions/einksync/EinkSyncPlugin.action", + "plugins/extensions/einksync/EinkSyncPlugin.cpp", + "plugins/extensions/einksync/kritaeinksync.json", +]; + +function git(args: string[], allowDifference = false): string { + const result = spawnSync("git", ["-C", krita, ...args], { + encoding: "utf8", + maxBuffer: 128 * 1024 * 1024, + }); + if (result.error) throw result.error; + if (result.status !== 0 && !(allowDifference && result.status === 1)) { + throw new Error(result.stderr || `git ${args.join(" ")} failed`); + } + return result.stdout; +} + +function generate(): void { + fs.mkdirSync(patchDir, { recursive: true }); + let output = git([ + "diff", + "--binary", + "--ignore-space-at-eol", + "--", + ...patchPaths, + ]); + const available = new Set( + git(["ls-files", "--others", "--exclude-standard"]) + .split("\n") + .filter(Boolean), + ); + const untracked = untrackedPatchPaths.filter((file) => available.has(file)); + for (const file of untracked) { + output += git( + ["diff", "--no-index", "--binary", "--", "/dev/null", file], + true, + ); + } + if (!output.trim()) throw new Error("Krita has no changes to package"); + fs.writeFileSync(patchFile, output); + console.log(`[ok] Generated ${patchFile} with ${untracked.length} new files`); +} + +function apply(): void { + if (!fs.existsSync(path.join(krita, ".git"))) + throw new Error("Initialize the Krita submodule first"); + if (!fs.existsSync(patchFile)) throw new Error(`Missing ${patchFile}`); + const applyArgs = ["apply", "--ignore-space-change", "--recount"]; + const check = spawnSync( + "git", + ["-C", krita, ...applyArgs, "--check", patchFile], + { + encoding: "utf8", + }, + ); + if (check.status === 0) { + git([...applyArgs, "--whitespace=nowarn", patchFile]); + console.log("[ok] Applied E Ink Krita patch set"); + return; + } + const reverse = spawnSync( + "git", + ["-C", krita, ...applyArgs, "--reverse", "--check", patchFile], + { encoding: "utf8" }, + ); + if (reverse.status === 0) { + console.log("[ok] E Ink Krita patch set is already applied"); + return; + } + throw new Error(`Patch does not apply cleanly\n${check.stderr}`); +} + +if (process.argv.includes("--generate")) generate(); +else apply(); diff --git a/scripts/krita-unified-build.ts b/scripts/krita-unified-build.ts new file mode 100644 index 0000000..119a9c7 --- /dev/null +++ b/scripts/krita-unified-build.ts @@ -0,0 +1,355 @@ +import fs from "node:fs"; +import path from "node:path"; +import crypto from "node:crypto"; +import { spawnSync } from "node:child_process"; + +const root = path.resolve(import.meta.dir, ".."); +const krita = path.join(root, "krita"); +const deps = path.join(root, "third_party", "krita-deps-management"); +const ciUtilities = path.join(root, "third_party", "krita-ci-utilities"); +const kdeCiUtilities = path.join(root, "third_party", "kde-ci-utilities"); +const notaryService = path.join(root, "third_party", "ci-notary-service"); +const venv = path.join(root, ".venv-krita-build"); +const python = + process.platform === "win32" + ? path.join(venv, "Scripts", "python.exe") + : path.join(venv, "bin", "python"); + +function run( + command: string, + args: string[], + cwd = root, + env = process.env, +): void { + const result = spawnSync(command, args, { + cwd, + env, + stdio: "inherit", + }); + if (result.error) throw result.error; + if (result.status !== 0) + throw new Error(`${command} ${args.join(" ")} failed`); +} + +function requirePath(value: string | undefined, name: string): string { + if (!value) + throw new Error(`Set ${name} to the installed Android toolchain path`); + if (!fs.existsSync(value)) + throw new Error(`${name} does not exist: ${value}`); + return path.resolve(value); +} + +function resolveAndroidNdk(value: string | undefined, sdk: string): string { + const roots = [value, path.join(sdk, "ndk")].filter((item): item is string => + Boolean(item), + ); + const candidates = new Set(); + for (const root of roots) { + if (!fs.existsSync(root)) continue; + candidates.add(path.resolve(root)); + for (const entry of fs.readdirSync(root, { withFileTypes: true })) { + if (entry.isDirectory()) + candidates.add(path.join(path.resolve(root), entry.name)); + } + } + for (const candidate of candidates) { + const toolchain = path.join( + candidate, + "build", + "cmake", + "android.toolchain.cmake", + ); + const cpuFeatures = path.join( + candidate, + "sources", + "android", + "cpufeatures", + ); + if (fs.existsSync(toolchain) && fs.existsSync(cpuFeatures)) + return candidate; + } + throw new Error( + "Set ANDROID_NDK_ROOT to an NDK directory, or set ANDROID_SDK_ROOT to an SDK containing ndk/", + ); +} + +function readJavaMajor(javaHome: string): number | undefined { + const release = path.join(javaHome, "release"); + if (!fs.existsSync(release)) return undefined; + const match = fs.readFileSync(release, "utf8").match(/^JAVA_VERSION="(\d+)/m); + return match ? Number(match[1]) : undefined; +} + +function resolveBuildJavaHome(): string { + const requested = process.env.KRITA_JAVA_HOME; + const roots = requested + ? [requested] + : [ + process.env.JAVA_HOME ?? "", + "/usr/lib/jvm/java-21-openjdk", + "/usr/lib/jvm/java-17-openjdk", + "/usr/lib/jvm", + ]; + const candidates = new Set(); + for (const root of roots) { + if (!root || !fs.existsSync(root)) continue; + candidates.add(path.resolve(root)); + if (fs.statSync(root).isDirectory()) { + for (const entry of fs.readdirSync(root, { withFileTypes: true })) { + if (entry.isDirectory()) + candidates.add(path.join(path.resolve(root), entry.name)); + } + } + } + for (const candidate of candidates) { + const major = readJavaMajor(candidate); + if ( + major !== undefined && + major >= 17 && + major <= 24 && + fs.existsSync(path.join(candidate, "bin", "java")) + ) { + return candidate; + } + } + throw new Error( + "Install JDK 17 through 24, or set KRITA_JAVA_HOME to a supported JDK", + ); +} + +function readEnvironmentFile(file: string): Record { + return Object.fromEntries( + fs + .readFileSync(file, "utf8") + .split("\n") + .filter(Boolean) + .map((line) => line.split("=", 2) as [string, string]), + ); +} + +function releaseSigning(javaHome: string): Record { + const signingDir = path.join(root, "build", "signing"); + const keystore = path.join(signingDir, "krita-eink-release.jks"); + const environmentFile = path.join(signingDir, "krita-eink-release.env"); + fs.mkdirSync(signingDir, { recursive: true, mode: 0o700 }); + if (!fs.existsSync(keystore)) { + const password = crypto.randomBytes(32).toString("base64url"); + const values = { + MISSTRING_RELEASE_STORE_FILE: keystore, + MISSTRING_RELEASE_STORE_PASSWORD: password, + MISSTRING_RELEASE_KEY_ALIAS: "krita-eink", + MISSTRING_RELEASE_KEY_PASSWORD: password, + }; + run(path.join(javaHome, "bin", "keytool"), [ + "-genkeypair", + "-keystore", + keystore, + "-storetype", + "PKCS12", + "-storepass", + password, + "-alias", + values.MISSTRING_RELEASE_KEY_ALIAS, + "-keypass", + password, + "-keyalg", + "RSA", + "-keysize", + "4096", + "-validity", + "36500", + "-dname", + "CN=MiString Krita E Ink,O=rip.crit.ms,C=US", + ]); + fs.writeFileSync( + environmentFile, + `${Object.entries(values) + .map(([key, value]) => `${key}=${value}`) + .join("\n")}\n`, + { mode: 0o600 }, + ); + console.log(`[ok] Created local release keystore at ${keystore}`); + } + if (!fs.existsSync(environmentFile)) + throw new Error(`Missing signing credentials: ${environmentFile}`); + return readEnvironmentFile(environmentFile); +} + +function removeManagedLink( + directory: string, + name: string, + target: string, +): void { + const link = path.join(directory, name); + if (!fs.existsSync(link) && !fs.lstatSync(link, { throwIfNoEntry: false })) + return; + const metadata = fs.lstatSync(link); + if ( + !metadata.isSymbolicLink() || + fs.realpathSync(link) !== fs.realpathSync(target) + ) { + throw new Error(`${link} exists and is not a generated compatibility link`); + } + fs.unlinkSync(link); +} + +function sync(): void { + run("git", ["submodule", "update", "--init", "--recursive"]); + for (const source of [ + krita, + deps, + ciUtilities, + kdeCiUtilities, + notaryService, + ]) { + if (!fs.existsSync(path.join(source, ".git"))) { + throw new Error(`Missing submodule checkout: ${source}`); + } + } + removeManagedLink(krita, "krita-deps-management", deps); + removeManagedLink(deps, "ci-utilities", ciUtilities); + removeManagedLink(krita, "upstream-ci-utilities", kdeCiUtilities); + removeManagedLink(krita, "ci-notary-service", notaryService); + run("bun", ["run", "kr"]); + console.log( + "[ok] Source submodules are initialized and the Xiaomi E Ink patch is applied", + ); +} + +function bootstrap(): void { + sync(); + if (!fs.existsSync(python)) + run("python3", ["-m", "venv", venv, "--upgrade-deps"]); + run(python, [ + "-m", + "pip", + "install", + "-r", + path.join(deps, "requirements.txt"), + ]); + console.log("[ok] Krita dependency manager Python environment is ready"); +} + +function generateDeps(): void { + if (!fs.existsSync(python)) { + throw new Error( + "Run `bun run krita:bootstrap` before generating the dependency graph", + ); + } + const output = path.join(root, "build", "krita", ".kde-ci.generated.yml"); + fs.mkdirSync(path.dirname(output), { recursive: true }); + run( + python, + [ + path.join(deps, "tools", "generate-deps-file.py"), + "-s", + path.join(deps, "latest", "krita-deps.yml"), + "-o", + output, + ], + krita, + { ...process.env, PYTHONDONTWRITEBYTECODE: "1" }, + ); + console.log(`[ok] Generated ${output}`); +} + +function build(release = false): void { + sync(); + generateDeps(); + const sdk = requirePath(process.env.ANDROID_SDK_ROOT, "ANDROID_SDK_ROOT"); + const ndk = resolveAndroidNdk(process.env.ANDROID_NDK_ROOT, sdk); + const javaHome = resolveBuildJavaHome(); + const signing = release ? releaseSigning(javaHome) : {}; + const localBuildRoot = path.join(root, "build", "krita"); + const localCache = + process.env.KDECI_CACHE_PATH ?? path.join(localBuildRoot, "cache"); + const localWork = + process.env.KDECI_WORKDIR_PATH ?? path.join(localBuildRoot, "work"); + const localCcache = + process.env.KDECI_CC_CACHE ?? path.join(localBuildRoot, "ccache"); + const xiaomiEink = process.env.KRITA_XIAOMI_EINK ?? "1"; + const xiaomiEinkEnabled = ["1", "ON", "true", "TRUE"].includes(xiaomiEink); + for (const directory of [localCache, localWork, localCcache]) { + fs.mkdirSync(directory, { recursive: true }); + } + const environment = { + ...process.env, + KRITA_EINK_SLIM: "1", + KRITA_XIAOMI_EINK: xiaomiEink, + UNOTE_SOURCE_DIR: path.join(root, "unote", "src", "main", "java"), + UNOTE_PLUS_SOURCE_DIR: path.join(root, "unote-plus", "src", "main", "java"), + KRITACI_ANDROID_PACKAGE_TYPE: release ? "release" : "debug", + KRITACI_ANDROID_RELEASE_MODE: release ? "1" : "", + PYTHONDONTWRITEBYTECODE: "1", + JAVA_HOME: javaHome, + PATH: `${path.join(javaHome, "bin")}:${process.env.PATH ?? ""}`, + KDECI_REPO_METADATA_PATH: path.join(deps, "repo-metadata"), + KDECI_ANDROID_SDK_ROOT: sdk, + KDECI_ANDROID_NDK_ROOT: ndk, + KDECI_ANDROID_ABI: "arm64-v8a", + KDECI_BUILD_TYPE: "Release", + KDECI_SKIP_ECM_ANDROID_TOOLCHAIN: "True", + KDECI_CACHE_PATH: localCache, + KDECI_WORKDIR_PATH: localWork, + KDECI_CC_CACHE: localCcache, + KDECI_GITLAB_SERVER: + process.env.KDECI_GITLAB_SERVER ?? "https://invent.kde.org/", + KDECI_PACKAGE_PROJECT: + process.env.KDECI_PACKAGE_PROJECT ?? + "teams/ci-artifacts/krita-android-arm64-v8a", + KDECI_COMPRESS_PACKAGES_ON_DOWNLOAD: "False", + ...signing, + CMAKE_TOOLCHAIN_FILE: path.join( + deps, + "tools", + "android-toolchain-krita.cmake", + ), + KDECI_EXTRA_CMAKE_ARGS: `-DKRITA_EINK_SLIM=ON -DKRITA_XIAOMI_EINK=${xiaomiEinkEnabled ? "ON" : "OFF"} -DBUILD_TESTING=OFF -DENABLE_UPDATERS=OFF`, + }; + const sourceConfig = path.join(krita, ".kde-ci.yml"); + const generatedConfig = path.join( + root, + "build", + "krita", + ".kde-ci.generated.yml", + ); + const originalConfig = fs.readFileSync(sourceConfig); + fs.copyFileSync(generatedConfig, sourceConfig); + try { + run( + python, + [ + path.join(ciUtilities, "run-ci-build.py"), + "--project", + "krita", + "--branch", + "master", + "--platform", + "Android/arm64-v8a/Qt5/Shared", + "--only-build", + "--skip-publishing", + ], + krita, + environment, + ); + run( + python, + ["build-tools/ci-scripts/build-android-package.py"], + krita, + environment, + ); + } finally { + fs.writeFileSync(sourceConfig, originalConfig); + } +} + +const command = process.argv[2] ?? "sync"; +if (command === "sync") sync(); +else if (command === "bootstrap") bootstrap(); +else if (command === "deps") generateDeps(); +else if (command === "build") build(); +else if (command === "release") build(true); +else + throw new Error( + "Usage: krita-unified-build.ts [sync|bootstrap|deps|build|release]", + ); diff --git a/scripts/reinstall-moannotes.ts b/scripts/reinstall-moannotes.ts new file mode 100644 index 0000000..4ecd9da --- /dev/null +++ b/scripts/reinstall-moannotes.ts @@ -0,0 +1,40 @@ +import { existsSync } from "node:fs"; +import { spawnSync } from "node:child_process"; +import path from "node:path"; + +const root = path.resolve(import.meta.dir, ".."); +const args = process.argv.slice(2); + +function value(flag: string): string | undefined { + const index = args.indexOf(flag); + return index >= 0 ? args[index + 1] : undefined; +} + +function run(command: string, commandArgs: string[]): void { + const result = spawnSync(command, commandArgs, { + cwd: root, + stdio: "inherit", + }); + if (result.error) throw result.error; + if (result.status !== 0) + throw new Error(`${command} ${commandArgs.join(" ")} failed`); +} + +const serial = value("--serial"); +if (!serial) + throw new Error("Specify the Xiaomi target with --serial "); +if (!args.includes("--confirm-reinstall")) + throw new Error("Refusing to replace an app without --confirm-reinstall"); + +run("bun", ["run", "patch:moannotes"]); +const apk = + value("--apk") ?? path.join(root, "outputs", "MoanNote_patched-signed.apk"); +if (!existsSync(apk)) { + throw new Error( + `Signed APK is missing at ${path.join("outputs", "MoanNote_patched-signed.apk")}`, + ); +} +run("adb", ["-s", serial, "install", "--no-incremental", "-r", apk]); +console.log( + `[ok] Reinstalled ${path.basename(apk)} without uninstalling MoanNotes data.`, +); diff --git a/scripts/sign-moannotes.ts b/scripts/sign-moannotes.ts new file mode 100644 index 0000000..dd16b56 --- /dev/null +++ b/scripts/sign-moannotes.ts @@ -0,0 +1,70 @@ +import crypto from "node:crypto"; +import fs from "node:fs"; +import path from "node:path"; +import { spawnSync } from "node:child_process"; + +const root = path.resolve(import.meta.dir, ".."); +const app = process.argv[2] ?? "MoanNote"; +if (!/^[A-Za-z0-9_-]+$/.test(app)) throw new Error("App name must be a simple file name"); +const unsignedApk = path.join(root, "outputs", `${app}_patched.apk`); +const signedApk = path.join(root, "outputs", `${app}_patched-signed.apk`); +const signingDir = path.join(root, "build", "signing"); +const keyName = `${app.toLowerCase()}-dev`; +const keystore = path.join(signingDir, `${keyName}.jks`); +const credentials = path.join(signingDir, `${keyName}.env`); + +function run(command: string, args: string[]): void { + const result = spawnSync(command, args, { cwd: root, stdio: "inherit" }); + if (result.error) throw result.error; + if (result.status !== 0) + throw new Error(`${path.basename(command)} failed with status ${result.status}`); +} + +function readCredentials(): Record { + return Object.fromEntries( + fs + .readFileSync(credentials, "utf8") + .trim() + .split("\n") + .filter(Boolean) + .map((line) => line.split("=", 2) as [string, string]), + ); +} + +function androidTool(name: "apksigner" | "zipalign"): string { + const sdk = process.env.ANDROID_HOME ?? process.env.ANDROID_SDK_ROOT ?? "/var/home/hellings/android-sdk"; + for (const version of ["36.0.0", "35.0.0", "34.0.0"]) { + const tool = path.join(sdk, "build-tools", version, name); + if (fs.existsSync(tool)) return tool; + } + throw new Error(`Android ${name} was not found under ${sdk}/build-tools`); +} + +function ensureDevKey(): Record { + fs.mkdirSync(signingDir, { recursive: true, mode: 0o700 }); + if (!fs.existsSync(keystore)) { + const password = crypto.randomBytes(32).toString("base64url"); + const values = { storePassword: password, keyPassword: password, alias: keyName }; + run("keytool", [ + "-genkeypair", "-keystore", keystore, "-storetype", "PKCS12", "-storepass", password, + "-alias", values.alias, "-keypass", password, "-keyalg", "RSA", "-keysize", "2048", + "-validity", "3650", "-dname", `CN=${app} Development,O=rip.crit.ms,C=US`, + ]); + fs.writeFileSync(credentials, Object.entries(values).map(([key, value]) => `${key}=${value}`).join("\n") + "\n", { mode: 0o600 }); + console.log(`[ok] Created local ${app} development key at ${keystore}`); + } + if (!fs.existsSync(credentials)) throw new Error(`Development key credentials are missing at ${credentials}`); + return readCredentials(); +} + +if (!fs.existsSync(unsignedApk)) throw new Error(`Patched APK is missing at ${unsignedApk}`); +const values = ensureDevKey(); +const aligned = path.join(root, "build", `${app}_patched-aligned.apk`); +fs.mkdirSync(path.dirname(aligned), { recursive: true }); +run(androidTool("zipalign"), ["-f", "-p", "4", unsignedApk, aligned]); +run(androidTool("apksigner"), [ + "sign", "--ks", keystore, "--ks-key-alias", values.alias!, "--ks-pass", `pass:${values.storePassword!}`, + "--key-pass", `pass:${values.keyPassword!}`, "--out", signedApk, aligned, +]); +run(androidTool("apksigner"), ["verify", "--verbose", "--print-certs", signedApk]); +console.log(`[ok] Signed ${signedApk}`); diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..300b5fc --- /dev/null +++ b/settings.gradle @@ -0,0 +1,2 @@ +rootProject.name = 'mistring' +include 'moannotes-native' diff --git a/tessl.json b/tessl.json new file mode 100644 index 0000000..d91cf08 --- /dev/null +++ b/tessl.json @@ -0,0 +1,21 @@ +{ + "name": "mistring", + "mode": "vendored", + "dependencies": { + "bergside/awesome-design-skills": { + "version": "f631a09b4fcc0166f2e2c1a8c81906ef680c57e8", + "source": "https://github.com/bergside/awesome-design-skills", + "include": { + "skills": ["neumorphism"] + } + } + }, + "agents": [ + "claude-code", + "gemini", + "antigravity", + "codex", + "copilot", + "copilot-vscode" + ] +} diff --git a/third_party/ci-notary-service/.flake8 b/third_party/ci-notary-service/.flake8 new file mode 100644 index 0000000..9805eb2 --- /dev/null +++ b/third_party/ci-notary-service/.flake8 @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: None + +[flake8] +max-line-length = 120 +extend-ignore = + # black adds spaces around ':' + E203, +extend-exclude = + ./build, + *.egg-info, + .venv, diff --git a/third_party/ci-notary-service/.gitignore b/third_party/ci-notary-service/.gitignore new file mode 100644 index 0000000..fc1ab8f --- /dev/null +++ b/third_party/ci-notary-service/.gitignore @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +/*.egg-info/ +/.tox/ + +/.coverage +/coverage.xml +/junit-*.xml + +.venv/ +__pycache__/ diff --git a/third_party/ci-notary-service/.gitlab-ci.yml b/third_party/ci-notary-service/.gitlab-ci.yml new file mode 100644 index 0000000..0a9619a --- /dev/null +++ b/third_party/ci-notary-service/.gitlab-ci.yml @@ -0,0 +1,70 @@ +# SPDX-License-Identifier: BSD-2-Clause +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + +include: + - project: sysadmin/ci-utilities + file: /gitlab-templates/reuse-lint.yml + +workflow: + rules: + # Prevent branch pipelines if an MR is open on the branch. + - if: $CI_COMMIT_BRANCH && $CI_PIPELINE_SOURCE == "push" && $CI_OPEN_MERGE_REQUESTS + when: never + # Allow merge request pipelines. + - if: $CI_PIPELINE_SOURCE == "merge_request_event" + # Build tags and branches too + - if: $CI_COMMIT_TAG + - if: $CI_COMMIT_BRANCH + +variables: + PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip" + +default: + image: python:3.11 + tags: + - Linux + interruptible: true + before_script: + - python --version + - python -m venv .venv + - source .venv/bin/activate + - pip install tox + artifacts: + reports: + coverage_report: + coverage_format: cobertura + path: coverage.xml + junit: junit-*.xml + +py310: + image: python:3.10 + script: tox -e py310 + +py311-coverage: + script: tox -e coverage + coverage: "/[^ ]+%/" + +format: + script: tox -e check-format + +lint: + script: tox -e lint + +imports: + script: tox -e check-imports + +security: + script: tox -e security + +type-check: + script: tox -e static-type-checker + +reuse: + inherit: + default: false + # override the stage of the reuse-lint template + stage: test + +yamllint: + script: tox -e yamllint diff --git a/third_party/ci-notary-service/.pre-commit-config.yaml b/third_party/ci-notary-service/.pre-commit-config.yaml new file mode 100644 index 0000000..12fcad9 --- /dev/null +++ b/third_party/ci-notary-service/.pre-commit-config.yaml @@ -0,0 +1,37 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +repos: + - repo: https://github.com/psf/black + rev: 23.11.0 + hooks: + - id: black + + - repo: https://github.com/pycqa/flake8 + rev: 6.1.0 + hooks: + - id: flake8 + + - repo: https://github.com/pycqa/isort + rev: 5.12.0 + hooks: + - id: isort + args: ["--profile", "black", "--filter-files"] + + - repo: https://github.com/pre-commit/mirrors-mypy + rev: v1.7.0 + hooks: + - id: mypy + args: ["--pretty", "--show-error-codes"] + additional_dependencies: + - types-paramiko + - types-PyYAML + - types-requests + - azure-storage-blob + - markdownify + - git+https://invent.kde.org/kloecker/microstore.git + + - repo: https://github.com/adrienverge/yamllint.git + rev: v1.33.0 + hooks: + - id: yamllint diff --git a/third_party/ci-notary-service/.yamllint.yaml b/third_party/ci-notary-service/.yamllint.yaml new file mode 100644 index 0000000..66ee938 --- /dev/null +++ b/third_party/ci-notary-service/.yamllint.yaml @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +extends: default + +rules: + document-start: disable + line-length: + max: 120 + level: warning diff --git a/third_party/ci-notary-service/LICENSES/BSD-2-Clause.txt b/third_party/ci-notary-service/LICENSES/BSD-2-Clause.txt new file mode 100644 index 0000000..baa80b5 --- /dev/null +++ b/third_party/ci-notary-service/LICENSES/BSD-2-Clause.txt @@ -0,0 +1,22 @@ +Copyright (c) All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/third_party/ci-notary-service/LICENSES/CC0-1.0.txt b/third_party/ci-notary-service/LICENSES/CC0-1.0.txt new file mode 100644 index 0000000..0e259d4 --- /dev/null +++ b/third_party/ci-notary-service/LICENSES/CC0-1.0.txt @@ -0,0 +1,121 @@ +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. diff --git a/third_party/ci-notary-service/README.md b/third_party/ci-notary-service/README.md new file mode 100644 index 0000000..1a2a61d --- /dev/null +++ b/third_party/ci-notary-service/README.md @@ -0,0 +1,106 @@ + + +# CI Notary Service + +This project provides code signing services, publishing services, and other +services that require sensitive data for usage by our CI. + +## Basic Idea + +Servers providing certain services and clients that want to use those services +exchange requests and responses via an SFTP server. This way the service +providers do not need to be reachable via a public IP address. + +If you want to learn more read the [Technical Details](doc/details.md) page. + +## Services + +The following services are provided: + +- [aabsigner](doc/aabsigner.md) - signs Android app bundles (AAB) +- [apksigner](doc/apksigner.md) - signs APKs +- [fdroidpublisher](doc/fdroidpublisher.md) - publishes APKs to F-Droid repositories +- [flatpaksigner](doc/flatpaksigner.md) - adds Flatpak bundles to a repository signing the commits +- [googleplaypublisher](doc/googleplaypublisher.md) - publishes APKs in Google Play +- [macappnotarizer](doc/macappnotarizer.md) - sends a notarization request to Apple to notarize DMGs +- [macappsigner](doc/macappsigner.md) - signs .app/DMGs +- [microsoftstorepublisher](doc/microsoftstorepublisher.md) - publishes APPXs in Microsoft Store +- [pypipublisher](doc/pypipublisher.md) - publishes Python packages to PyPi +- [websitepublisher](doc/websitepublisher.md) - publishes static websites to webservers +- [windowsbinariessigner](doc/windowsbinariessigner.md) - signs Windows binaries and packages (APPX/MSIX) + +## Installation + +Clone this repository, create a virtual environment, and install the requirements. + +```sh +git clone https://invent.kde.org/sysadmin/ci-notary-service.git +python3 -m venv .venv +. .venv/bin/activate +pip3 install -r requirements.txt +``` + +## Local testing + +Patch the python file of the service like + +```diff +- startWorker(options.workerId) ++ # startWorker(options.workerId) ++ from unittest.mock import patch ++ ++ fakeJob = {"ref": "master", "pipeline": {"project_id": 73, "source": "push"}} ++ with patch("sftpnotary.authentication.GitLabJobTokenAuthentication.getJob", return_value=fakeJob): ++ startWorker(options.workerId) +``` + +to fake the `/job` request done to invent with the job token. + +A SFTP server is the core part of all services. + +A simple way to get one runnning is the `lscr.io/linuxserver/openssh-server` docker. You can start it like this: + +```bash +docker run -d \ + --name=openssh-server \ + -e PUID=1000 \ + -e PGID=1000 \ + -e TZ=Etc/UTC \ + -e USER_NAME=kde \ + -p 2222:2222 \ + -e PUBLIC_KEY="ssh-rsa A...z== something@something" \ # Replace this by your own public key + --restart unless-stopped \ + lscr.io/linuxserver/openssh-server:latest +``` + +With the above docker the `[SFTP]` section of your config needs to look like this: + +```ini +[SFTP] +Server = 0.0.0.0 +Port = 2222 +Username = kde +# This depends on the service you are testing +BasePath = websitepublisher +RsaKeyFile = /path/to/private/ssh_key +``` + +If you run the service also inside a Docker container then you need to use `Server = host.docker.internal` as SFTP server for the service. + +The private SSH key should not be encrypted / password protected. + +Note: paramiko's error messages are sometimes wrong and misleading. Eg. if the port in your config is wrong, it might tell you that the key is encrypted. + +For running the client you need to pass a few environment variables, e.g. + +```shell +CI_JOB_TOKEN=dummy \ # This does not need to be an actual job token, can be anything +CI_PROJECT_PATH=pim/itinerary \ +CI_COMMIT_REF_NAME=master \ +``` + +`CI_PROJECT_PATH` and `CI_COMMIT_REF_NAME` must match `project_id` and `ref` used for fakeJob (see patch above). diff --git a/third_party/ci-notary-service/aabsigner.py b/third_party/ci-notary-service/aabsigner.py new file mode 100644 index 0000000..8692937 --- /dev/null +++ b/third_party/ci-notary-service/aabsigner.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: BSD-2-Clause +# +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + +import sys + +from sftpnotary import authentication, config, util +from sftpnotary.aabsigner import SignAabWorker +from sftpnotary.exceptions import Error + + +def parseCommandLine(): + import argparse + + parser = argparse.ArgumentParser(description="Worker for signing AABs") + + # debug options + parser.add_argument("-v", "--verbose", action="count", default=0, help="increase the verbosity") + + parser.add_argument("--id", dest="workerId", help="Unique, alpha-numeric identifier of this service worker") + + parser.add_argument("--config") + + options = parser.parse_args() + return options + + +def setUpAuthentication(): + auth = authentication.GitLabJobTokenAuthentication( + apiV4Url=config.settings.get("Authentication", "GitLabAPIv4Url", ""), userAgent="org.kde.aabsigner" + ) + authentication.setAuthentication(auth) + + +def startWorker(workerId: str): + with util.connectToSftpServer() as sftp: + worker = SignAabWorker(workerId, sftp) + worker.start() + + +def main(): + options = parseCommandLine() + config.loadConfig(options.config) + util.setUpServiceLogging("aabsigner", options.verbose) + util.loadProjectSettings(config.settings.get("General", "ProjectSettings")) + if config.settings.getboolean("Authentication", "Enabled", False): + setUpAuthentication() + + startWorker(options.workerId) + + return 0 + + +if __name__ == "__main__": + try: + sys.exit(main()) + except Error as e: + print("Error: %s" % e, file=sys.stderr) + sys.exit(1) diff --git a/third_party/ci-notary-service/apksigner.py b/third_party/ci-notary-service/apksigner.py new file mode 100644 index 0000000..451bbad --- /dev/null +++ b/third_party/ci-notary-service/apksigner.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: BSD-2-Clause +# +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + +import sys + +from sftpnotary import authentication, config, util +from sftpnotary.apksigner import SignApkWorker +from sftpnotary.exceptions import Error + + +def parseCommandLine(): + import argparse + + parser = argparse.ArgumentParser(description="Worker for signing APKs") + + # debug options + parser.add_argument("-v", "--verbose", action="count", default=0, help="increase the verbosity") + + parser.add_argument("--id", dest="workerId", help="Unique, alpha-numeric identifier of this service worker") + + parser.add_argument("--config") + + options = parser.parse_args() + return options + + +def setUpAuthentication(): + auth = authentication.GitLabJobTokenAuthentication( + apiV4Url=config.settings.get("Authentication", "GitLabAPIv4Url", ""), userAgent="org.kde.apksigner" + ) + authentication.setAuthentication(auth) + + +def startWorker(workerId: str): + with util.connectToSftpServer() as sftp: + worker = SignApkWorker(workerId, sftp) + worker.start() + + +def main(): + options = parseCommandLine() + config.loadConfig(options.config) + util.setUpServiceLogging("apksigner", options.verbose) + util.loadProjectSettings(config.settings.get("General", "ProjectSettings")) + if config.settings.getboolean("Authentication", "Enabled", False): + setUpAuthentication() + + startWorker(options.workerId) + + return 0 + + +if __name__ == "__main__": + try: + sys.exit(main()) + except Error as e: + print("Error: %s" % e, file=sys.stderr) + sys.exit(1) diff --git a/third_party/ci-notary-service/buildpublisher.py b/third_party/ci-notary-service/buildpublisher.py new file mode 100644 index 0000000..39720d6 --- /dev/null +++ b/third_party/ci-notary-service/buildpublisher.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: BSD-2-Clause +# +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileCopyrightText: 2023 Ben Cooksley +# SPDX-FileContributor: Ingo Klöcker + +import sys + +from sftpnotary import authentication, config, util +from sftpnotary.buildpublisher import PublishBuildWorker +from sftpnotary.exceptions import Error + + +def parseCommandLine(): + import argparse + + parser = argparse.ArgumentParser(description="Worker for publishing build artifacts to a remote server") + + # debug options + parser.add_argument("-v", "--verbose", action="count", default=0, help="increase the verbosity") + + parser.add_argument("--id", dest="workerId", help="Unique, alpha-numeric identifier of this service worker") + + parser.add_argument("--config") + + options = parser.parse_args() + return options + + +def setUpAuthentication(): + auth = authentication.GitLabJobTokenAuthentication( + apiV4Url=config.settings.get("Authentication", "GitLabAPIv4Url", ""), userAgent="org.kde.buildpublisher" + ) + authentication.setAuthentication(auth) + + +def startWorker(workerId: str): + with util.connectToSftpServer() as sftp: + worker = PublishBuildWorker(workerId, sftp) + worker.start() + + +def main(): + options = parseCommandLine() + config.loadConfig(options.config) + util.setUpServiceLogging("buildpublisher", options.verbose) + util.loadProjectSettings(config.settings.get("General", "ProjectSettings")) + if config.settings.getboolean("Authentication", "Enabled", False): + setUpAuthentication() + + startWorker(options.workerId) + + return 0 + + +if __name__ == "__main__": + try: + sys.exit(main()) + except Error as e: + print("Error: %s" % e, file=sys.stderr) + sys.exit(1) diff --git a/third_party/ci-notary-service/doc/aabsigner-projects.sample.yaml b/third_party/ci-notary-service/doc/aabsigner-projects.sample.yaml new file mode 100644 index 0000000..45d859d --- /dev/null +++ b/third_party/ci-notary-service/doc/aabsigner-projects.sample.yaml @@ -0,0 +1,37 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +# define defaults for all listed projects +defaults: + # the KeyStore file containing the (upload) key used for signing AABs + uploadkeystore: ~/.credentials/keystore-for-google-play-upload.jks + # the password for the KeyStore file; prefer the "file:" format + uploadkeystorepass: file:~/.credentials/keystore-for-google-play-upload.pass + # the alias of the (upload) key used for signing AABs + uploadkeyalias: google-play-upload-key + # list of branches cleared for signing AABs for all listed projects + branches: [] + +# define settings specific for Project A (in Namespace A) +# key for Project A is the GitLab path of the project +namespace-a/project-a: + # the application ID of the AAB; checked against the AAB to sign + applicationid: net.example.projecta + # dictionary of additional branches cleared for signing of AABs + branches: + # allow signing AABs from the release branch for Project A + release: + +namespace-a/project-b: + # the application ID of the AAB + applicationid: net.example.projectb + # keys for signing AABs for Project B are stored in a different KeyStore file + uploadkeystore: ~/.credentials/projectb.jks + # the keys are protected with another password + uploadkeystorepass: file:~/.credentials/projectb.pass + # and the key used for signing AABs has another alias + uploadkeyalias: projectb-upload-key + branches: + # use a different KeyStore for the legacy branch of Project B + legacy: + uploadkeystore: ~/.credentials/projectb/legacy.jks diff --git a/third_party/ci-notary-service/doc/aabsigner-user.sample.service b/third_party/ci-notary-service/doc/aabsigner-user.sample.service new file mode 100644 index 0000000..594513c --- /dev/null +++ b/third_party/ci-notary-service/doc/aabsigner-user.sample.service @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +[Unit] +Description=aabsigner +After=syslog.target network.target + +[Service] +Type=exec +WorkingDirectory=%h/aabsigner +Environment="PATH=%h/aabsigner/.venv/bin:/usr/local/bin:/usr/bin:/bin" +ExecStart=%h/aabsigner/.venv/bin/python aabsigner.py -vv --id %u --config %h/.config/aabsigner.ini +Restart=on-failure +# avoid too many restarts in a short time span if starting the service fails +# because the SFTP server is temporarily unavailable +RestartSec=5s + +[Install] +WantedBy=default.target diff --git a/third_party/ci-notary-service/doc/aabsigner.md b/third_party/ci-notary-service/doc/aabsigner.md new file mode 100644 index 0000000..84becf9 --- /dev/null +++ b/third_party/ci-notary-service/doc/aabsigner.md @@ -0,0 +1,116 @@ + + +# aabsigner.py - An AAB Signing Service + +Provides code signing for Android app bundles (AAB). + +## Prerequisites + +The service needs an SFTP server for exchanging data with the clients. + +Additionally, for signing AABs you need + +- a key store file containing the certificate to sign the AABs with, +- a file containing the password to unlock the key store. + +## Installation + +### Install Bundletool + +Bundletool is needed for verifying the application ID of AABs. Download the jar +file from the +[GitHub repository](https://github.com/google/bundletool/releases). + +### Install the Service + +Clone this repository on a server that shall provide the service, +create a virtual environment, and install the requirements. + +```sh +git clone https://invent.kde.org/sysadmin/ci-notary-service.git aabsigner +cd aabsigner +python3 -m venv .venv +. .venv/bin/activate +pip3 install -r requirements.txt +``` + +### Configure the Service + +Copy `aabsigner.sample.ini` to `aabsigner.ini` and replace the example values +with the appropriate values for your installation. + +Then copy `aabsigner-projects.sample.yaml` to `aabsigner-projects.yaml` and +specify the settings for the projects you want to sign APKs for. + +## Run the Service + +Activate the virtual environment and start `aabsigner.py`. + +```sh +cd ~/aabsigner +. .venv/bin/activate +python3 aabsigner.py --id workerA --config aabsigner.ini +``` + +where you replace `workerA` with a unique alpha-numeric ID for each instance +of `aabsigner.py` you start. + +## Use the Service to Sign an APK + +Clone this repository on the client, create a virtual environment, and install +the requirements. + +```sh +git clone https://invent.kde.org/sysadmin/ci-notary-service.git aabsigner +cd aabsigner +python3 -m venv .venv +. .venv/bin/activate +pip3 install -r requirements.txt +``` + +Copy `signaab.sample.ini` to `signaab.ini` and replace the example values +with the appropriate values for your installation. In particular, the value +for `BasePath` must match the corresponding value in the settings of the +service. + +Then run `signaab.py` to sign the APK + +```sh +python3 signaab.py --config signaab.ini +``` + +## Managing the Service with systemd + +We set up the service under the user's control with a per-user systemd instance. + +Copy `aabsigner-user.sample.service` to `~/.config/systemd/user/aabsigner-user.service` +and modify it as needed. The example uses the username as ID of the service +worker. Make sure that the ID is unique if you run multiple service workers. + +Start the service with + +```sh +systemctl --user start aabsigner-user.service +``` + +If you want the service to be started automatically, then enable autostart with + +```sh +systemctl --user enable aabsigner-user.service +``` + +Note: By default, the systemd user instance and thus the user-managed services are +started after the first login of a user and killed after the last session of the +user is closed. To start the user instance right after boot, and keep the systemd +user instance running after the last session closes you have to enable lingering +for the user: + +```sh +loginctl enable-linger USERNAME +``` + +For more details on user-managed services see https://wiki.archlinux.org/title/Systemd/User. diff --git a/third_party/ci-notary-service/doc/aabsigner.sample.ini b/third_party/ci-notary-service/doc/aabsigner.sample.ini new file mode 100644 index 0000000..5c9b3b5 --- /dev/null +++ b/third_party/ci-notary-service/doc/aabsigner.sample.ini @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +[Authentication] +Enabled = true +GitLabAPIv4Url = https://gitlab.example.net/api/v4 + +[ApkSigning] +# the path of the bundletool jar file (used when signing AABs) +BundletoolJarPath = /opt/bundletool/bundletool-all-1.15.6.jar + +[GooglePlayPublishing] +# the path of jarsigner (used for signing the AABs) +JarsignerPath = /usr/bin/jarsigner +# the KeyStore file containing the (upload) key used for signing AABs; overridden by project settings +UploadKeyStore = ~/.local/share/aabsigner/keystore-for-google-play-upload.jks +# the password for the KeyStore file; overridden by project settings +UploadKeyStorePass = file:~/.local/share/aabsigner/keystore-for-google-play-upload.pass +# the alias of the (upload) key used for signing AABs; overridden by project settings +UploadKeyAlias = google-play-upload-key + +[General] +ProjectSettings = ~/.local/share/aabsigner/aabsigner-projects.yaml + +[Logging] +# Optionally, write log output to a file +#LogFile = .../aabsigner.log + +[SFTP] +# SFTP server to use +Server = sftp.example.net +# Port to connect to +#Port = 2222 +# User to connect with +Username = sftpnotary +# (Sub)directory on the server used for tasks for this service +BasePath = aabsigner + +# File with known host keys to prevent connection to unknown servers; +# if not specified, then the system host keys are used and missing host keys +# are accepted automatically +#KnownHostsFile = ~/.local/share/aabsigner/known_hosts + +# File with the private OpenSSH RSA key to use for login +#RsaKeyFile = ~/.ssh/id_rsa +# or name of environment variable with private OpenSSH RSA key to use for login +#RsaKeyFile = env:ENVIRONMENT_VARIABLE +# if no key is specified, then the SSH agent is used diff --git a/third_party/ci-notary-service/doc/apksigner-projects.sample.yaml b/third_party/ci-notary-service/doc/apksigner-projects.sample.yaml new file mode 100644 index 0000000..68a7913 --- /dev/null +++ b/third_party/ci-notary-service/doc/apksigner-projects.sample.yaml @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +# define defaults for all listed projects +defaults: + # define the KeyStore file to use by default + keystore: ~/.local/apksigner/keystore.jks + # and the password for the KeyStore file; prefer the "file:" format + keystorepass: file:/keystorepass + # list of branches to sign for all listed projects + branches: + - master + +# define settings specific for Project A (in Namespace A) +# key for Project A is the GitLab path of the project +namespace-a/project-a: + # the application ID of the APK; checked against the APK to sign + applicationid: net.example.projecta + # use key with alias "projecta" from default KeyStore for Project A + keyalias: projecta + # dictionary of branches to sign additionally to the default branches + branches: + # also allow signing the release branch for Project A + release: + +namespace-a/project-b: + # the application ID of the APK + applicationid: net.example.projectb + # signing keys for Project B are stored in a different KeyStore file + keystore: projectb.jks + # specifying the key alias is not necessary if the KeyStore contains only one key + branches: + # use a different KeyStore for the legacy branch of Project B + legacy: + keystore: ~/.local/apksigner/legacy.jks diff --git a/third_party/ci-notary-service/doc/apksigner-user.sample.service b/third_party/ci-notary-service/doc/apksigner-user.sample.service new file mode 100644 index 0000000..4f0b12d --- /dev/null +++ b/third_party/ci-notary-service/doc/apksigner-user.sample.service @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +[Unit] +Description=apksigner +After=syslog.target network.target + +[Service] +Type=exec +WorkingDirectory=%h/apksigner +Environment="PATH=%h/apksigner/.venv/bin:/usr/local/bin:/usr/bin:/bin" +ExecStart=%h/apksigner/.venv/bin/python apksigner.py -vv --id %u --config %h/.config/apksigner.ini +Restart=on-failure +# avoid too many restarts in a short time span if starting the service fails +# because the SFTP server is temporarily unavailable +RestartSec=5s + +[Install] +WantedBy=default.target diff --git a/third_party/ci-notary-service/doc/apksigner.md b/third_party/ci-notary-service/doc/apksigner.md new file mode 100644 index 0000000..f787228 --- /dev/null +++ b/third_party/ci-notary-service/doc/apksigner.md @@ -0,0 +1,184 @@ + + +# apksigner.py - An APK Signing Service + +Provides code signing for APKs. + +## Prerequisites + +The service needs an SFTP server for exchanging data with the clients. + +Additionally, for signing APKs you need + +- a key store file containing the certificate to sign the APKs with, +- a file containing the password to unlock the key store. + +## Installation + +### Install an Android SDK + +`apksigner.py` needs the tools `apksigner`, `zipalign`, and `apkanalyzer` from +an Android SDK. The following instructions are based on the installation of +the Android SDK in KDE's Android Docker image. See below for an alternative +setup using KDE's Android Docker image. + +```sh +export NDK_VERSION=22.1.7171670 +export SDK_PLATFORM=android-33 +export SDK_BUILD_TOOLS=30.0.3 +export SDK_PACKAGES="tools platform-tools" + +export ANDROID_HOME=~/android-sdk +export ANDROID_SDK_ROOT=${ANDROID_HOME} +export PATH=${ANDROID_HOME}/cmdline-tools/tools/bin:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools:${PATH} + +curl -Lo /tmp/sdk-tools.zip 'https://dl.google.com/android/repository/commandlinetools-linux-6609375_latest.zip' +mkdir -p ${ANDROID_SDK_ROOT}/cmdline-tools +unzip -q /tmp/sdk-tools.zip -d ${ANDROID_SDK_ROOT}/cmdline-tools +rm -f /tmp/sdk-tools.zip + +yes | sdkmanager --licenses +sdkmanager --verbose "platforms;${SDK_PLATFORM}" "build-tools;${SDK_BUILD_TOOLS}" "ndk;${NDK_VERSION}" ${SDK_PACKAGES} +sdkmanager --uninstall --verbose emulator +``` + +### Install the Service + +Clone this repository on a server that shall provide the service, +create a virtual environment, and install the requirements. + +```sh +git clone https://invent.kde.org/sysadmin/ci-notary-service.git apksigner +cd apksigner +python3 -m venv .venv +. .venv/bin/activate +pip3 install -r requirements.txt +``` + +### Configure the Service + +Copy `apksigner.sample.ini` to `apksigner.ini` and replace the example values +with the appropriate values for your installation. + +Then copy `apksigner-projects.sample.yaml` to `apksigner-projects.yaml` and +specify the settings for the projects you want to sign APKs for. + +## Run the Service + +Activate the virtual environment and start `apksigner.py`. + +```sh +cd ~/apksigner +. .venv/bin/activate +python3 apksigner.py --id workerA --config apksigner.ini +``` + +where you replace `workerA` with a unique alpha-numeric ID for each instance +of `apksigner.py` you start. + +## Use the Service to Sign an APK + +Clone this repository on the client, create a virtual environment, and install +the requirements. + +```sh +git clone https://invent.kde.org/sysadmin/ci-notary-service.git apksigner +cd apksigner +python3 -m venv .venv +. .venv/bin/activate +pip3 install -r requirements.txt +``` + +Copy `signapk.sample.ini` to `signapk.ini` and replace the example values +with the appropriate values for your installation. In particular, the value +for `BasePath` must match the corresponding value in the settings of the +service. + +Then run `signapk.py` to sign the APK + +```sh +python3 signapk.py --config signapk.ini +``` + +## Managing the Service with systemd + +We set up the service under the user's control with a per-user systemd instance. + +Copy `apksigner-user.sample.service` to `~/.config/systemd/user/apksigner-user.service` +and modify it as needed. The example uses the username as ID of the service +worker. Make sure that the ID is unique if you run multiple service workers. + +Start the service with + +```sh +systemctl --user start apksigner-user.service +``` + +If you want the service to be started automatically, then enable autostart with + +```sh +systemctl --user enable apksigner-user.service +``` + +Note: By default, the systemd user instance and thus the user-managed services are +started after the first login of a user and killed after the last session of the +user is closed. To start the user instance right after boot, and keep the systemd +user instance running after the last session closes you have to enable lingering +for the user: + +```sh +loginctl enable-linger USERNAME +``` + +For more details on user-managed services see https://wiki.archlinux.org/title/Systemd/User. + +## Running the Service with KDE's Android Docker Image + +We assume that you have already created a suitable `apksigner.ini` and +`apksigner-projects.yaml` and put them in the working copy of this repository. + +The correct values for `apksigner.ini` for KDE's Android Docker image are + +```ini +[ApkSigning] +KeyStore = /keystore.jks +KeyStorePass = file:/keystorepass +SDKToolsPath = /opt/android-sdk/build-tools/30.0.2 +APKAnalyzerPath = /opt/android-sdk/cmdline-tools/tools/bin/apkanalyzer + +[General] +ProjectSettings = apksigner-projects.yaml +``` + +Start a Docker container from inside the working copy of this repository +passing in the working copy, the `known_hosts` file, the files with the KeyStore +and the password to unlock the KeyStore, and the socket of the SSH agent: + +```sh +docker run -it --rm \ + -v $(pwd):/apksigner \ + -v :/home/user/.ssh/known_hosts \ + -v :/keystore.jks -v :/keystorepass \ + -v $SSH_AUTH_SOCK:/ssh-agent --env SSH_AUTH_SOCK=/ssh-agent \ + invent-registry.kde.org/sysadmin/ci-images/android-qt515 +``` + +Then inside the container run: + +```sh +python3 -m venv ~/.venv +. ~/.venv/bin/activate +cd /apksigner +pip3 install -r requirements.txt +python3 apksigner.py --id workerA --config apksigner.ini +``` + +### Details + +To protect the private SSH key we forward the SSH agent into the Docker container. +Alternatively, you can mount a file holding a private OpenSSH RSA key into the +container. diff --git a/third_party/ci-notary-service/doc/apksigner.sample.ini b/third_party/ci-notary-service/doc/apksigner.sample.ini new file mode 100644 index 0000000..d79da75 --- /dev/null +++ b/third_party/ci-notary-service/doc/apksigner.sample.ini @@ -0,0 +1,44 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +[Authentication] +Enabled = true +GitLabAPIv4Url = https://gitlab.example.net/api/v4 + +[ApkSigning] +# the KeyStore file to use; overridden by project settings +KeyStore = ~/.local/share/apksigner/keystore.jks +# the password for the KeyStore file; overridden by project settings +KeyStorePass = file:~/.local/share/apksigner/keystorepass +# the path containing apksigner and zipalign +SDKToolsPath = /opt/android-sdk/build-tools/30.0.2 +# the path of apkanalyzer +APKAnalyzerPath = /opt/android-sdk/cmdline-tools/tools/bin/apkanalyzer + +[General] +ProjectSettings = ~/.local/share/apksigner/apksigner-projects.yaml + +[Logging] +# Optionally, write log output to a file +#LogFile = ~/.cache/apksigner/apksigner.log + +[SFTP] +# SFTP server to use +Server = sftp.example.net +# Port to connect to +#Port = 2222 +# User to connect with +Username = sftpnotary +# (Sub)directory on the server used for this service +BasePath = apksigner + +# File with known host keys to prevent connection to unknown servers; +# if not specified, then the system host keys are used and missing host keys +# are accepted automatically +#KnownHostsFile = ~/.local/share/apksigner/known_hosts + +# File with the private OpenSSH RSA key to use for login +#RsaKeyFile = ~/.ssh/id_rsa +# or name of environment variable with private OpenSSH RSA key to use for login +#RsaKeyFile = env:ENVIRONMENT_VARIABLE +# if no key is specified, then the SSH agent is used diff --git a/third_party/ci-notary-service/doc/buildpublisher-projects.sample.yaml b/third_party/ci-notary-service/doc/buildpublisher-projects.sample.yaml new file mode 100644 index 0000000..fc55579 --- /dev/null +++ b/third_party/ci-notary-service/doc/buildpublisher-projects.sample.yaml @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 Ben Cooksley + +# define defaults for all listed projects +defaults: + # template used to construct the destination that rsync should be syncing to + rsyncDestination: "deploy@server.example.net:/var/www/cdn.example.net/nightlies/{projectPath}/{branch}/{platform}/" + +# Project we are allowing to be published +# key is the GitLab path of the project +group/projectname: + # dictionary of branches to performing publishing services for + branches: + master: + stable/2.0: diff --git a/third_party/ci-notary-service/doc/buildpublisher-user.sample.service b/third_party/ci-notary-service/doc/buildpublisher-user.sample.service new file mode 100644 index 0000000..79ca0c5 --- /dev/null +++ b/third_party/ci-notary-service/doc/buildpublisher-user.sample.service @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileCopyrightText: 2023 Ben Cooksley + +[Unit] +Description=buildpublisher +After=syslog.target network.target + +[Service] +Type=exec +WorkingDirectory=%h/buildpublisher +Environment="PATH=%h/buildpublisher/.venv/bin:/usr/local/bin:/usr/bin:/bin" +ExecStart=%h/buildpublisher/.venv/bin/python buildpublisher.py -vv --id %u --config %h/.config/buildpublisher.ini +Restart=on-failure +# avoid too many restarts in a short time span if starting the service fails +# because the SFTP server is temporarily unavailable +RestartSec=5s + +[Install] +WantedBy=default.target diff --git a/third_party/ci-notary-service/doc/buildpublisher.sample.ini b/third_party/ci-notary-service/doc/buildpublisher.sample.ini new file mode 100644 index 0000000..32ad9dd --- /dev/null +++ b/third_party/ci-notary-service/doc/buildpublisher.sample.ini @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileCopyrightText: 2023 Ben Cooksley + +[Authentication] +Enabled = true +GitLabAPIv4Url = https://gitlab.example.net/api/v4 + +[General] +ProjectSettings = ~/.local/buildpublisher/buildpublisher-projects.yaml + +[Logging] +# Optionally, write log output to a file +#LogFile = ~/.cache/buildpublisher.log + +[SFTP] +# SFTP server to use +Server = sftp.example.net +# Port to connect to +#Port = 2222 +# User to connect with +Username = sftpnotary +# (Sub)directory on the server used for tasks for this service +BasePath = buildpublisher + +# File with known host keys to prevent connection to unknown servers; +# if not specified, then the system host keys are used and missing host keys +# are accepted automatically +#KnownHostsFile = ~/.local/buildpublisher/known_hosts + +# File with the private OpenSSH RSA key to use for login +#RsaKeyFile = ~/.local/websitepublisher/ssh_key +# or name of environment variable with private OpenSSH RSA key to use for login +#RsaKeyFile = env:ENVIRONMENT_VARIABLE +# if no key is specified, then the SSH agent is used diff --git a/third_party/ci-notary-service/doc/details.md b/third_party/ci-notary-service/doc/details.md new file mode 100644 index 0000000..43254f4 --- /dev/null +++ b/third_party/ci-notary-service/doc/details.md @@ -0,0 +1,90 @@ + + +# Technical Details + +## Architecture + +Each service consists of a client script, a service script, and a Python +module implementing the details of the service. The client script uploads +requests and related data (e.g. an APK to sign) to an SFTP server. Then it +watches the SFTP server for the response by the service. The service watches +the SFTP server for incoming requests. If a request is found then the service +downloads the request, processes it, and uploads the result to the SFTP server. +Below, the task workflow is described in more detail. + +### Clients + +The client scripts connect to the SFTP server and start a service-specific `Job`. +Then they wait for the job to complete. But before they do any of this they +check if the project branch the client script runs for is allowed to use the +service. Typically, a service can only be used for the master branch and release +branches. If the script runs for a project branch that's not cleared then the script +exits with success, so that the CI system doesn't consider the CI job failed. + +The `Job` subclass adds a new task to the task queue and uploads a `Request` +describing the task and the files to process. When the task is completed, the +`Job` downloads the `Response` and, if applicable, the processed files. Moreover, +it downloads the logs captured by the service while processing the task. + +### Services + +The server scripts connect to the SFTP server and start a service-specific `Worker`. +Usually, the service-specific `Worker` subclass just defines the `TaskProcessor` to use. + +The common `Worker` class watches the task queue (on the SFTP server) for +incoming tasks and creates a service-specific `TaskProcessor` to process the task. +After verifying that the task `Request` is legitimate (i.e. that it was submitted +by a CI job running for an allowed project branch) the `TaskProcessor` base class +calls the service-specific `TaskProcessor` subclass to process the `Request`, +e.g. `SignApkProcessor` downloads an APK from the SFTP server, signs it and uploads the signed APK +to the SFTP server. Any log output produced by the `TaskProcessor` is captured +and also uploaded to the SFTP server. + +## Task Workflow + +For each kind of task, e.g. signing of APKs, signing of APPXs, etc., a base folder +exists on an SFTP server. Each base folder contains the following subfolders + +- `tmp` +- `queue` +- `processing-` for each worker where `worker ID` is a unique alpha-numeric ID +- `done` +- `trash` + +For each task a folder containing the needed data and meta-data moves from one of those +stage folders to the next one. The naming scheme for the task folders is +`-`, e.g. 20230516T132050-pim-itinerary_1515327. +The leading timestamp allows sorting the tasks by creation time. The client ID which +is built from the project path slug (CI_PROJECT_PATH_SLUG) and the job ID (CI_JOB_ID) +avoids collisions. + +### Task Stages + +#### Creating a new task + +Clients create a new task folder in `tmp` and upload all necessary data to the +task folder. Then they commit the task by moving it from `tmp` to `queue`. + +#### Processing the task queue + +One or more workers watch (poll) `queue` for new task folders. When they see a task folder, +they try to take it by moving it to their `processing-*` folder. If they successfully +took the task, they process the task, i.e. they download the data, process the +data (e.g. by signing it), and upload the results. Then they set the task to done +by moving it from their `processing-*` folder to `done`. + +#### Retrieving the results + +The client watches (polls) the `done` folder for its task folder. When the task +folder is found, they download the results. Then they remove the task which +currently moves the task folder from `done` to `trash`. + +## Cleanup + +Whenever a task completes processing, the services remove old task folders from the above +subfolders of the base folder. Additionally, old tasks are removed when a service +is (re)started. diff --git a/third_party/ci-notary-service/doc/fdroidpublisher-projects.sample.yaml b/third_party/ci-notary-service/doc/fdroidpublisher-projects.sample.yaml new file mode 100644 index 0000000..cb57f05 --- /dev/null +++ b/third_party/ci-notary-service/doc/fdroidpublisher-projects.sample.yaml @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +# define defaults for all listed projects +defaults: + # default name of the F-Droid repository for the APKs + repository: nightly + # list of branches cleared for publishing of APKs for all listed projects + branches: + - master + +# define settings specific for Project A (in Namespace A) +# key for Project A is the GitLab path of the project +namespace-a/project-a: + # the application ID of the APK; checked against the APK to publish + applicationid: net.example.projecta + # dictionary of additional branches cleared for publishing of APKs + branches: + # also allow publishing APKs from the release branch for Project A + release: + # name of the repository for the APKs from the release branch of this project + repository: stable-releases diff --git a/third_party/ci-notary-service/doc/fdroidpublisher-user.sample.service b/third_party/ci-notary-service/doc/fdroidpublisher-user.sample.service new file mode 100644 index 0000000..ae83d80 --- /dev/null +++ b/third_party/ci-notary-service/doc/fdroidpublisher-user.sample.service @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +[Unit] +Description=fdroidpublisher +After=syslog.target network.target + +[Service] +Type=exec +WorkingDirectory=%h/fdroidpublisher +Environment="PATH=%h/fdroidpublisher/.venv/bin:/usr/local/bin:/usr/bin:/bin" +ExecStart=%h/fdroidpublisher/.venv/bin/python fdroidpublisher.py -vv --id %u --config %h/.config/fdroidpublisher.ini +Restart=on-failure +# avoid too many restarts in a short time span if starting the service fails +# because the SFTP server is temporarily unavailable +RestartSec=5s + +[Install] +WantedBy=default.target diff --git a/third_party/ci-notary-service/doc/fdroidpublisher.md b/third_party/ci-notary-service/doc/fdroidpublisher.md new file mode 100644 index 0000000..89fbca6 --- /dev/null +++ b/third_party/ci-notary-service/doc/fdroidpublisher.md @@ -0,0 +1,153 @@ + + +# fdroidpublisher.py - An F-Droid Publishing Service + +This services publishs APKs in F-Droid repositories. + +## Prerequisites + +The service needs an SFTP server for exchanging data with the clients. + +## Installation + +### Install an Android SDK + +`fdroidpublisher.py` and the [fdroidserver](https://gitlab.com/fdroid/fdroidserver) +tools need the tools `apksigner` and `apkanalyzer` from an Android SDK. +The following instructions are based on the installation of +the Android SDK in KDE's Android Docker image. See below for an alternative +setup using KDE's Android Docker image. + +```sh +export NDK_VERSION=22.1.7171670 +export SDK_PLATFORM=android-33 +export SDK_BUILD_TOOLS=30.0.3 +export SDK_PACKAGES="tools platform-tools" + +export ANDROID_HOME=~/android-sdk +export ANDROID_SDK_ROOT=${ANDROID_HOME} +export PATH=${ANDROID_HOME}/cmdline-tools/tools/bin:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools:${PATH} + +curl -Lo /tmp/sdk-tools.zip 'https://dl.google.com/android/repository/commandlinetools-linux-6609375_latest.zip' +mkdir -p ${ANDROID_SDK_ROOT}/cmdline-tools +unzip -q /tmp/sdk-tools.zip -d ${ANDROID_SDK_ROOT}/cmdline-tools +rm -f /tmp/sdk-tools.zip + +yes | sdkmanager --licenses +sdkmanager --verbose "platforms;${SDK_PLATFORM}" "build-tools;${SDK_BUILD_TOOLS}" "ndk;${NDK_VERSION}" ${SDK_PACKAGES} +sdkmanager --uninstall --verbose emulator +``` + +### Install the Service + +Clone this repository on a server that shall provide the service, +create a virtual environment, and install the requirements. + +```sh +git clone https://invent.kde.org/sysadmin/ci-notary-service.git fdroidpublisher +cd fdroidpublisher +python3 -m venv .venv +. .venv/bin/activate +pip3 install -r requirements_fdroid.txt +``` + +### Configure the Service + +Copy `fdroidpublisher.sample.ini` to `fdroidpublisher.ini` and replace the example values +with the appropriate values for your installation. + +Then copy `fdroidpublisher-projects.sample.yaml` to `fdroidpublisher-projects.yaml` and +specify the settings for the projects you want to publish APKs for. + +### Set up an F-Droid App Repo + +Very brief list of commands to run: + +```sh +export ANDROID_HOME=~/android-sdk + +mkdir -p .../fdroid-repos/nightly/fdroid +cd .../fdroid-repos/nightly/fdroid +fdroid init +``` + +Edit the `config.yml` file to your liking. In particular, set `serverwebroot`. + +For details read the official instructions to +[set up an F-Droid App Repo](https://f-droid.org/en/docs/Setup_an_F-Droid_App_Repo/). + +## Run the Service + +Activate the virtual environment and start `fdroidpublisher.py`. + +```sh +cd ~/fdroidpublisher +. .venv/bin/activate +python3 fdroidpublisher.py --id workerA --config fdroidpublisher.ini +``` + +where you replace `workerA` with a unique alpha-numeric ID for each instance +of `fdroidpublisher.py` you start. + +## Use the Service to Publish an APK + +Clone this repository on the client, create a virtual environment, and install +the requirements. + +```sh +git clone https://invent.kde.org/sysadmin/ci-notary-service.git fdroidpublisher +cd fdroidpublisher +python3 -m venv .venv +. .venv/bin/activate +pip3 install -r requirements.txt +``` + +Copy `publishonfdroid.sample.ini` to `publishonfdroid.ini` and replace the example values +with the appropriate values for your installation. In particular, the value +for `BasePath` must match the corresponding value in the settings of the +service. + +Then run `publishonfdroid.py` to publish a signed APK + +```sh +python3 publishonfdroid.py --config publishonfdroid.ini --fastlane ... +``` + +where `...` are the APKs you want to publish and `` is the +fastlane zip file containing the meta data for the APKs. + +## Manage the Service with systemd + +We set up the service under the user's control with a per-user systemd instance. + +Copy `fdroidpublisher-user.sample.service` to `~/.config/systemd/user/fdroidpublisher-user.service` +and modify it as needed. The example uses the username as ID of the service +worker. Make sure that the ID is unique if you run multiple service workers. + +Start the service with + +```sh +systemctl --user start fdroidpublisher-user.service +``` + +If you want the service to be started automatically, then enable autostart with + +```sh +systemctl --user enable fdroidpublisher-user.service +``` + +Note: By default, the systemd user instance and thus the user-managed services are +started after the first login of a user and killed after the last session of the +user is closed. To start the user instance right after boot, and keep the systemd +user instance running after the last session closes you have to enable lingering +for the user: + +```sh +loginctl enable-linger USERNAME +``` + +For more details on user-managed services see https://wiki.archlinux.org/title/Systemd/User. diff --git a/third_party/ci-notary-service/doc/fdroidpublisher.sample.ini b/third_party/ci-notary-service/doc/fdroidpublisher.sample.ini new file mode 100644 index 0000000..2c97995 --- /dev/null +++ b/third_party/ci-notary-service/doc/fdroidpublisher.sample.ini @@ -0,0 +1,52 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +[Authentication] +Enabled = true +GitLabAPIv4Url = https://gitlab.example.net/api/v4 + +[ApkSigning] +# the path containing apksigner +SDKToolsPath = /opt/android-sdk/build-tools/30.0.3 +# the path of apkanalyzer +APKAnalyzerPath = /opt/android-sdk/cmdline-tools/tools/bin/apkanalyzer + +[FDroidPublishing] +# common prefix for the local F-Droid repos +LocalRepoPrefix = ~/.local/share/fdroidpublisher/fdroid-repos + +[FDroidRepository nightly] +# maximum age of APKs published in this repository; older APKs will be removed +Expiry = 60 + +[FDroidRepository stable-releases] +# maximum age of APKs published in this repository; older APKs will be removed +Expiry = 365 + +[General] +ProjectSettings = ~/.local/share/fdroidpublisher/fdroidpublisher-projects.yaml + +[Logging] +# Optionally, write log output to a file +#LogFile = ~/.cache/fdroidpublisher/fdroidpublisher.log + +[SFTP] +# SFTP server to use +Server = sftp.example.net +# Port to connect to +#Port = 2222 +# User to connect with +Username = sftpnotary +# (Sub)directory on the server used for tasks for this service +BasePath = fdroidpublisher + +# File with known host keys to prevent connection to unknown servers; +# if not specified, then the system host keys are used and missing host keys +# are accepted automatically +#KnownHostsFile = ~/.local/share/fdroidpublisher/known_hosts + +# File with the private OpenSSH RSA key to use for login +#RsaKeyFile = ~/.ssh/id_rsa +# or name of environment variable with private OpenSSH RSA key to use for login +#RsaKeyFile = env:ENVIRONMENT_VARIABLE +# if no key is specified, then the SSH agent is used diff --git a/third_party/ci-notary-service/doc/flatpaksigner-projects.sample.yaml b/third_party/ci-notary-service/doc/flatpaksigner-projects.sample.yaml new file mode 100644 index 0000000..c58e1a6 --- /dev/null +++ b/third_party/ci-notary-service/doc/flatpaksigner-projects.sample.yaml @@ -0,0 +1,41 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +# define defaults for all listed projects +defaults: + # name of the repository for the signed flatpaks + repository: flatpaks + # fingerprint of the OpenPGP key to use by default + signingkey: 0123456789ABCDEF0123456789ABCDEF01234567 + # runtime repo path (for .flatpakref) to use by default + runtimerepourl: https://dl.flathub.org/repo/flathub.flatpakrepo + # list of branches to sign for all listed projects + branches: + - master + +# define settings specific for Project A (in Namespace A) +# key for Project A is the GitLab path of the project +namespace-a/project-a: + # the application ID of the flatpak; checked against the flatpak to sign + applicationid: net.example.projecta + # name of the repository for the signed flatpaks of this project + repository: flatpaks.projecta + # dictionary of branches to sign additionally to the default branches + branches: + # also allow signing the release branch for Project A + release: + # name of the repository for the signed flatpaks of the release branch of this project + repository: flatpaks.stable.projecta + # use a different runtime repo path too + runtimerepourl: https://example.otg/repo/example.flatpakrepo + +namespace-a/project-b: + # multiple application IDs per project are possible; all apps are added to + # the same repo + applicationid: + - net.example.Platform + - net.example.Sdk + # use a different signing key for Project B + signingkey: DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF + # this is a flatpak runtime (relavant for .flatpakref), default is false + isruntime: true diff --git a/third_party/ci-notary-service/doc/flatpaksigner-user.sample.service b/third_party/ci-notary-service/doc/flatpaksigner-user.sample.service new file mode 100644 index 0000000..a0885c8 --- /dev/null +++ b/third_party/ci-notary-service/doc/flatpaksigner-user.sample.service @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +[Unit] +Description=flatpaksigner +After=syslog.target network.target + +[Service] +Type=exec +WorkingDirectory=%h/flatpaksigner +Environment="PATH=%h/flatpaksigner/.venv/bin:/usr/local/bin:/usr/bin:/bin" +ExecStart=%h/flatpaksigner/.venv/bin/python flatpaksigner.py -vv --id %u --config %h/.config/flatpaksigner.ini +Restart=on-failure +# avoid too many restarts in a short time span if starting the service fails +# because the SFTP server is temporarily unavailable +RestartSec=5s + +[Install] +WantedBy=default.target diff --git a/third_party/ci-notary-service/doc/flatpaksigner.md b/third_party/ci-notary-service/doc/flatpaksigner.md new file mode 100644 index 0000000..9ee472b --- /dev/null +++ b/third_party/ci-notary-service/doc/flatpaksigner.md @@ -0,0 +1,151 @@ + + +# flatpaksigner.py - A Flatpak Signing and Publishing Service + +This service takes a Flatpak bundle file and adds it to a remote repository +signing the commits. The remote repository is fetched and re-uploaded with +rsync. + +## Prerequisites + +The service needs an SFTP server for exchanging data with the clients. + +For signing the commits you need a private OpenPGP key. No password must be +required for using the key, i.e. either the private key is not protected with +a password or the private key is preloaded in gpg-agent. + +Additionally, the following tools must be available in the path: + +- `flatpak` +- `rsync` +- `ostree` - used for creating a new repo + +## Installation + +### Install the Service + +Clone this repository on a server that shall provide the service, +create a virtual environment, and install the requirements. + +```sh +git clone https://invent.kde.org/sysadmin/ci-notary-service.git flatpaksigner +cd flatpaksigner +python3 -m venv .venv +. .venv/bin/activate +pip3 install -r requirements.txt +``` + +### Configure the Service + +Copy `flatpaksigner.sample.ini` to `flatpaksigner.ini` and replace the example values +with the appropriate values for your installation. + +Then copy `flatpaksigner-projects.sample.yaml` to `flatpaksigner-projects.yaml` and +specify the settings for the projects you want to use service for. + +Create a signing key for the repository, e.g. use + +```sh +gpg --quick-gen-key "My Flatpak Repo Signing Key " default default never +``` + +to create a key with default algorithm and usage that doesn't expire. When asked +for a passphrase press Return and confirm that you do not want to protect the key +with a passphrase. This has to be done twice because two key pairs are generated. +You should get output like this: + +``` +gpg: revocation certificate stored as '~/.gnupg/openpgp-revocs.d/A8C4AA3035D600F41C5240DAE27DF85D87A8FD63.rev' +public and secret key created and signed. + +pub ed25519 2023-12-07 [SC] + A8C4AA3035D600F41C5240DAE27DF85D87A8FD63 +uid My Flatpak Repo Signing Key +sub cv25519 2023-12-07 [E] +``` + +Add the fingerprint of the signing key to the `flatpaksigner-projects.yaml`. +Then export the public key of the signing key to a file, e.g. with + +```sh +gpg --export A8C4AA3035D600F41C5240DAE27DF85D87A8FD63 >~/repo_keys/A8C4AA3035D600F41C5240DAE27DF85D87A8FD63.gpg +``` + +where `~/repo_keys/` is the location you specified as `RepoKeysLocation` in +`flatpaksigner.ini`. The service will use the public key when it generates +`.flatpakref` files for the signed and published applications. + +## Run the Service + +Activate the virtual environment and start `flatpaksigner.py`. + +```sh +cd ~/flatpaksigner +. .venv/bin/activate +python3 flatpaksigner.py --id workerA --config flatpaksigner.ini +``` + +where you replace `workerA` with a unique alpha-numeric ID for each instance +of `flatpaksigner.py` you start. You can run multiple instances, but the +behavior is undefined if multiple instances operate on the same repository. +Therefore, it's recommended to run only one service per repository. + +## Use the Service to Sign and Publish a Flatpak Bundle + +Clone this repository on the client, create a virtual environment, and install +the requirements. + +```sh +git clone https://invent.kde.org/sysadmin/ci-notary-service.git flatpaksigner +cd flatpaksigner +python3 -m venv .venv +. .venv/bin/activate +pip3 install -r requirements.txt +``` + +Copy `signflatpak.sample.ini` to `signflatpak.ini` and replace the example values +with the appropriate values for your installation. In particular, the value +for `BasePath` must match the corresponding value in the settings of the +service. + +Then run `signflatpak.py` to sign and publish the Flatpak bundle + +```sh +python3 signflatpak.py --config signflatpak.ini +``` + +## Manage the Service with systemd + +We set up the service under the user's control with a per-user systemd instance. + +Copy `flatpaksigner-user.sample.service` to `~/.config/systemd/user/flatpaksigner-user.service` +and modify it as needed. The example uses the username as ID of the service +worker. Make sure that the ID is unique if you run multiple service workers. + +Start the service with + +```sh +systemctl --user start flatpaksigner-user.service +``` + +If you want the service to be started automatically, then enable autostart with + +```sh +systemctl --user enable flatpaksigner-user.service +``` + +Note: By default, the systemd user instance and thus the user-managed services are +started after the first login of a user and killed after the last session of the +user is closed. To start the user instance right after boot, and keep the systemd +user instance running after the last session closes you have to enable lingering +for the user: + +```sh +loginctl enable-linger USERNAME +``` + +For more details on user-managed services see https://wiki.archlinux.org/title/Systemd/User. diff --git a/third_party/ci-notary-service/doc/flatpaksigner.sample.ini b/third_party/ci-notary-service/doc/flatpaksigner.sample.ini new file mode 100644 index 0000000..7800cdd --- /dev/null +++ b/third_party/ci-notary-service/doc/flatpaksigner.sample.ini @@ -0,0 +1,44 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +[Authentication] +Enabled = true +GitLabAPIv4Url = https://gitlab.example.net/api/v4 + +[FlatpakSigning] +# common prefix for application repos +RemoteRepoPrefix = flatpak@flatpak.example.net:/srv/www/flatpaks.example.net/ +# common prefix for the URL for application repos +RepoURLPrefix = https://flatpaks.example.net/ +# location containing the exported public signing keys named .gpg +RepoKeysLocation = ~/repo_keys/ +# URL to a SVG icon used by the *.flatpakrepo file +RepoIconFile = ~/flatpak/somelogo.svg + +[General] +ProjectSettings = ~/.local/flatpaksigner/flatpaksigner-projects.yaml + +[Logging] +# Optionally, write log output to a file +#LogFile = ~/.cache/flatpaksigner.log + +[SFTP] +# SFTP server to use +Server = sftp.example.net +# Port to connect to +#Port = 2222 +# User to connect with +Username = sftpnotary +# (Sub)directory on the server used for tasks for this service +BasePath = flatpaksigner + +# File with known host keys to prevent connection to unknown servers; +# if not specified, then the system host keys are used and missing host keys +# are accepted automatically +#KnownHostsFile = ~/.local/share/flatpaksigner/known_hosts + +# File with the private OpenSSH RSA key to use for login +#RsaKeyFile = ~/.ssh/id_rsa +# or name of environment variable with private OpenSSH RSA key to use for login +#RsaKeyFile = env:ENVIRONMENT_VARIABLE +# if no key is specified, then the SSH agent is used diff --git a/third_party/ci-notary-service/doc/googleplaypublisher-projects.sample.yaml b/third_party/ci-notary-service/doc/googleplaypublisher-projects.sample.yaml new file mode 100644 index 0000000..026f704 --- /dev/null +++ b/third_party/ci-notary-service/doc/googleplaypublisher-projects.sample.yaml @@ -0,0 +1,37 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +# define defaults for all listed projects +defaults: + # the KeyStore file containing the (upload) key used for signing AABs + uploadkeystore: ~/.credentials/keystore-for-google-play-upload.jks + # the password for the KeyStore file; prefer the "file:" format + uploadkeystorepass: file:~/.credentials/keystore-for-google-play-upload.pass + # the alias of the (upload) key used for signing AABs + uploadkeyalias: google-play-upload-key + # list of branches cleared for publishing of AABs and APKs for all listed projects + branches: [] + +# define settings specific for Project A (in Namespace A) +# key for Project A is the GitLab path of the project +namespace-a/project-a: + # the application ID of the APK; checked against the APK to publish + applicationid: net.example.projecta + # dictionary of additional branches cleared for publishing of APKs + branches: + # allow publishing APKs from the release branch for Project A + release: + +namespace-a/project-b: + # the application ID of the APK + applicationid: net.example.projectb + # keys for signing AABs for Project B are stored in a different KeyStore file + uploadkeystore: ~/.credentials/projectb.jks + # the keys are protected with another password + uploadkeystorepass: file:~/.credentials/projectb.pass + # and the key used for signing AABs has another alias + uploadkeyalias: projectb-upload-key + branches: + # use a different KeyStore for the legacy branch of Project B + legacy: + uploadkeystore: ~/.credentials/projectb/legacy.jks diff --git a/third_party/ci-notary-service/doc/googleplaypublisher-user.sample.service b/third_party/ci-notary-service/doc/googleplaypublisher-user.sample.service new file mode 100644 index 0000000..479b63f --- /dev/null +++ b/third_party/ci-notary-service/doc/googleplaypublisher-user.sample.service @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +[Unit] +Description=googleplaypublisher +After=syslog.target network.target + +[Service] +Type=exec +WorkingDirectory=%h/googleplaypublisher +Environment="PATH=%h/googleplaypublisher/.venv/bin:/usr/local/bin:/usr/bin:/bin" +ExecStart=%h/googleplaypublisher/.venv/bin/python googleplaypublisher.py -vv --id %u --config %h/.config/googleplaypublisher.ini +Restart=on-failure +# avoid too many restarts in a short time span if starting the service fails +# because the SFTP server is temporarily unavailable +RestartSec=5s + +[Install] +WantedBy=default.target diff --git a/third_party/ci-notary-service/doc/googleplaypublisher.md b/third_party/ci-notary-service/doc/googleplaypublisher.md new file mode 100644 index 0000000..7be4d68 --- /dev/null +++ b/third_party/ci-notary-service/doc/googleplaypublisher.md @@ -0,0 +1,190 @@ + + +# googleplaypublisher.py - A Google Play Publishing Service + +This services publishs AABs and APKs in Google Play. + +## Prerequisites + +The service needs an SFTP server for exchanging data with the clients. + +## Installation + +### Install an Android SDK + +`googleplaypublisher.py` need the `apkanalyzer` tool from an Android SDK. +The following instructions are based on the installation of +the Android SDK in KDE's Android Docker image. + +```sh +export NDK_VERSION=22.1.7171670 +export SDK_PLATFORM=android-33 +export SDK_BUILD_TOOLS=30.0.3 +export SDK_PACKAGES="tools platform-tools" + +export ANDROID_HOME=~/android-sdk +export ANDROID_SDK_ROOT=${ANDROID_HOME} +export PATH=${ANDROID_HOME}/cmdline-tools/tools/bin:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools:${PATH} + +curl -Lo /tmp/sdk-tools.zip 'https://dl.google.com/android/repository/commandlinetools-linux-6609375_latest.zip' +mkdir -p ${ANDROID_SDK_ROOT}/cmdline-tools +unzip -q /tmp/sdk-tools.zip -d ${ANDROID_SDK_ROOT}/cmdline-tools +rm -f /tmp/sdk-tools.zip + +yes | sdkmanager --licenses +sdkmanager --verbose "platforms;${SDK_PLATFORM}" "build-tools;${SDK_BUILD_TOOLS}" "ndk;${NDK_VERSION}" ${SDK_PACKAGES} +sdkmanager --uninstall --verbose emulator +``` + +### Install Fastlane Supply + +This service uses [Fastlane](https://docs.fastlane.tools) +for interaction with Google Play. + +```sh +# writeable base directory +FASTLANE_INSTALL_PREFIX=~ +# install location for the fastlane tool +FASTLANE_DIR=$FASTLANE_INSTALL_PREFIX/fastlane +# executable name of Ruby Bundler +BUNDLE_EXECUTABLE=bundle3.0 + +# setup bundler to no try to install things in the global prefix +export BUNDLE_EXECUTABLE +export BUNDLE_PATH=$FASTLANE_INSTALL_PREFIX/vendor/bundle +export BUNDLE_APP_CONFIG=$FASTLANE_INSTALL_PREFIX/.bundle +$BUNDLE_EXECUTABLE config set --local path $BUNDLE_PATH + +# install/update fastlane +mkdir -p $FASTLANE_DIR +pushd $FASTLANE_DIR + +cat >Gemfile < ... +``` + +where `...` is the AAB or the APKs you want to publish and `` is the +fastlane zip file containing the meta data for the app. + +## Manage the Service with systemd + +We set up the service under the user's control with a per-user systemd instance. + +Copy `googleplaypublisher-user.sample.service` to `~/.config/systemd/user/googleplaypublisher-user.service` +and modify it as needed. The example uses the username as ID of the service +worker. Make sure that the ID is unique if you run multiple service workers. + +Start the service with + +```sh +systemctl --user start googleplaypublisher-user.service +``` + +If you want the service to be started automatically, then enable autostart with + +```sh +systemctl --user enable googleplaypublisher-user.service +``` + +Note: By default, the systemd user instance and thus the user-managed services are +started after the first login of a user and killed after the last session of the +user is closed. To start the user instance right after boot, and keep the systemd +user instance running after the last session closes you have to enable lingering +for the user: + +```sh +loginctl enable-linger USERNAME +``` + +For more details on user-managed services see https://wiki.archlinux.org/title/Systemd/User. + +## Trouble Shooting + +The following lists errors that occurred when trying to publish a new app on Google Play. + +### Downloading existing metadata fails with `undefined method 'name' for nil:NilClass` in `block in latest_version` + +This happens if there is no release in the production track. As workaround one can +create a production release but save it as draft. If you already created a release +in another track then you can promote this release to the production track. It is +automatically saved as draft when you promote it. + +### Uploading metadata fails with `undefined method 'flat_map' for nil:NilClass` in `track_version_codes` + +This happens if there is no release in the beta (aka Open Testing) track. As workaround one can +create a beta release but save it as draft. If you already created a release +in another testing track then you can promote this release to the beta track. It is +automatically saved as draft when you promote it. diff --git a/third_party/ci-notary-service/doc/googleplaypublisher.sample.ini b/third_party/ci-notary-service/doc/googleplaypublisher.sample.ini new file mode 100644 index 0000000..69f9828 --- /dev/null +++ b/third_party/ci-notary-service/doc/googleplaypublisher.sample.ini @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +[Authentication] +Enabled = true +GitLabAPIv4Url = https://gitlab.example.net/api/v4 + +[ApkSigning] +# the path of apkanalyzer +APKAnalyzerPath = /opt/android-sdk/cmdline-tools/tools/bin/apkanalyzer +# the path of the bundletool jar file (used when publishing AABs) +BundletoolJarPath = /opt/bundletool/bundletool-all-1.15.6.jar + +[GooglePlayPublishing] +# location where you put the Gemfile to install fastlane +FastlaneDirectory = ~/fastlane +# location where the service will put its data +FastlaneWorkingDirectory = ~/work +# JSON file containing the credentials for Google Play +Credentials = ~/keys/play-store-credentials.json +# executable name of Ruby Bundler +BundleExecutable = bundle3.0 +# location for Ruby bundles +BundlePath = ~/vendor/bundle +BundleAppConfig = ~/.bundle + +# the path of jarsigner (used for signing the AABs to publish) +JarsignerPath = /usr/bin/jarsigner +# the KeyStore file containing the (upload) key used for signing AABs; overridden by project settings +UploadKeyStore = ~/.local/share/googleplaypublisher/keystore-for-google-play-upload.jks +# the password for the KeyStore file; overridden by project settings +UploadKeyStorePass = file:~/.local/share/googleplaypublisher/keystore-for-google-play-upload.pass +# the alias of the (upload) key used for signing AABs; overridden by project settings +UploadKeyAlias = google-play-upload-key + +[General] +ProjectSettings = ~/.local/share/googleplaypublisher/googleplaypublisher-projects.yaml + +[Logging] +# Optionally, write log output to a file +#LogFile = .../googleplaypublisher.log + +[SFTP] +# SFTP server to use +Server = sftp.example.net +# Port to connect to +#Port = 2222 +# User to connect with +Username = sftpnotary +# (Sub)directory on the server used for tasks for this service +BasePath = googleplaypublisher + +# File with known host keys to prevent connection to unknown servers; +# if not specified, then the system host keys are used and missing host keys +# are accepted automatically +#KnownHostsFile = ~/.local/share/googleplaypublisher/known_hosts + +# File with the private OpenSSH RSA key to use for login +#RsaKeyFile = ~/.ssh/id_rsa +# or name of environment variable with private OpenSSH RSA key to use for login +#RsaKeyFile = env:ENVIRONMENT_VARIABLE +# if no key is specified, then the SSH agent is used diff --git a/third_party/ci-notary-service/doc/macappnotarizer-projects.sample.yaml b/third_party/ci-notary-service/doc/macappnotarizer-projects.sample.yaml new file mode 100644 index 0000000..e192496 --- /dev/null +++ b/third_party/ci-notary-service/doc/macappnotarizer-projects.sample.yaml @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +# define defaults for all listed projects +defaults: + # list of branches to notarize for all listed projects + branches: + - master + +# define settings specific for Project A (in Namespace A) +# key for Project A is the GitLab path of the project +namespace-a/project-a: + # the application ID of the app; checked against the plist of the app to notarize + applicationid: net.example.projecta + # dictionary of branches to notarize additionally to the default branches + branches: + # also allow notarizing the release branch for Project A + release: + +namespace-a/project-b: + # the application ID of the app + applicationid: net.example.projectb + branches: + legacy: diff --git a/third_party/ci-notary-service/doc/macappnotarizer-user.sample.service b/third_party/ci-notary-service/doc/macappnotarizer-user.sample.service new file mode 100644 index 0000000..a487c44 --- /dev/null +++ b/third_party/ci-notary-service/doc/macappnotarizer-user.sample.service @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +[Unit] +Description=macappnotarizer +After=syslog.target network.target + +[Service] +Type=exec +WorkingDirectory=%h/macappnotarizer +Environment="PATH=%h/macappnotarizer/.venv/bin:/usr/local/bin:/usr/bin:/bin" +ExecStart=%h/macappnotarizer/.venv/bin/python macappnotarizer.py -vv --id %u --config %h/.config/macappnotarizer.ini +Restart=on-failure +# avoid too many restarts in a short time span if starting the service fails +# because the SFTP server is temporarily unavailable +RestartSec=5s + +[Install] +WantedBy=default.target diff --git a/third_party/ci-notary-service/doc/macappnotarizer.md b/third_party/ci-notary-service/doc/macappnotarizer.md new file mode 100644 index 0000000..1b40b36 --- /dev/null +++ b/third_party/ci-notary-service/doc/macappnotarizer.md @@ -0,0 +1,118 @@ + + +# macappnotarizer.py - A Notarizing Service for macOS apps + +Provides app notarization for macOS apps. + +`*.dmg` files can by signed directly, `*.app` files are rather special folders than real files and should be packed inside a tar archive for signing. + +## Prerequisites + +The service needs an SFTP server for exchanging data with the clients. + +Additionally, for signing your macOS app you need + +- if you want to notarize the app an App Store Connect API key + +## Installation + +### Install dependencies + +Install `rcodesign` as described here in the documentation: https://gregoryszorc.com/docs/apple-codesign/0.26.0/apple_codesign_getting_started.html#installing + +Install a recent version of `7zz` either from your distros package manager or from https://7-zip.org/download.html + +### Install the Service + +Clone this repository on a server that shall provide the service, +create a virtual environment, and install the requirements. + +```sh +git clone https://invent.kde.org/sysadmin/ci-notary-service.git macappnotarizer +cd macappnotarizer +python3 -m venv .venv +. .venv/bin/activate +pip3 install -r requirements.txt +``` + +### Configure the Service + +Copy `macappnotarizer.sample.ini` to `macappnotarizer.ini` and replace the example values +with the appropriate values for your installation. + +Then copy `macappnotarizer-projects.sample.yaml` to `macappnotarizer-projects.yaml` and +specify the settings for the projects you want to notarize apps for. + +## Run the Service + +Activate the virtual environment and start `macappnotarizer.py`. + +```sh +cd ~/macappnotarizer +. .venv/bin/activate +python3 macappnotarizer.py --id workerA --config macappnotarizer.ini +``` + +where you replace `workerA` with a unique alpha-numeric ID for each instance +of `macappnotarizer.py` you start. + +## Use the Service to Notarize a macOS App + +Clone this repository on the client, create a virtual environment, and install +the requirements. + +```sh +git clone https://invent.kde.org/sysadmin/ci-notary-service.git macappnotarizer +cd macappnotarizer +python3 -m venv .venv +. .venv/bin/activate +pip3 install -r requirements.txt +``` + +Copy `notarizemacapp.sample.ini` to `notarizemacapp.ini` and replace the example values +with the appropriate values for your installation. In particular, the value +for `BasePath` must match the corresponding value in the settings of the +service. + +Then run `notarizemacapp.py` to notarize the macOS app + +```sh +python3 notarizemacapp --config notarizemacapp.ini +``` + +## Managing the Service with systemd + +We set up the service under the user's control with a per-user systemd instance. + +Copy `macappnotarizer-user.sample.service` to `~/.config/systemd/user/macappnotarizer-user.service` +and modify it as needed. The example uses the username as ID of the service +worker. Make sure that the ID is unique if you run multiple service workers. + +Start the service with + +```sh +systemctl --user start macappnotarizer-user.service +``` + +If you want the service to be started automatically, then enable autostart with + +```sh +systemctl --user enable macappnotarizer-user.service +``` + +Note: By default, the systemd user instance and thus the user-managed services are +started after the first login of a user and killed after the last session of the +user is closed. To start the user instance right after boot, and keep the systemd +user instance running after the last session closes you have to enable lingering +for the user: + +```sh +loginctl enable-linger USERNAME +``` + +For more details on user-managed services see https://wiki.archlinux.org/title/Systemd/User. diff --git a/third_party/ci-notary-service/doc/macappnotarizer.sample.ini b/third_party/ci-notary-service/doc/macappnotarizer.sample.ini new file mode 100644 index 0000000..acbeabf --- /dev/null +++ b/third_party/ci-notary-service/doc/macappnotarizer.sample.ini @@ -0,0 +1,44 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +[Authentication] +Enabled = true +GitLabAPIv4Url = https://gitlab.example.net/api/v4 + +[AppleTools] +# the path to rcodesing +RCodesignPath = ~/.cargo/bin/rcodesign +# the path to a recent version of 7z +SevenZipPath = ~/some/path/7zz + +[MacAppNotarization] +# The api for notarization requests +ApiKey = file:~/.local/share/macappnotarizer/apikey.json + +[General] +ProjectSettings = ~/.local/share/macappnotarizer/macappnotarizer-projects.yaml + +[Logging] +# Optionally, write log output to a file +#LogFile = ~/.cache/macappnotarizer/macappnotarizer.log + +[SFTP] +# SFTP server to use +Server = sftp.example.net +# Port to connect to +#Port = 2222 +# User to connect with +Username = sftpnotary +# (Sub)directory on the server used for this service +BasePath = macappnotarizer + +# File with known host keys to prevent connection to unknown servers; +# if not specified, then the system host keys are used and missing host keys +# are accepted automatically +#KnownHostsFile = ~/.local/share/macappnotarizer/known_hosts + +# File with the private OpenSSH RSA key to use for login +#RsaKeyFile = ~/.ssh/id_rsa +# or name of environment variable with private OpenSSH RSA key to use for login +#RsaKeyFile = env:ENVIRONMENT_VARIABLE +# if no key is specified, then the SSH agent is used diff --git a/third_party/ci-notary-service/doc/macappsigner-projects.sample.yaml b/third_party/ci-notary-service/doc/macappsigner-projects.sample.yaml new file mode 100644 index 0000000..c192573 --- /dev/null +++ b/third_party/ci-notary-service/doc/macappsigner-projects.sample.yaml @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +# define defaults for all listed projects +defaults: + # list of branches to sign for all listed projects + branches: + - master + +# define settings specific for Project A (in Namespace A) +# key for Project A is the GitLab path of the project +namespace-a/project-a: + # the application ID of the app; checked against the plist of the app to sign + applicationid: net.example.projecta + # dictionary of branches to sign additionally to the default branches + branches: + # also allow signing the release branch for Project A + release: + +namespace-a/project-b: + # the application ID of the app + applicationid: net.example.projectb + branches: + legacy: diff --git a/third_party/ci-notary-service/doc/macappsigner-user.sample.service b/third_party/ci-notary-service/doc/macappsigner-user.sample.service new file mode 100644 index 0000000..5eaf870 --- /dev/null +++ b/third_party/ci-notary-service/doc/macappsigner-user.sample.service @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +[Unit] +Description=macappsigner +After=syslog.target network.target + +[Service] +Type=exec +WorkingDirectory=%h/macappsigner +Environment="PATH=%h/macappsigner/.venv/bin:/usr/local/bin:/usr/bin:/bin" +ExecStart=%h/macappsigner/.venv/bin/python macappsigner.py -vv --id %u --config %h/.config/macappsigner.ini +Restart=on-failure +# avoid too many restarts in a short time span if starting the service fails +# because the SFTP server is temporarily unavailable +RestartSec=5s + +[Install] +WantedBy=default.target diff --git a/third_party/ci-notary-service/doc/macappsigner.md b/third_party/ci-notary-service/doc/macappsigner.md new file mode 100644 index 0000000..2026c0a --- /dev/null +++ b/third_party/ci-notary-service/doc/macappsigner.md @@ -0,0 +1,119 @@ + + +# macappsigner.py - A Signing Service for macOS apps + +Provides code signing for macOS apps. + +`*.dmg` files can by signed directly, `*.app` files are rather special folders than real files and should be packed inside a tar archive for signing. + +## Prerequisites + +The service needs an SFTP server for exchanging data with the clients. + +Additionally, for signing your macOS app you need + +- a key store file containing the certificate to sign the app with, +- a file containing the password to unlock the key store. + +## Installation + +### Install dependencies + +Install `rcodesign` as described here in the documentation: https://gregoryszorc.com/docs/apple-codesign/0.26.0/apple_codesign_getting_started.html#installing + +Install a recent version of `7zz` either from your distros package manager or from https://7-zip.org/download.html + +### Install the Service + +Clone this repository on a server that shall provide the service, +create a virtual environment, and install the requirements. + +```sh +git clone https://invent.kde.org/sysadmin/ci-notary-service.git macappsigner +cd macappsigner +python3 -m venv .venv +. .venv/bin/activate +pip3 install -r requirements.txt +``` + +### Configure the Service + +Copy `macappsigner.sample.ini` to `macappsigner.ini` and replace the example values +with the appropriate values for your installation. + +Then copy `macappsigner-projects.sample.yaml` to `macappsigner-projects.yaml` and +specify the settings for the projects you want to sign apps for. + +## Run the Service + +Activate the virtual environment and start `macappsigner.py`. + +```sh +cd ~/macappsigner +. .venv/bin/activate +python3 macappsigner.py --id workerA --config macappsigner.ini +``` + +where you replace `workerA` with a unique alpha-numeric ID for each instance +of `macappsigner.py` you start. + +## Use the Service to Sign a macOS App + +Clone this repository on the client, create a virtual environment, and install +the requirements. + +```sh +git clone https://invent.kde.org/sysadmin/ci-notary-service.git macappsigner +cd macappsigner +python3 -m venv .venv +. .venv/bin/activate +pip3 install -r requirements.txt +``` + +Copy `signmacapp.sample.ini` to `signmacapp.ini` and replace the example values +with the appropriate values for your installation. In particular, the value +for `BasePath` must match the corresponding value in the settings of the +service. + +Then run `signmacapp.py` to sign the macOS app + +```sh +python3 signmacapp.py --config signmacapp.ini +``` + +## Managing the Service with systemd + +We set up the service under the user's control with a per-user systemd instance. + +Copy `macappsigner-user.sample.service` to `~/.config/systemd/user/macappsigner-user.service` +and modify it as needed. The example uses the username as ID of the service +worker. Make sure that the ID is unique if you run multiple service workers. + +Start the service with + +```sh +systemctl --user start macappsigner-user.service +``` + +If you want the service to be started automatically, then enable autostart with + +```sh +systemctl --user enable macappsigner-user.service +``` + +Note: By default, the systemd user instance and thus the user-managed services are +started after the first login of a user and killed after the last session of the +user is closed. To start the user instance right after boot, and keep the systemd +user instance running after the last session closes you have to enable lingering +for the user: + +```sh +loginctl enable-linger USERNAME +``` + +For more details on user-managed services see https://wiki.archlinux.org/title/Systemd/User. diff --git a/third_party/ci-notary-service/doc/macappsigner.sample.ini b/third_party/ci-notary-service/doc/macappsigner.sample.ini new file mode 100644 index 0000000..a71aaa5 --- /dev/null +++ b/third_party/ci-notary-service/doc/macappsigner.sample.ini @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +[Authentication] +Enabled = true +GitLabAPIv4Url = https://gitlab.example.net/api/v4 + +[AppleTools] +# the path to rcodesing +RCodesignPath = ~/.cargo/bin/rcodesign +# the path to a recent version of 7z +SevenZipPath = ~/some/path/7zz + +[MacAppSigning] +# the KeyStore file to use; overridden by project settings +KeyStore = ~/.local/share/macappsigner/keystore.jks +# the password for the KeyStore file; overridden by project settings +KeyStorePass = file:~/.local/share/macappsigner/keystorepass + + +[General] +ProjectSettings = ~/.local/share/macappsigner/macappsigner-projects.yaml + +[Logging] +# Optionally, write log output to a file +#LogFile = ~/.cache/macappsigner/macappsigner.log + +[SFTP] +# SFTP server to use +Server = sftp.example.net +# Port to connect to +#Port = 2222 +# User to connect with +Username = sftpnotary +# (Sub)directory on the server used for this service +BasePath = macappsigner + +# File with known host keys to prevent connection to unknown servers; +# if not specified, then the system host keys are used and missing host keys +# are accepted automatically +#KnownHostsFile = ~/.local/share/macappsigner/known_hosts + +# File with the private OpenSSH RSA key to use for login +#RsaKeyFile = ~/.ssh/id_rsa +# or name of environment variable with private OpenSSH RSA key to use for login +#RsaKeyFile = env:ENVIRONMENT_VARIABLE +# if no key is specified, then the SSH agent is used diff --git a/third_party/ci-notary-service/doc/microsoftstorepublisher-projects.sample.yaml b/third_party/ci-notary-service/doc/microsoftstorepublisher-projects.sample.yaml new file mode 100644 index 0000000..a4c1037 --- /dev/null +++ b/third_party/ci-notary-service/doc/microsoftstorepublisher-projects.sample.yaml @@ -0,0 +1,45 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +# define defaults for all listed projects +defaults: + # list of branches cleared for publishing of APPX for all listed projects + branches: [] + +# define settings specific for Project A (in Namespace A) +# key for Project A is the GitLab path of the project +namespace-a/project-a: + # the AppStream ID of the project; used to retrieve metadata of the project + appstreamid: net.example.projecta + # list of attributes to keep when updating the submission data from the AppStream data + # update everything from the AppStream data (including all translations) + # keep: + # - description + # - keywords + # - licenseTerms + # - releaseNotes + # - images + # - shortDescription + # - devStudio + # dictionary of branches cleared for publishing of APPXs + branches: + # allow publishing APPXs from the release branch for Project A + release: + +namespace-a/project-b: + # the AppStream ID of the project; used to retrieve metadata of the project + appstreamid: net.example.projectb + # list of attributes to keep when updating the submission data from the AppStream data + # don't overwrite anything of our nicely curated project information in the Microsoft Store + keep: + - description + - keywords + - licenseTerms + - releaseNotes + - images + - shortDescription + - devStudio + # dictionary of branches cleared for publishing of APPXs + branches: + # allow publishing APPXs from the release branch for Project B + release: diff --git a/third_party/ci-notary-service/doc/microsoftstorepublisher-user.sample.service b/third_party/ci-notary-service/doc/microsoftstorepublisher-user.sample.service new file mode 100644 index 0000000..fff32de --- /dev/null +++ b/third_party/ci-notary-service/doc/microsoftstorepublisher-user.sample.service @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +[Unit] +Description=microsoftstorepublisher +After=syslog.target network.target + +[Service] +Type=exec +WorkingDirectory=%h/microsoftstorepublisher +Environment="PATH=%h/microsoftstorepublisher/.venv/bin:/usr/local/bin:/usr/bin:/bin" +ExecStart=%h/microsoftstorepublisher/.venv/bin/python microsoftstorepublisher.py -vv --id %u --config %h/.config/microsoftstorepublisher.ini +Restart=on-failure +# avoid too many restarts in a short time span if starting the service fails +# because the SFTP server is temporarily unavailable +RestartSec=5s + +[Install] +WantedBy=default.target diff --git a/third_party/ci-notary-service/doc/microsoftstorepublisher.md b/third_party/ci-notary-service/doc/microsoftstorepublisher.md new file mode 100644 index 0000000..655dc1d --- /dev/null +++ b/third_party/ci-notary-service/doc/microsoftstorepublisher.md @@ -0,0 +1,154 @@ + + +# microsoftstorepublisher.py - A Microsoft Store Publishing Service + +This services submits apps to Microsoft Store. + +## Prerequisites + +The service needs an SFTP server for exchanging data with the clients. + +## Installation + +### Install the Service + +Clone this repository on a server that shall provide the service, +create a virtual environment, and install the requirements. + +```sh +git clone https://invent.kde.org/sysadmin/ci-notary-service.git microsoftstorepublisher +cd microsoftstorepublisher +python3 -m venv .venv +. .venv/bin/activate +pip3 install -r requirements_microsoftstore.txt +``` + +### Configure the Service + +Copy `microsoftstorepublisher.sample.ini` to `microsoftstorepublisher.ini` and replace the example values +with the appropriate values for your installation. + +Then copy `microsoftstorepublisher-projects.sample.yaml` to `microsoftstorepublisher-projects.yaml` and +specify the settings for the projects you want to submit to the Microsoft Store. + +## Run the Service + +Activate the virtual environment and start `microsoftstorepublisher.py`. + +```sh +cd ~/microsoftstorepublisher +. .venv/bin/activate +python3 microsoftstorepublisher.py --id workerA --config microsoftstorepublisher.ini +``` + +where you replace `workerA` with a unique alpha-numeric ID for each instance +of `microsoftstorepublisher.py` you start. + +## Use the Service to Submit an APPX Package + +Clone this repository on the client, create a virtual environment, and install +the requirements. + +```sh +git clone https://invent.kde.org/sysadmin/ci-notary-service.git microsoftstorepublisher +cd microsoftstorepublisher +python3 -m venv .venv +. .venv/bin/activate +pip3 install -r requirements.txt +``` + +Copy `publishonmicrosoftstore.sample.ini` to `publishonmicrosoftstore.ini` and replace the example values +with the appropriate values for your installation. In particular, the value +for `BasePath` must match the corresponding value in the settings of the +service. + +Then run `publishonmicrosoftstore.py` to submit an .appxupload file. + +```sh +python3 publishonmicrosoftstore.py --config publishonmicrosoftstore.ini +``` + +where `` is the .appxupload file you want to submit. + +Note that the service does not commit the submission. This allows you to have a +final look at the submission in the [Microsoft Partner Center](https://partner.microsoft.com/en-us/dashboard/windows/overview) +before you commit it from there. + +Also note that the very first submission has to be made via the Microsoft Partner +Center to fill out the age restriction questionnaire. There are also other values +that cannot be changed with the submission API. + +## Manage the Service with systemd + +We set up the service under the user's control with a per-user systemd instance. + +Copy `microsoftstorepublisher-user.sample.service` to `~/.config/systemd/user/microsoftstorepublisher-user.service` +and modify it as needed. The example uses the username as ID of the service +worker. Make sure that the ID is unique if you run multiple service workers. + +Start the service with + +```sh +systemctl --user start microsoftstorepublisher-user.service +``` + +If you want the service to be started automatically, then enable autostart with + +```sh +systemctl --user enable microsoftstorepublisher-user.service +``` + +Note: By default, the systemd user instance and thus the user-managed services are +started after the first login of a user and killed after the last session of the +user is closed. To start the user instance right after boot, and keep the systemd +user instance running after the last session closes you have to enable lingering +for the user: + +```sh +loginctl enable-linger USERNAME +``` + +For more details on user-managed services see https://wiki.archlinux.org/title/Systemd/User. + +## How the Service Updates the App's Information in the Store + +Additionally to uploading the `.appxupload` file to the Microsoft Store, the service +updates the information of the last published submission with the information found +in the AppStream data of the app (including translations). The Store ID is extracted +from the Microsoft Store URL of the app which is stored in the AppStream data as +custom value with key `KDE::windows_store`. +The script will add a store listing for each language with a non-empty Description +in the AppStream data. By default, existing listing values are overwritten with +corresponding AppStream values for a language. To keep existing non-empty values +set the `keep` option for your project in the project settings file (`microsoftstorepublisher-projects.yaml`) +to a comma-separated list of the values to keep. + +| Listing Value | AppStream Value | Notes | +| ------------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| copyrightAndTrademarkInfo | - | | +| description | `description` | Uses value for language. | +| keywords | `keywords` | Uses values for language. | +| licenseTerms | `project_license` | | +| features | - | | +| releaseNotes | `releases` | Uses `description` of first `release` for language (with fallback to English). | +| images | `screenshots` | Uses the Windows-specific `screenshot` (i.e. those with `environment="windows"`) or, as fallback, all `screenshot` with `type="default"` marking files with "mobile" in the name as MobileScreenshot; uses `caption` for language as image description. | +| recommendedHardware | - | | +| minimumHardware | - | | +| title | - | must be a reserved name; we keep what's there or use the primaryName of the [Application resource](https://learn.microsoft.com/en-us/windows/uwp/monetize/get-app-data#application-resource) | +| shortDescription | `summary` | Uses value for language. | +| shortTitle | - | | +| sortTitle | - | | +| voiceTitle | - | | +| devStudio | `developer_name` | Uses value for language (with fallback to English). | + +See [Base listing resource](https://learn.microsoft.com/en-us/windows/uwp/monetize/manage-app-submissions#base-listing-object) +for a description of the listing values. Listing values which have no equivalent +in the AppStream data can be filled out manually in the +[Microsoft Partner Center](https://partner.microsoft.com/en-us/dashboard/windows/overview). +If you want to make sure that those values are not overwritten once AppStream +provides this information and the script has been updated, then add those +values to the list of values to keep. diff --git a/third_party/ci-notary-service/doc/microsoftstorepublisher.sample.ini b/third_party/ci-notary-service/doc/microsoftstorepublisher.sample.ini new file mode 100644 index 0000000..97794d8 --- /dev/null +++ b/third_party/ci-notary-service/doc/microsoftstorepublisher.sample.ini @@ -0,0 +1,38 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +[Authentication] +Enabled = true +GitLabAPIv4Url = https://gitlab.example.net/api/v4 + +[MicrosoftStorePublishing] +# JSON file containing the credentials for Microsoft Store +Credentials = ~/keys/microsoft-store-credentials.json + +[General] +ProjectSettings = ~/.local/share/microsoftstorepublisher/microsoftstorepublisher-projects.yaml + +[Logging] +# Optionally, write log output to a file +#LogFile = .../microsoftstorepublisher.log + +[SFTP] +# SFTP server to use +Server = sftp.example.net +# Port to connect to +#Port = 2222 +# User to connect with +Username = sftpnotary +# (Sub)directory on the server used for tasks for this service +BasePath = microsoftstorepublisher + +# File with known host keys to prevent connection to unknown servers; +# if not specified, then the system host keys are used and missing host keys +# are accepted automatically +#KnownHostsFile = ~/.local/share/microsoftstorepublisher/known_hosts + +# File with the private OpenSSH RSA key to use for login +#RsaKeyFile = ~/.ssh/id_rsa +# or name of environment variable with private OpenSSH RSA key to use for login +#RsaKeyFile = env:ENVIRONMENT_VARIABLE +# if no key is specified, then the SSH agent is used diff --git a/third_party/ci-notary-service/doc/notarizemacapp.sample.ini b/third_party/ci-notary-service/doc/notarizemacapp.sample.ini new file mode 100644 index 0000000..6514854 --- /dev/null +++ b/third_party/ci-notary-service/doc/notarizemacapp.sample.ini @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +[General] +# location of the project settings file (relative to the location of this file); +# defaults to "macappnotarizer-projects.yaml" +#ProjectSettings = ~/.local/share/macappnotarizer/macappnotarizer-projects.yaml + +[SFTP] +# SFTP server to use +Server = sftp.example.net +# Port to connect to +#Port = 2222 +# User to connect with +Username = sftpnotary +# (Sub)directory on the server used for tasks for this service +BasePath = macappnotarizer + +# File with known host keys to prevent connection to unknown servers; +# if not specified, then the system host keys are used and missing host keys +# are accepted automatically +#KnownHostsFile = ~/.local/share/macappnotarizer/known_hosts + +# File with the private OpenSSH RSA key to use for login +#RsaKeyFile = ~/.ssh/id_rsa +# or name of environment variable with private OpenSSH RSA key to use for login +#RsaKeyFile = env:ENVIRONMENT_VARIABLE +# if no key is specified, then the SSH agent is used diff --git a/third_party/ci-notary-service/doc/publishbuild.sample.ini b/third_party/ci-notary-service/doc/publishbuild.sample.ini new file mode 100644 index 0000000..d5da760 --- /dev/null +++ b/third_party/ci-notary-service/doc/publishbuild.sample.ini @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +[SFTP] +# SFTP server to use +Server = sftp.example.net +# Port to connect to +#Port = 2222 +# User to connect with +Username = sftpnotary +# (Sub)directory on the server used for tasks for this service +BasePath = buildpublisher + +# File with known host keys to prevent connection to unknown servers; +# if not specified, then the system host keys are used and missing host keys +# are accepted automatically +#KnownHostsFile = ~/.local/buildpublisher/known_hosts + +# File with the private OpenSSH RSA key to use for login +#RsaKeyFile = ~/.local/buildpublisher/ssh_key +# or name of environment variable with private OpenSSH RSA key to use for login +#RsaKeyFile = env:ENVIRONMENT_VARIABLE +# if no key is specified, then the SSH agent is used diff --git a/third_party/ci-notary-service/doc/publishonfdroid.sample.ini b/third_party/ci-notary-service/doc/publishonfdroid.sample.ini new file mode 100644 index 0000000..467ed42 --- /dev/null +++ b/third_party/ci-notary-service/doc/publishonfdroid.sample.ini @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +[General] +# location of the project settings file (relative to the location of this file); +# defaults to "fdroidpublisher-projects.yaml" +#ProjectSettings = ~/.local/share/fdroidpublisher/fdroidpublisher-projects.yaml + +[SFTP] +# SFTP server to use +Server = sftp.example.net +# Port to connect to +#Port = 2222 +# User to connect with +Username = sftpnotary +# (Sub)directory on the server used for tasks for this service +BasePath = fdroidpublisher + +# File with known host keys to prevent connection to unknown servers; +# if not specified, then the system host keys are used and missing host keys +# are accepted automatically +#KnownHostsFile = ~/.local/share/fdroidpublisher/known_hosts + +# File with the private OpenSSH RSA key to use for login +#RsaKeyFile = ~/.ssh/id_rsa +# or name of environment variable with private OpenSSH RSA key to use for login +#RsaKeyFile = env:ENVIRONMENT_VARIABLE +# if no key is specified, then the SSH agent is used diff --git a/third_party/ci-notary-service/doc/publishongoogleplay.sample.ini b/third_party/ci-notary-service/doc/publishongoogleplay.sample.ini new file mode 100644 index 0000000..f907530 --- /dev/null +++ b/third_party/ci-notary-service/doc/publishongoogleplay.sample.ini @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +[General] +# location of the project settings file (relative to the location of this file); +# defaults to "googleplaypublisher-projects.yaml" +#ProjectSettings = ~/.local/share/googleplaypublisher/googleplaypublisher-projects.yaml + +[SFTP] +# SFTP server to use +Server = sftp.example.net +# Port to connect to +#Port = 2222 +# User to connect with +Username = sftpnotary +# (Sub)directory on the server used for tasks for this service +BasePath = googleplaypublisher + +# File with known host keys to prevent connection to unknown servers; +# if not specified, then the system host keys are used and missing host keys +# are accepted automatically +#KnownHostsFile = ~/.local/share/googleplaypublisher/known_hosts + +# File with the private OpenSSH RSA key to use for login +#RsaKeyFile = ~/.ssh/id_rsa +# or name of environment variable with private OpenSSH RSA key to use for login +#RsaKeyFile = env:ENVIRONMENT_VARIABLE +# if no key is specified, then the SSH agent is used diff --git a/third_party/ci-notary-service/doc/publishonmicrosoftstore.sample.ini b/third_party/ci-notary-service/doc/publishonmicrosoftstore.sample.ini new file mode 100644 index 0000000..a5ef1b2 --- /dev/null +++ b/third_party/ci-notary-service/doc/publishonmicrosoftstore.sample.ini @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +[General] +# location of the project settings file (relative to the location of this file); +# defaults to "microsoftstorepublisher-projects.yaml" +#ProjectSettings = ~/.local/share/microsoftstorepublisher/microsoftstorepublisher-projects.yaml + +[SFTP] +# SFTP server to use +Server = sftp.example.net +# Port to connect to +#Port = 2222 +# User to connect with +Username = sftpnotary +# (Sub)directory on the server used for tasks for this service +BasePath = microsoftstorepublisher + +# File with known host keys to prevent connection to unknown servers; +# if not specified, then the system host keys are used and missing host keys +# are accepted automatically +#KnownHostsFile = ~/.local/share/microsoftstorepublisher/known_hosts + +# File with the private OpenSSH RSA key to use for login +#RsaKeyFile = ~/.ssh/id_rsa +# or name of environment variable with private OpenSSH RSA key to use for login +#RsaKeyFile = env:ENVIRONMENT_VARIABLE +# if no key is specified, then the SSH agent is used diff --git a/third_party/ci-notary-service/doc/publishonpypi.sample.ini b/third_party/ci-notary-service/doc/publishonpypi.sample.ini new file mode 100644 index 0000000..abdee47 --- /dev/null +++ b/third_party/ci-notary-service/doc/publishonpypi.sample.ini @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +[SFTP] +# SFTP server to use +Server = sftp.example.net +# Port to connect to +#Port = 2222 +# User to connect with +Username = sftpnotary +# (Sub)directory on the server used for tasks for this service +BasePath = pypipublisher + +# File with known host keys to prevent connection to unknown servers; +# if not specified, then the system host keys are used and missing host keys +# are accepted automatically +#KnownHostsFile = ~/.local/pypipublisher/known_hosts + +# File with the private OpenSSH RSA key to use for login +#RsaKeyFile = ~/.local/pypipublisher/ssh_key +# or name of environment variable with private OpenSSH RSA key to use for login +#RsaKeyFile = env:ENVIRONMENT_VARIABLE +# if no key is specified, then the SSH agent is used diff --git a/third_party/ci-notary-service/doc/publishwebsite.sample.ini b/third_party/ci-notary-service/doc/publishwebsite.sample.ini new file mode 100644 index 0000000..7395063 --- /dev/null +++ b/third_party/ci-notary-service/doc/publishwebsite.sample.ini @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +[SFTP] +# SFTP server to use +Server = sftp.example.net +# Port to connect to +#Port = 2222 +# User to connect with +Username = sftpnotary +# (Sub)directory on the server used for tasks for this service +BasePath = websitepublisher + +# File with known host keys to prevent connection to unknown servers; +# if not specified, then the system host keys are used and missing host keys +# are accepted automatically +#KnownHostsFile = ~/.local/websitepublisher/known_hosts + +# File with the private OpenSSH RSA key to use for login +#RsaKeyFile = ~/.local/websitepublisher/ssh_key +# or name of environment variable with private OpenSSH RSA key to use for login +#RsaKeyFile = env:ENVIRONMENT_VARIABLE +# if no key is specified, then the SSH agent is used diff --git a/third_party/ci-notary-service/doc/pypipublisher-projects.sample.yaml b/third_party/ci-notary-service/doc/pypipublisher-projects.sample.yaml new file mode 100644 index 0000000..3887465 --- /dev/null +++ b/third_party/ci-notary-service/doc/pypipublisher-projects.sample.yaml @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +namespace/some-project: + # the package name; checked against the metadata of the files requested to publish + # can be a list to support multiple package names for a project + packagename: some-project + # the branches cleared for publishing + branches: + master: diff --git a/third_party/ci-notary-service/doc/pypipublisher-user.sample.service b/third_party/ci-notary-service/doc/pypipublisher-user.sample.service new file mode 100644 index 0000000..26b4635 --- /dev/null +++ b/third_party/ci-notary-service/doc/pypipublisher-user.sample.service @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +[Unit] +Description=pypipublisher +After=syslog.target network.target + +[Service] +Type=exec +WorkingDirectory=%h/pypipublisher +Environment="PATH=%h/pypipublisher/.venv/bin:/usr/local/bin:/usr/bin:/bin" +ExecStart=%h/pypipublisher/.venv/bin/python pypipublisher.py -vv --id %u --config %h/.config/pypipublisher.ini +Restart=on-failure +# avoid too many restarts in a short time span if starting the service fails +# because the SFTP server is temporarily unavailable +RestartSec=5s + +[Install] +WantedBy=default.target diff --git a/third_party/ci-notary-service/doc/pypipublisher.md b/third_party/ci-notary-service/doc/pypipublisher.md new file mode 100644 index 0000000..458e675 --- /dev/null +++ b/third_party/ci-notary-service/doc/pypipublisher.md @@ -0,0 +1,96 @@ + + +# pypipublisher.py - A service to publish Python distribution packages + +This service takes an archive of distribution files (like *.whl), unpacks it and publishes them +with [twine](https://twine.readthedocs.io/en/stable/index.html#) to a Python repository. + +## Prerequisites + +The service needs an SFTP server for exchanging data with the clients. + +For publishing to the remote repository, a `.pypirc` config needs to be in place. +Inside this configuration file the credentials for the remote repositories need to be set. +The service currently supports two repositories: https://test.pypi.org and https://pypi.org + +Hence your config file may look like this: + +``` +[pypi] +username = __token__ +password = # Replace by the real api token + +[testpypi] +username = __token__ +password = # Replace by the real api token +``` + +The name of the file does not need to be `.pypirc`, but its path needs to be set in `pypipublisher.ini`. + +For more details on the config file, read the [documentation](https://packaging.python.org/en/latest/specifications/pypirc/). + +## Installation + +### Install the Service + +Clone this repository on a server that shall provide the service, +create a virtual environment, and install the requirements. + +```sh +git clone https://invent.kde.org/sysadmin/ci-notary-service.git pypipublisher +cd pypipublisher +python3 -m venv .venv +. .venv/bin/activate +pip3 install -r requirements_pypi.txt +``` + +### Configure the Service + +Copy `pypipublisher.sample.ini` to `pypipublisher.ini` and replace the example values +with the appropriate values for your installation. + +Then copy `pypipublisher-projects.sample.yaml` to `pypipublisher-projects.yaml` and +specify the settings for the projects you want to use the service for. + +## Run the Service + +Activate the virtual environment and start `pypipublisher.py`. + +```sh +cd ~/pypipublisher +. .venv/bin/activate +python3 pypipublisher.py --id workerA --config pypipublisher.ini +``` + +where you replace `workerA` with a unique alpha-numeric ID for each instance +of `pypipublisher.py` you start. + +## Use the Service to Publish a Package + +Clone this repository on the client, create a virtual environment, and install +the requirements. + +```sh +git clone https://invent.kde.org/sysadmin/ci-notary-service.git pypipublisher +cd pypipublisher +python3 -m venv .venv +. .venv/bin/activate +pip3 install -r requirements.txt +``` + +Copy `publishonpypi.sample.ini` to `publishonpypi.ini` and replace the example values +with the appropriate values for your installation. In particular, the value +for `BasePath` must match the corresponding value in the settings of the +service. + +Then run `publishonpypi.py` to publish the package. + +```sh +python3 publishonpypi.py --config publishonpypi.ini --repository +``` diff --git a/third_party/ci-notary-service/doc/pypipublisher.sample.ini b/third_party/ci-notary-service/doc/pypipublisher.sample.ini new file mode 100644 index 0000000..b8ec8bf --- /dev/null +++ b/third_party/ci-notary-service/doc/pypipublisher.sample.ini @@ -0,0 +1,38 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +[Authentication] +Enabled = true +GitLabAPIv4Url = https://gitlab.example.net/api/v4 + +[PyPiPublishing] +# Path to pypirc file https://packaging.python.org/en/latest/specifications/pypirc/ +ConfigFilePath = ~/.local/pypipublisher/pypirc + +[General] +ProjectSettings = ~/.local/pypipublisher/pypipublisher-projects.yaml + +[Logging] +# Optionally, write log output to a file +#LogFile = ~/.cache/pypipublisher.log + +[SFTP] +# SFTP server to use +Server = sftp.example.net +# Port to connect to +#Port = 2222 +# User to connect with +Username = sftpnotary +# (Sub)directory on the server used for tasks for this service +BasePath = pypipublisher + +# File with known host keys to prevent connection to unknown servers; +# if not specified, then the system host keys are used and missing host keys +# are accepted automatically +#KnownHostsFile = ~/.local/share/pypipublisher/known_hosts + +# File with the private OpenSSH RSA key to use for login +#RsaKeyFile = ~/.ssh/id_rsa +# or name of environment variable with private OpenSSH RSA key to use for login +#RsaKeyFile = env:ENVIRONMENT_VARIABLE +# if no key is specified, then the SSH agent is used diff --git a/third_party/ci-notary-service/doc/signaab.sample.ini b/third_party/ci-notary-service/doc/signaab.sample.ini new file mode 100644 index 0000000..539e4e1 --- /dev/null +++ b/third_party/ci-notary-service/doc/signaab.sample.ini @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +[General] +# location of the project settings file (relative to the location of this file); +# defaults to "aabsigner-projects.yaml" +#ProjectSettings = ~/.local/share/aabsigner/aabsigner-projects.yaml + +[SFTP] +# SFTP server to use +Server = sftp.example.net +# Port to connect to +#Port = 2222 +# User to connect with +Username = sftpnotary +# (Sub)directory on the server used for tasks for this service +BasePath = aabsigner + +# File with known host keys to prevent connection to unknown servers; +# if not specified, then the system host keys are used and missing host keys +# are accepted automatically +#KnownHostsFile = ~/.local/share/aabsigner/known_hosts + +# File with the private OpenSSH RSA key to use for login +#RsaKeyFile = ~/.ssh/id_rsa +# or name of environment variable with private OpenSSH RSA key to use for login +#RsaKeyFile = env:ENVIRONMENT_VARIABLE +# if no key is specified, then the SSH agent is used diff --git a/third_party/ci-notary-service/doc/signapk.sample.ini b/third_party/ci-notary-service/doc/signapk.sample.ini new file mode 100644 index 0000000..7e2c146 --- /dev/null +++ b/third_party/ci-notary-service/doc/signapk.sample.ini @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +[General] +# location of the project settings file (relative to the location of this file); +# defaults to "apksigner-projects.yaml" +#ProjectSettings = ~/.local/share/apksigner/apksigner-projects.yaml + +[SFTP] +# SFTP server to use +Server = sftp.example.net +# Port to connect to +#Port = 2222 +# User to connect with +Username = sftpnotary +# (Sub)directory on the server used for tasks for this service +BasePath = apksigner + +# File with known host keys to prevent connection to unknown servers; +# if not specified, then the system host keys are used and missing host keys +# are accepted automatically +#KnownHostsFile = ~/.local/share/apksigner/known_hosts + +# File with the private OpenSSH RSA key to use for login +#RsaKeyFile = ~/.ssh/id_rsa +# or name of environment variable with private OpenSSH RSA key to use for login +#RsaKeyFile = env:ENVIRONMENT_VARIABLE +# if no key is specified, then the SSH agent is used diff --git a/third_party/ci-notary-service/doc/signflatpak.sample.ini b/third_party/ci-notary-service/doc/signflatpak.sample.ini new file mode 100644 index 0000000..9cf90c1 --- /dev/null +++ b/third_party/ci-notary-service/doc/signflatpak.sample.ini @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +[General] +# location of the project settings file (relative to the location of this file); +# defaults to "flatpaksigner-projects.yaml" +#ProjectSettings = ~/.local/share/flatpaksigner/flatpaksigner-projects.yaml + +[SFTP] +# SFTP server to use +Server = sftp.example.net +# Port to connect to +#Port = 2222 +# User to connect with +Username = sftpnotary +# (Sub)directory on the server used for tasks for this service +BasePath = flatpaksigner + +# File with known host keys to prevent connection to unknown servers; +# if not specified, then the system host keys are used and missing host keys +# are accepted automatically +#KnownHostsFile = ~/.local/share/flatpaksigner/known_hosts + +# File with the private OpenSSH RSA key to use for login +#RsaKeyFile = ~/.ssh/id_rsa +# or name of environment variable with private OpenSSH RSA key to use for login +#RsaKeyFile = env:ENVIRONMENT_VARIABLE +# if no key is specified, then the SSH agent is used diff --git a/third_party/ci-notary-service/doc/signmacapp.sample.ini b/third_party/ci-notary-service/doc/signmacapp.sample.ini new file mode 100644 index 0000000..f7430ba --- /dev/null +++ b/third_party/ci-notary-service/doc/signmacapp.sample.ini @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +[General] +# location of the project settings file (relative to the location of this file); +# defaults to "macappsigner-projects.yaml" +#ProjectSettings = ~/.local/share/macappsigner/macappsigner-projects.yaml + +[SFTP] +# SFTP server to use +Server = sftp.example.net +# Port to connect to +#Port = 2222 +# User to connect with +Username = sftpnotary +# (Sub)directory on the server used for tasks for this service +BasePath = macappsigner + +# File with known host keys to prevent connection to unknown servers; +# if not specified, then the system host keys are used and missing host keys +# are accepted automatically +#KnownHostsFile = ~/.local/share/macappsigner/known_hosts + +# File with the private OpenSSH RSA key to use for login +#RsaKeyFile = ~/.ssh/id_rsa +# or name of environment variable with private OpenSSH RSA key to use for login +#RsaKeyFile = env:ENVIRONMENT_VARIABLE +# if no key is specified, then the SSH agent is used diff --git a/third_party/ci-notary-service/doc/signwindowsbinaries.sample.ini b/third_party/ci-notary-service/doc/signwindowsbinaries.sample.ini new file mode 100644 index 0000000..fa2af41 --- /dev/null +++ b/third_party/ci-notary-service/doc/signwindowsbinaries.sample.ini @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2024 KDE e.V. + +[SFTP] +# SFTP server to use +Server = sftp.example.net +# Port to connect to +#Port = 2222 +# User to connect with +Username = sftpnotary +# (Sub)directory on the server used for tasks for this service +BasePath = windowsbinariessigner + +# File with known host keys to prevent connection to unknown servers; +# if not specified, then the system host keys are used and missing host keys +# are accepted automatically +#KnownHostsFile = known_hosts + +# File with the private OpenSSH RSA key to use for login +#RsaKeyFile = ssh_key +# or name of environment variable with private OpenSSH RSA key to use for login +#RsaKeyFile = env:ENVIRONMENT_VARIABLE +# if no key is specified, then the SSH agent is used diff --git a/third_party/ci-notary-service/doc/websitepublisher-projects.sample.yaml b/third_party/ci-notary-service/doc/websitepublisher-projects.sample.yaml new file mode 100644 index 0000000..cf51da8 --- /dev/null +++ b/third_party/ci-notary-service/doc/websitepublisher-projects.sample.yaml @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 Ben Cooksley + +# define defaults for all listed projects +defaults: + # template used to construct the destination that rsync should be syncing to + rsyncDestination: "deployment@remote-server.example.net:/var/www/%s" + +# define settings specific for subdomain.example.net (in Websites namespace) +# key is the GitLab path of the project +websites/www-example-net: + # dictionary of branches to performing publishing services for + branches: + master: + domain: www.example.net + staging: + domain: staging.example.net + +# This website is hosted on a different server to the others +websites/subdomain-example-net: + # Different rsync template here + rsyncDestination: "deployment@other-server.example.net:/var/apps/subdomain-example-net" + # As there is no %s in the template this will do nothing but we define it just to keep things happy + domain: subdomain.example.net + # For this one only production is supported, there is no development/staging environment + # We therefore just list master to enable it + branches: + master: diff --git a/third_party/ci-notary-service/doc/websitepublisher-user.sample.service b/third_party/ci-notary-service/doc/websitepublisher-user.sample.service new file mode 100644 index 0000000..ea38d2a --- /dev/null +++ b/third_party/ci-notary-service/doc/websitepublisher-user.sample.service @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileCopyrightText: 2023 Ben Cooksley + +[Unit] +Description=websitepublisher +After=syslog.target network.target + +[Service] +Type=exec +WorkingDirectory=%h/websitepublisher +Environment="PATH=%h/websitepublisher/.venv/bin:/usr/local/bin:/usr/bin:/bin" +ExecStart=%h/websitepublisher/.venv/bin/python websitepublisher.py -vv --id %u --config %h/.config/websitepublisher.ini +Restart=on-failure +# avoid too many restarts in a short time span if starting the service fails +# because the SFTP server is temporarily unavailable +RestartSec=5s + +[Install] +WantedBy=default.target diff --git a/third_party/ci-notary-service/doc/websitepublisher.md b/third_party/ci-notary-service/doc/websitepublisher.md new file mode 100644 index 0000000..cb3dae0 --- /dev/null +++ b/third_party/ci-notary-service/doc/websitepublisher.md @@ -0,0 +1,89 @@ + + +# websitepublisher.py - A service to publish files securely to a either a local or remote location (usually for serving by a web server) + +This service takes an archive of a website, unpacks it and transfers the contents +using rsync to a specified destination, which can be either local or remote. + +## Prerequisites + +The service needs an SFTP server for exchanging data with the clients. + +Additionally `rsync` must be installed and available in path, as it is used +to transfer files to the final destination, whether local or remote. + +For transfers to remote destinations, an SSH private key pair must be created +and authorised to access the remote system. The key pair must be available for +use without a password - either because the key has no password or because it +has been added to an SSH agent prior to the service being started. Use of SSH +password based authentication is not supported. + +Should particular parameters (such as a non-standard port) be required to connect +to the remote system then this must be configured in ~/.ssh/config + +## Installation + +### Install the Service + +Clone this repository on a server that shall provide the service, +create a virtual environment, and install the requirements. + +```sh +git clone https://invent.kde.org/sysadmin/ci-notary-service.git websitepublisher +cd websitepublisher +python3 -m venv .venv +. .venv/bin/activate +pip3 install -r requirements.txt +``` + +### Configure the Service + +Copy `websitepublisher.sample.ini` to `websitepublisher.ini` and replace the example values +with the appropriate values for your installation. + +Then copy `websitepublisher-projects.sample.yaml` to `websitepublisher-projects.yaml` and +specify the settings for the projects you want to use service for. + +## Run the Service + +Activate the virtual environment and start `websitepublisher.py`. + +```sh +cd ~/websitepublisher +. .venv/bin/activate +python3 websitepublisher.py --id workerA --config websitepublisher.ini +``` + +where you replace `workerA` with a unique alpha-numeric ID for each instance +of `websitepublisher.py` you start. You can run multiple instances, but the +behavior is undefined if multiple instances operate on the same destination. +Therefore, it's recommended to run only one service for a given Gitlab repository. + +## Use the Service to Publish a Website + +Clone this repository on the client, create a virtual environment, and install +the requirements. + +```sh +git clone https://invent.kde.org/sysadmin/ci-notary-service.git websitepublisher +cd websitepublisher +python3 -m venv .venv +. .venv/bin/activate +pip3 install -r requirements.txt +``` + +Copy `publishwebsite.sample.ini` to `publishwebsite.ini` and replace the example values +with the appropriate values for your installation. In particular, the value +for `BasePath` must match the corresponding value in the settings of the +service. + +Then run `publishwebsite.py` to sign and publish the website. + +```sh +python3 publishwebsite.py --config publishwebsite.ini +``` diff --git a/third_party/ci-notary-service/doc/websitepublisher.sample.ini b/third_party/ci-notary-service/doc/websitepublisher.sample.ini new file mode 100644 index 0000000..1cf8454 --- /dev/null +++ b/third_party/ci-notary-service/doc/websitepublisher.sample.ini @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileCopyrightText: 2023 Ben Cooksley + +[Authentication] +Enabled = true +GitLabAPIv4Url = https://gitlab.example.net/api/v4 + +[General] +ProjectSettings = ~/.local/websitepublisher/websitepublisher-projects.yaml + +[Logging] +# Optionally, write log output to a file +#LogFile = ~/.cache/flatpaksigner.log + +[SFTP] +# SFTP server to use +Server = sftp.example.net +# Port to connect to +#Port = 2222 +# User to connect with +Username = sftpnotary +# (Sub)directory on the server used for tasks for this service +BasePath = websitepublisher + +# File with known host keys to prevent connection to unknown servers; +# if not specified, then the system host keys are used and missing host keys +# are accepted automatically +#KnownHostsFile = ~/.local/websitepublisher/known_hosts + +# File with the private OpenSSH RSA key to use for login +#RsaKeyFile = ~/.local/websitepublisher/ssh_key +# or name of environment variable with private OpenSSH RSA key to use for login +#RsaKeyFile = env:ENVIRONMENT_VARIABLE +# if no key is specified, then the SSH agent is used diff --git a/third_party/ci-notary-service/doc/windowsbinariessigner-projects.sample.yaml b/third_party/ci-notary-service/doc/windowsbinariessigner-projects.sample.yaml new file mode 100644 index 0000000..0a00543 --- /dev/null +++ b/third_party/ci-notary-service/doc/windowsbinariessigner-projects.sample.yaml @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2024 KDE e.V. + +# define defaults for all listed projects +defaults: + # list of branches to sign for all listed projects + branches: + - master + +# define settings specific for Project A (in Namespace A) +# key for Project A is the GitLab path of the project +namespace-a/project-a: + # the application ID of the app package; checked against APPX packages to sign + applicationid: net.example.projecta + # dictionary of branches to sign additionally to the default branches + branches: + # also allow signing the release branch for Project A + release: diff --git a/third_party/ci-notary-service/doc/windowsbinariessigner.md b/third_party/ci-notary-service/doc/windowsbinariessigner.md new file mode 100644 index 0000000..294dd67 --- /dev/null +++ b/third_party/ci-notary-service/doc/windowsbinariessigner.md @@ -0,0 +1,102 @@ + + +# windowsbinariessigner.py - A Signing Service for Windows Binaries and APPX Packages + +Provides code signing for Windows binaries and APPX sideload packages. + +## Prerequisites + +You need + +- Python 3.10+ (I entered `python` in PowerShell and then the Microsoft Store app opened offering Python 3.11) +- Git (install with `winget install --id Git.Git -e --source winget`; then open a new PowerShell) +- a code signing certificate (either as `*.pfx` file or in your certificate store), +- a config file (see `windowsbinariessigner.sample.ini`), +- a project settings file (see `windowsbinariessigner-projects.sample.yaml`), +- a file with the private SSH key, e.g. `testsshkey`, without password for + accessing the SFTP server. + +Moreover, you need a directory (e.g. `windowsbinariessigner`) on an SFTP server that can be used for +exchanging data with the clients. + +## Installation + +### Install the Service + +Clone this repository on a Windows machine that shall provide the service, +create a virtual environment, and install the requirements. + +In PowerShell do + +```powershell +git clone https://invent.kde.org/sysadmin/ci-notary-service.git windowsbinariessigner +cd .\windowsbinariessigner +python -m venv $env:USERPROFILE\venv\windowsbinariessigner +~\venv\windowsbinariessigner\Scripts\Activate.ps1 +pip3 install -r requirements.txt +``` + +#### Note + +> It may be necessary to set the execution policy for the user to be able to run the `Activate.ps1` script. You can do this by issuing the following PowerShell command: +> `Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser` +> See [About Execution Policies](https://go.microsoft.com/fwlink/?LinkID=135170) for more information. + +### Configure the Service + +Copy `windowsbinariessigner.sample.ini` to `windowsbinariessigner.ini` and replace the example values +with the appropriate values for your installation. + +Then copy `windowsbinariessigner-projects.sample.yaml` to `windowsbinariessigner-projects.yaml` and +specify the settings for the projects you want to sign Windows binaries or APPX sideload packages for. +If you want to sign APPX sideload packages then you have to add the application IDs of the projects +to the project settings. The application ID of a project is the value of the `Name` attribute of the +`Identity` element in the `AppxManifest.xml`. + +## Run the Service + +Enter the folder containing `windowsbinariessigner.py`, install the needed Python packages, and run the script + +```powershell +cd .\windowsbinariessigner +~\venv\windowsbinariessigner\Scripts\Activate.ps1 +python windowsbinariessigner.py --config windowsbinariessigner.ini --id workerA +``` + +## Use the Service to Sign Windows Binaries + +Install the necessary Python modules in a virtual environment (e.g. on Linux) + +```sh +python3 -m venv .venv +. .venv/bin/activate +pip install -r requirements.txt +``` + +Copy `signwindowsbinaries.sample.ini` to `signwindowsbinaries.ini` and replace the example values +with the appropriate values for your installation. In particular, the value +for `BasePath` must match the corresponding value in the settings of the +service. + +Then run `signwindowsbinaries.py` to sign Windows binaries + +```sh +python3 signwindowsbinaries.py --config signwindowsbinaries.ini ... +``` + +or + +```sh +python3 signwindowsbinaries.py --config signwindowsbinaries.ini --files-from +``` + +where `` contains a list of files to sign. Use the later command if you want to sign a lot of files +and want to avoid problems caused by command line length limitations. + +## Creating a Test Certificate + +See https://learn.microsoft.com/en-us/windows/msix/package/create-certificate-package-signing diff --git a/third_party/ci-notary-service/doc/windowsbinariessigner.sample.ini b/third_party/ci-notary-service/doc/windowsbinariessigner.sample.ini new file mode 100644 index 0000000..0eb6899 --- /dev/null +++ b/third_party/ci-notary-service/doc/windowsbinariessigner.sample.ini @@ -0,0 +1,52 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2024 KDE e.V. + +[Authentication] +Enabled = true +GitLabAPIv4Url = https://gitlab.example.net/api/v4 + +[CodeSigning] +## Utility to use when signing +# For Windows using Windows SDK Sign Tool +Utility = codesign +# For all other systems +# Utility = jsign +## Path of SignTool +SignTool = C:/windowsbinariessigner/signtool.exe +## Path of JSign +JSignPath = /usr/bin/jsign +## Path of Certificate +# Certificate = C:\windowsbinariessigner\mycert.pfx +## Password to unlock the certificate +# Password = test +## Attributes of Code Signing Certificate in certificate store +CommonName = K Desktop Environment e. V. +Organization = K Desktop Environment e. V. +State = Berlin +Country = DE + +[General] +ProjectSettings = windowsbinariessigner-projects.yaml +## Directory to use for the temporary working directories created by the signer; +## defaults to the user's temporary directory +# TempDirectory = C:/windowsbinariessigner-temp + +[SFTP] +# SFTP server to use +Server = sftp.example.net +# Port to connect to +#Port = 2222 +# User to connect with +Username = sftpnotary +# (Sub)directory on the server used for tasks for this service +BasePath = windowsbinariessigner + +# File with known host keys to prevent connection to unknown servers; +# if not specified, then the system host keys are used and missing host keys +# are accepted automatically +#KnownHostsFile = C:/windowsbinariessigner/known_hosts + +# File with the private OpenSSH RSA key to use for login +#RsaKeyFile = C:/windowsbinariessigner/ssh_key +# or name of environment variable with private OpenSSH RSA key to use for login +#RsaKeyFile = env:ENVIRONMENT_VARIABLE diff --git a/third_party/ci-notary-service/fdroidpublisher.py b/third_party/ci-notary-service/fdroidpublisher.py new file mode 100644 index 0000000..eb12062 --- /dev/null +++ b/third_party/ci-notary-service/fdroidpublisher.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: BSD-2-Clause +# +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + +import sys + +from sftpnotary import authentication, config, util +from sftpnotary.exceptions import Error +from sftpnotary.fdroidpublisher import PublishOnFDroidWorker + + +def parseCommandLine(): + import argparse + + parser = argparse.ArgumentParser(description="Worker for publishing APKs in an F-Droid repository") + + # debug options + parser.add_argument("-v", "--verbose", action="count", default=0, help="increase the verbosity") + + parser.add_argument("--id", dest="workerId", help="Unique, alpha-numeric identifier of this service worker") + + parser.add_argument("--config") + + options = parser.parse_args() + return options + + +def setUpAuthentication(): + auth = authentication.GitLabJobTokenAuthentication( + apiV4Url=config.settings.get("Authentication", "GitLabAPIv4Url", ""), userAgent="org.kde.fdroidpublisher" + ) + authentication.setAuthentication(auth) + + +def startWorker(workerId: str): + with util.connectToSftpServer() as sftp: + worker = PublishOnFDroidWorker(workerId, sftp) + worker.start() + + +def main(): + options = parseCommandLine() + config.loadConfig(options.config) + util.setUpServiceLogging("fdroidpublisher", options.verbose) + util.loadProjectSettings(config.settings.get("General", "ProjectSettings")) + if config.settings.getboolean("Authentication", "Enabled", False): + setUpAuthentication() + + startWorker(options.workerId) + + return 0 + + +if __name__ == "__main__": + try: + sys.exit(main()) + except Error as e: + print("Error: %s" % e, file=sys.stderr) + sys.exit(1) diff --git a/third_party/ci-notary-service/flatpaksigner.py b/third_party/ci-notary-service/flatpaksigner.py new file mode 100644 index 0000000..b1a6ffb --- /dev/null +++ b/third_party/ci-notary-service/flatpaksigner.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: BSD-2-Clause +# +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + +import sys + +from sftpnotary import authentication, config, util +from sftpnotary.exceptions import Error +from sftpnotary.flatpaksigner import SignFlatpakWorker + + +def parseCommandLine(): + import argparse + + parser = argparse.ArgumentParser(description="Worker for signing Flatpaks") + + # debug options + parser.add_argument("-v", "--verbose", action="count", default=0, help="increase the verbosity") + + parser.add_argument("--id", dest="workerId", help="Unique, alpha-numeric identifier of this service worker") + + parser.add_argument("--config") + + options = parser.parse_args() + return options + + +def setUpAuthentication(): + auth = authentication.GitLabJobTokenAuthentication( + apiV4Url=config.settings.get("Authentication", "GitLabAPIv4Url", ""), userAgent="org.kde.flatpaksigner" + ) + authentication.setAuthentication(auth) + + +def startWorker(workerId: str): + with util.connectToSftpServer() as sftp: + worker = SignFlatpakWorker(workerId, sftp) + worker.start() + + +def main(): + options = parseCommandLine() + config.loadConfig(options.config) + util.setUpServiceLogging("flatpaksigner", options.verbose) + util.loadProjectSettings(config.settings.get("General", "ProjectSettings")) + if config.settings.getboolean("Authentication", "Enabled", False): + setUpAuthentication() + + startWorker(options.workerId) + + return 0 + + +if __name__ == "__main__": + try: + sys.exit(main()) + except Error as e: + print("Error: %s" % e, file=sys.stderr) + sys.exit(1) diff --git a/third_party/ci-notary-service/googleplaypublisher.py b/third_party/ci-notary-service/googleplaypublisher.py new file mode 100644 index 0000000..49f3ca4 --- /dev/null +++ b/third_party/ci-notary-service/googleplaypublisher.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: BSD-2-Clause +# +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + +import sys + +from sftpnotary import authentication, config, util +from sftpnotary.exceptions import Error +from sftpnotary.googleplaypublisher import PublishOnGooglePlayWorker + + +def parseCommandLine(): + import argparse + + parser = argparse.ArgumentParser(description="Worker for publishing AABs and APKs on Google Play") + + # debug options + parser.add_argument("-v", "--verbose", action="count", default=0, help="increase the verbosity") + + parser.add_argument("--id", dest="workerId", help="Unique, alpha-numeric identifier of this service worker") + + parser.add_argument("--config") + + options = parser.parse_args() + return options + + +def setUpAuthentication(): + auth = authentication.GitLabJobTokenAuthentication( + apiV4Url=config.settings.get("Authentication", "GitLabAPIv4Url", ""), userAgent="org.kde.googleplaypublisher" + ) + authentication.setAuthentication(auth) + + +def startWorker(workerId: str): + with util.connectToSftpServer() as sftp: + worker = PublishOnGooglePlayWorker(workerId, sftp) + worker.start() + + +def main(): + options = parseCommandLine() + config.loadConfig(options.config) + util.setUpServiceLogging("googleplaypublisher", options.verbose) + util.loadProjectSettings(config.settings.get("General", "ProjectSettings")) + if config.settings.getboolean("Authentication", "Enabled", False): + setUpAuthentication() + + startWorker(options.workerId) + + return 0 + + +if __name__ == "__main__": + try: + sys.exit(main()) + except Error as e: + print("Error: %s" % e, file=sys.stderr) + sys.exit(1) diff --git a/third_party/ci-notary-service/macappnotarizer.py b/third_party/ci-notary-service/macappnotarizer.py new file mode 100644 index 0000000..7c5840b --- /dev/null +++ b/third_party/ci-notary-service/macappnotarizer.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: BSD-2-Clause +# +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker +# SPDX-FileCopyrightText: 2023 Julius Künzel + +import sys + +from sftpnotary import authentication, config, util +from sftpnotary.exceptions import Error +from sftpnotary.macappnotarizer import NotarizeMacAppWorker + + +def parseCommandLine(): + import argparse + + parser = argparse.ArgumentParser(description="Worker for notarizing Apple macOS apps") + + # debug options + parser.add_argument("-v", "--verbose", action="count", default=0, help="increase the verbosity") + + parser.add_argument("--id", dest="workerId", help="Unique, alpha-numeric identifier of this service worker") + + parser.add_argument("--config") + + options = parser.parse_args() + return options + + +def setUpAuthentication(): + auth = authentication.GitLabJobTokenAuthentication( + apiV4Url=config.settings.get("Authentication", "GitLabAPIv4Url", ""), userAgent="org.kde.macappnotarizer" + ) + authentication.setAuthentication(auth) + + +def startWorker(workerId: str): + with util.connectToSftpServer() as sftp: + worker = NotarizeMacAppWorker(workerId, sftp) + worker.start() + + +def main(): + options = parseCommandLine() + config.loadConfig(options.config) + util.setUpServiceLogging("macappnotarizer", options.verbose) + util.loadProjectSettings(config.settings.get("General", "ProjectSettings")) + if config.settings.getboolean("Authentication", "Enabled", False): + setUpAuthentication() + + startWorker(options.workerId) + + return 0 + + +if __name__ == "__main__": + try: + sys.exit(main()) + except Error as e: + print("Error: %s" % e, file=sys.stderr) + sys.exit(1) diff --git a/third_party/ci-notary-service/macappsigner.py b/third_party/ci-notary-service/macappsigner.py new file mode 100644 index 0000000..94d3565 --- /dev/null +++ b/third_party/ci-notary-service/macappsigner.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: BSD-2-Clause +# +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker +# SPDX-FileCopyrightText: 2023 Julius Künzel + +import sys + +from sftpnotary import authentication, config, util +from sftpnotary.exceptions import Error +from sftpnotary.macappsigner import SignMacAppWorker + + +def parseCommandLine(): + import argparse + + parser = argparse.ArgumentParser(description="Worker for signing Apple macOS apps") + + # debug options + parser.add_argument("-v", "--verbose", action="count", default=0, help="increase the verbosity") + + parser.add_argument("--id", dest="workerId", help="Unique, alpha-numeric identifier of this service worker") + + parser.add_argument("--config") + + options = parser.parse_args() + return options + + +def setUpAuthentication(): + auth = authentication.GitLabJobTokenAuthentication( + apiV4Url=config.settings.get("Authentication", "GitLabAPIv4Url", ""), userAgent="org.kde.macappsigner" + ) + authentication.setAuthentication(auth) + + +def startWorker(workerId: str): + with util.connectToSftpServer() as sftp: + worker = SignMacAppWorker(workerId, sftp) + worker.start() + + +def main(): + options = parseCommandLine() + config.loadConfig(options.config) + util.setUpServiceLogging("macappsigner", options.verbose) + util.loadProjectSettings(config.settings.get("General", "ProjectSettings")) + if config.settings.getboolean("Authentication", "Enabled", False): + setUpAuthentication() + + startWorker(options.workerId) + + return 0 + + +if __name__ == "__main__": + try: + sys.exit(main()) + except Error as e: + print("Error: %s" % e, file=sys.stderr) + sys.exit(1) diff --git a/third_party/ci-notary-service/microsoftstorepublisher.py b/third_party/ci-notary-service/microsoftstorepublisher.py new file mode 100644 index 0000000..85aa74a --- /dev/null +++ b/third_party/ci-notary-service/microsoftstorepublisher.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: BSD-2-Clause +# +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + +import logging +import sys + +from sftpnotary import authentication, config, util +from sftpnotary.exceptions import Error +from sftpnotary.microsoftstoreservice import PublishOnMicrosoftStoreWorker + + +def parseCommandLine(): + import argparse + + parser = argparse.ArgumentParser(description="Worker for submitting APPXs to Microsoft Store") + + # debug options + parser.add_argument("-v", "--verbose", action="count", default=0, help="increase the verbosity") + parser.add_argument( + "--debug-authorization", + type=int, + default=0, + dest="debugAuth", + metavar="LEVEL", + help="debug level for authorization to Microsoft Store (1 or 2)", + ) + parser.add_argument( + "--debug-api-calls", + type=int, + default=0, + dest="debugApi", + metavar="LEVEL", + help="debug level for API calls to Microsoft Store (1 or 2)", + ) + + parser.add_argument("--id", dest="workerId", help="Unique, alpha-numeric identifier of this service worker") + + parser.add_argument("--config") + + options = parser.parse_args() + return options + + +def setUpAuthentication(): + auth = authentication.GitLabJobTokenAuthentication( + apiV4Url=config.settings.get("Authentication", "GitLabAPIv4Url", ""), + userAgent="org.kde.microsoftstorepublisher", + ) + authentication.setAuthentication(auth) + + +def startWorker(workerId: str): + with util.connectToSftpServer() as sftp: + worker = PublishOnMicrosoftStoreWorker(workerId, sftp) + worker.start() + + +def main(): + options = parseCommandLine() + config.loadConfig(options.config) + util.setUpServiceLogging("microsoftstorepublisher", options.verbose) + microstoreLogger = logging.getLogger("microstore") + microstoreLogger.setLevel(max(logging.DEBUG, logging.WARNING - 10 * options.verbose)) + authLogger = logging.getLogger("microstore.auth") + authLogger.setLevel(max(logging.DEBUG, logging.WARNING - 10 * options.debugAuth)) + apiLogger = logging.getLogger("microstore.api") + apiLogger.setLevel(max(logging.DEBUG, logging.WARNING - 10 * options.debugApi)) + + util.loadProjectSettings(config.settings.get("General", "ProjectSettings")) + if config.settings.getboolean("Authentication", "Enabled", False): + setUpAuthentication() + + startWorker(options.workerId) + + return 0 + + +if __name__ == "__main__": + try: + sys.exit(main()) + except Error as e: + print("Error: %s" % e, file=sys.stderr) + sys.exit(1) diff --git a/third_party/ci-notary-service/notarizemacapp.py b/third_party/ci-notary-service/notarizemacapp.py new file mode 100644 index 0000000..6c1448f --- /dev/null +++ b/third_party/ci-notary-service/notarizemacapp.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: BSD-2-Clause +# +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker +# SPDX-FileCopyrightText: 2023 Julius Künzel + +import logging +import os +import sys +import tarfile +from pathlib import Path +from tempfile import TemporaryDirectory +from typing import Optional + +from sftpnotary import config, projects, util +from sftpnotary.exceptions import Error +from sftpnotary.macappnotarizer import NotarizeMacAppJob + +log = logging.getLogger("notarizemacapp") + + +def parseCommandLine(): + import argparse + + parser = argparse.ArgumentParser(description="Notarize macOS apps with signing service") + + # debug options + parser.add_argument("-v", "--verbose", action="count", default=0, help="increase the verbosity") + + parser.add_argument("--config") + + parser.add_argument("appfile", help="the .dmg file or .app (inside tar archive) to notarize") + + options = parser.parse_args() + return options + + +def logTaskLog(logFile: Path): + log.info("Logs of remote signing:") + with open(logFile, "r", encoding="utf-8") as f: + for line in f: + log.info(line.rstrip()) + + +def notarizeMacApp(app: Path, logFolder: Path, projectPath: Optional[str], branch: Optional[str]) -> bool: + with util.connectToSftpServer() as sftp: + job = NotarizeMacAppJob( + sftp, + macAppFilePath=app, + logFolder=logFolder, + token=os.environ.get("CI_JOB_TOKEN"), + projectPath=projectPath, + branch=branch, + ) + try: + job.start() + job.waitForCompletion() + except Exception as e: # or more specific exception + log.error("Error: NotarizeMacAppJob failed", exc_info=e) + for logFile in job.logFiles: + if logFile.name == "task.log": + logTaskLog(logFile) + if not job.success: + log.error("Error: Notarizing macOS app failed") + return job.success + + +def main() -> int: + options = parseCommandLine() + config.loadConfig(options.config) + util.setUpClientLogging(log, options.verbose) + projectSettingsLocation = config.settings.get("General", "ProjectSettings", "macappnotarizer-projects.yaml") + util.loadProjectSettings( + projectSettingsLocation, + relativeTo=Path(options.config).absolute().parent, + ) + + # Ignore merge request pipelines + if os.environ.get("CI_PIPELINE_SOURCE") == "merge_request_event": + log.info("Merge request pipelines are not cleared for notarization. Skipping.") + return 0 + + # Check if it makes sense to attempt notarizing the macOS file + projectPath = os.environ["CI_PROJECT_PATH"] + branch = os.environ["CI_COMMIT_REF_NAME"] + if not projects.settings.exists(projectPath, branch): + log.info( + f"""Branch '{branch}' of project '{projectPath}' is not cleared for notarization. Skipping.\n +You can clear it by adding the branch to {projectSettingsLocation}""" + ) + return 0 + + appFilePath = Path(options.appfile) + + if appFilePath.suffix == ".app": + # Build a tarball since .app files are basically special folders + with TemporaryDirectory() as tempArchiveDir: + appArchivePath = Path(tempArchiveDir) / "shuttleArchive" + with tarfile.open(name=appArchivePath, mode="w") as archive: + archive.add(appFilePath, arcname=appFilePath.name, recursive=True) + + success = notarizeMacApp(appArchivePath, appFilePath.parent, projectPath, branch) + + if success: + # notarizeMacApp overwrites the archive with the unsigned content + # so we can just extract the archive at the same location again + util.extractTarArchive(appArchivePath, appFilePath.parent) + + else: + success = notarizeMacApp(appFilePath, appFilePath.parent, projectPath, branch) + + return 0 if success else 1 + + +if __name__ == "__main__": + try: + sys.exit(main()) + except Error as e: + print("Error: %s" % e, file=sys.stderr) + sys.exit(1) diff --git a/third_party/ci-notary-service/publishbuild.py b/third_party/ci-notary-service/publishbuild.py new file mode 100644 index 0000000..221d060 --- /dev/null +++ b/third_party/ci-notary-service/publishbuild.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: BSD-2-Clause +# +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileCopyrightText: 2023 Ben Cooksley +# SPDX-FileContributor: Ingo Klöcker + +import logging +import os +import sys +import tarfile +from pathlib import Path +from tempfile import NamedTemporaryFile + +from sftpnotary import config, projects, util +from sftpnotary.buildpublisher import PublishBuildJob +from sftpnotary.exceptions import Error + +log = logging.getLogger("publishbuild") + + +def parseCommandLine(): + import argparse + + parser = argparse.ArgumentParser(description="Publish build artifacts to a remote server (usually a web server)") + + # debug options + parser.add_argument("-v", "--verbose", action="count", default=0, help="increase the verbosity") + + parser.add_argument("--config", required=True, help="the configuration to use; required") + + parser.add_argument("--platform", required=True, help="the platform the artifacts correspond to") + + parser.add_argument("folderToPublish", help="the folder containing build artifacts to be published; required") + + options = parser.parse_args() + return options + + +def logTaskLog(logFile: Path): + log.info("Logs of remote signing:") + with open(logFile, "r", encoding="utf-8") as f: + for line in f: + log.info(line.rstrip()) + + +def publishBuild(buildArchiveFilePath: Path, projectPath: str, branch: str, platform: str) -> bool: + with util.connectToSftpServer() as sftp: + job = PublishBuildJob( + sftp, + buildArchiveFilePath=buildArchiveFilePath, + token=os.environ.get("CI_JOB_TOKEN", ""), + projectPath=projectPath, + branch=branch, + platform=platform, + ) + try: + job.start() + job.waitForCompletion() + except Exception as e: # or more specific exception + log.error("Error: PublishBuildJob failed", exc_info=e) + for logFile in job.logFiles: + if logFile.name == "task.log": + logTaskLog(logFile) + if not job.success: + log.error("Error: Publishing the build artifacts failed") + return job.success + + +def main() -> int: + options = parseCommandLine() + config.loadConfig(options.config) + util.setUpClientLogging(log, options.verbose) + projectSettingsLocation = config.settings.get("General", "ProjectSettings", "buildpublisher-projects.yaml") + util.loadProjectSettings( + projectSettingsLocation, + relativeTo=Path(options.config).absolute().parent, + ) + + # Ignore merge request pipelines + if os.environ.get("CI_PIPELINE_SOURCE") == "merge_request_event": + log.info("Merge request pipelines are not cleared for publishing. Skipping.") + return 0 + + # Check if it makes sense to attempt publishing the build + projectPath = os.environ["CI_PROJECT_PATH"] + branch = os.environ["CI_COMMIT_REF_NAME"] + platform = options.platform + if not projects.settings.exists(projectPath, branch): + log.info( + f"""Branch '{branch}' of project '{projectPath}' is not cleared for publishing. Skipping.\n +You can clear it by adding the branch to {projectSettingsLocation}""" + ) + return 0 + + # Build a tarball of the build files and trigger the publishing process + with NamedTemporaryFile(delete=False, mode="wb") as artifactArchive: + # Open our temporary file as a tarball + archive = tarfile.open(fileobj=artifactArchive, mode="w") + + # Determine the path to be archived and the files to be included + pathToArchive = Path(options.folderToPublish) + filesToInclude = os.listdir(pathToArchive) + + # Start populating it with the build artifact files + for filename in filesToInclude: + fullPath = pathToArchive / filename + archive.add(fullPath, arcname=filename, recursive=True) + + # Close it out to ensure everything is flushed to disk + # We have to use close() to ensure the file handle is fully closed otherwise 'sftp' on Windows will + # not be allowed to open the file + archive.close() + artifactArchive.close() + + success = publishBuild(Path(artifactArchive.name), projectPath, branch, platform) + + # Cleanup + os.remove(artifactArchive.name) + + return 0 if success else 1 + + +if __name__ == "__main__": + try: + sys.exit(main()) + except Error as e: + print("Error: %s" % e, file=sys.stderr) + sys.exit(1) diff --git a/third_party/ci-notary-service/publishonfdroid.py b/third_party/ci-notary-service/publishonfdroid.py new file mode 100644 index 0000000..4a7e72e --- /dev/null +++ b/third_party/ci-notary-service/publishonfdroid.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: BSD-2-Clause +# +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + +import logging +import os +import sys +from pathlib import Path +from typing import List, Optional + +from sftpnotary import config, projects, util +from sftpnotary.exceptions import Error +from sftpnotary.fdroidpublisher import PublishOnFDroidJob + +log = logging.getLogger("publishonfdroid") + + +def parseCommandLine(): + import argparse + + parser = argparse.ArgumentParser(description="Publish one or more APKs of a single app in an F-Droid repository") + + # debug options + parser.add_argument("-v", "--verbose", action="count", default=0, help="increase the verbosity") + + parser.add_argument("--config", required=True, help="the configuration to use; required") + + parser.add_argument( + "--fastlane", required=True, help="the Fastlane file containing the meta data for the APKs; required" + ) + parser.add_argument("apks", nargs="+", metavar="APK", help="the APKs to publish") + + options = parser.parse_args() + return options + + +def logTaskLog(logFile: Path): + log.info("Logs of remote signing:") + with open(logFile, "r", encoding="utf-8") as f: + for line in f: + log.info(line.rstrip()) + + +def publishApks(apks: List[Path], fastlane: Path, projectPath: Optional[str], branch: Optional[str]) -> bool: + with util.connectToSftpServer() as sftp: + job = PublishOnFDroidJob( + sftp, + apkFilePaths=apks, + fastlaneFilePath=fastlane, + token=os.environ.get("CI_JOB_TOKEN"), + projectPath=projectPath, + branch=branch, + ) + try: + job.start() + job.waitForCompletion() + except Exception as e: # or more specific exception + log.error("Error: PublishOnFDroidJob failed", exc_info=e) + for logFile in job.logFiles: + if logFile.name == "task.log": + logTaskLog(logFile) + if not job.success: + log.error("Error: Publishing the APKs failed") + return job.success + + +def main() -> int: + options = parseCommandLine() + config.loadConfig(options.config) + util.setUpClientLogging(log, options.verbose) + projectSettingsLocation = config.settings.get("General", "ProjectSettings", "fdroidpublisher-projects.yaml") + util.loadProjectSettings( + projectSettingsLocation, + relativeTo=Path(options.config).absolute().parent, + ) + + # Ignore merge request pipelines + if os.environ.get("CI_PIPELINE_SOURCE") == "merge_request_event": + log.info("Merge request pipelines are not cleared for publishing. Skipping.") + return 0 + + # Check if it makes sense to attempt publishing the APK + projectPath = os.environ["CI_PROJECT_PATH"] + branch = os.environ["CI_COMMIT_REF_NAME"] + if not projects.settings.exists(projectPath, branch): + log.info( + f"""Branch '{branch}' of project '{projectPath}' is not cleared for publishing. Skipping.\n +You can clear it by adding the branch to {projectSettingsLocation}""" + ) + return 0 + + success = publishApks([Path(apk) for apk in options.apks], Path(options.fastlane), projectPath, branch) + + return 0 if success else 1 + + +if __name__ == "__main__": + try: + sys.exit(main()) + except Error as e: + print("Error: %s" % e, file=sys.stderr) + sys.exit(1) diff --git a/third_party/ci-notary-service/publishongoogleplay.py b/third_party/ci-notary-service/publishongoogleplay.py new file mode 100644 index 0000000..4401cad --- /dev/null +++ b/third_party/ci-notary-service/publishongoogleplay.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: BSD-2-Clause +# +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + +import logging +import os +import sys +from pathlib import Path +from typing import List, Optional + +from sftpnotary import config, projects, util +from sftpnotary.exceptions import Error +from sftpnotary.googleplaypublisher import PublishOnGooglePlayJob + +log = logging.getLogger("publishongoogleplay") + + +def parseCommandLine(): + import argparse + + parser = argparse.ArgumentParser(description="Publish an AAB or one or more APKs of a single app on Google Play") + + # debug options + parser.add_argument("-v", "--verbose", action="count", default=0, help="increase the verbosity") + + parser.add_argument("--config", required=True, help="the configuration to use; required") + + parser.add_argument( + "--fastlane", required=True, help="the Fastlane file containing the meta data for the app; required" + ) + parser.add_argument("files", nargs="+", metavar="FILE", help="the AAB or the APKs to publish") + + options = parser.parse_args() + + aabs = [f for f in options.files if f.endswith(".aab")] + apks = [f for f in options.files if f.endswith(".apk")] + haveWrongFiles = len(aabs) + len(apks) < len(options.files) + haveAABandAPK = aabs and apks + haveTooManyAAB = len(aabs) > 1 + if haveWrongFiles or haveAABandAPK or haveTooManyAAB: + parser.error("You must specify either one *.aab file or one or more *.apk files.") + + return options + + +def logTaskLog(logFile: Path): + log.info("Logs of remote signing:") + with open(logFile, "r", encoding="utf-8") as f: + for line in f: + log.info(line.rstrip()) + + +def publishFiles(paths: List[Path], fastlane: Path, projectPath: Optional[str], branch: Optional[str]) -> bool: + with util.connectToSftpServer() as sftp: + job = PublishOnGooglePlayJob( + sftp, + filePaths=paths, + fastlaneFilePath=fastlane, + token=os.environ.get("CI_JOB_TOKEN"), + projectPath=projectPath, + branch=branch, + ) + try: + job.start() + job.waitForCompletion() + except Exception as e: # or more specific exception + log.error("Error: PublishOnGooglePlayJob failed", exc_info=e) + for logFile in job.logFiles: + if logFile.name == "task.log": + logTaskLog(logFile) + if not job.success: + log.error("Error: Publishing failed") + return job.success + + +def main() -> int: + options = parseCommandLine() + config.loadConfig(options.config) + util.setUpClientLogging(log, options.verbose) + projectSettingsLocation = config.settings.get("General", "ProjectSettings", "googleplaypublisher-projects.yaml") + util.loadProjectSettings( + projectSettingsLocation, + relativeTo=Path(options.config).absolute().parent, + ) + + # Ignore merge request pipelines + if os.environ.get("CI_PIPELINE_SOURCE") == "merge_request_event": + log.info("Merge request pipelines are not cleared for publishing. Skipping.") + return 0 + + # Check if it makes sense to attempt publishing the AAB/APKs + projectPath = os.environ["CI_PROJECT_PATH"] + branch = os.environ["CI_COMMIT_REF_NAME"] + if not projects.settings.exists(projectPath, branch): + log.info( + f"""Branch '{branch}' of project '{projectPath}' is not cleared for publishing. Skipping.\n +You can clear it by adding the branch to {projectSettingsLocation}""" + ) + return 0 + + success = publishFiles([Path(f) for f in options.files], Path(options.fastlane), projectPath, branch) + + return 0 if success else 1 + + +if __name__ == "__main__": + try: + sys.exit(main()) + except Error as e: + print("Error: %s" % e, file=sys.stderr) + sys.exit(1) diff --git a/third_party/ci-notary-service/publishonmicrosoftstore.py b/third_party/ci-notary-service/publishonmicrosoftstore.py new file mode 100644 index 0000000..c47e191 --- /dev/null +++ b/third_party/ci-notary-service/publishonmicrosoftstore.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: BSD-2-Clause +# +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + +import logging +import os +import sys +from pathlib import Path + +from sftpnotary import config, projects, util +from sftpnotary.exceptions import Error +from sftpnotary.microsoftstoreclient import PublishOnMicrosoftStoreJob + +log = logging.getLogger("publishonmicrosoftstore") + + +def parseCommandLine(): + import argparse + + parser = argparse.ArgumentParser(description="Submit an app to the Microsoft Store") + + # debug options + parser.add_argument("-v", "--verbose", action="count", default=0, help="increase the verbosity") + + parser.add_argument("--config", required=True, help="the configuration to use; required") + + parser.add_argument("appxuploadFile", help="the .appxupload file to submit") + + options = parser.parse_args() + return options + + +def logTaskLog(logFile: Path): + log.info("Logs of remote signing:") + with open(logFile, "r", encoding="utf-8") as f: + for line in f: + log.info(line.rstrip()) + + +def submitAppx(appx: Path, projectPath: str, branch: str) -> bool: + with util.connectToSftpServer() as sftp: + job = PublishOnMicrosoftStoreJob( + sftp, + appxFilePath=appx, + token=os.environ.get("CI_JOB_TOKEN"), + projectPath=projectPath, + branch=branch, + ) + try: + job.start() + job.waitForCompletion() + except Exception as e: # or more specific exception + log.error("Error: PublishOnMicrosoftStoreJob failed", exc_info=e) + for logFile in job.logFiles: + if logFile.name == "task.log": + logTaskLog(logFile) + if not job.success: + log.error("Error: Submitting the APPX failed") + return job.success + + +def main() -> int: + options = parseCommandLine() + config.loadConfig(options.config) + util.setUpClientLogging(log, options.verbose) + projectSettingsLocation = config.settings.get("General", "ProjectSettings", "microsoftstorepublisher-projects.yaml") + util.loadProjectSettings( + projectSettingsLocation, + relativeTo=Path(options.config).absolute().parent, + ) + + # Ignore merge request pipelines + if os.environ.get("CI_PIPELINE_SOURCE") == "merge_request_event": + log.info("Merge request pipelines are not cleared for publishing. Skipping.") + return 0 + + # Check if it makes sense to attempt publishing the APPX + projectPath = os.environ["CI_PROJECT_PATH"] + branch = os.environ["CI_COMMIT_REF_NAME"] + if not projects.settings.exists(projectPath, branch): + log.info( + f"""Branch '{branch}' of project '{projectPath}' is not cleared for publishing. Skipping.\n +You can clear it by adding the branch to {projectSettingsLocation}""" + ) + return 0 + + success = submitAppx(Path(options.appxuploadFile), projectPath, branch) + + return 0 if success else 1 + + +if __name__ == "__main__": + try: + sys.exit(main()) + except Error as e: + print("Error: %s" % e, file=sys.stderr) + sys.exit(1) diff --git a/third_party/ci-notary-service/publishonpypi.py b/third_party/ci-notary-service/publishonpypi.py new file mode 100644 index 0000000..f273f5a --- /dev/null +++ b/third_party/ci-notary-service/publishonpypi.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: BSD-2-Clause +# +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileCopyrightText: 2023 Ben Cooksley +# SPDX-FileContributor: Ingo Klöcker + +import logging +import os +import sys +import tarfile +from pathlib import Path +from tempfile import NamedTemporaryFile + +from sftpnotary import config, projects, util +from sftpnotary.exceptions import Error +from sftpnotary.pypipublisher import PublishPyPiJob + +log = logging.getLogger("publishonpypi") + + +def parseCommandLine(): + import argparse + + parser = argparse.ArgumentParser(description="Publish Python packages to a PyPi repository") + + # debug options + parser.add_argument("-v", "--verbose", action="count", default=0, help="increase the verbosity") + + parser.add_argument("--config", required=True, help="the configuration to use; required") + + parser.add_argument( + "--repository", required=True, help="the repository the package should be published to; required" + ) + + parser.add_argument( + "folderToPublish", help='the folder containing the package to be published (eg. the "dist" folder); required' + ) + + options = parser.parse_args() + return options + + +def logTaskLog(logFile: Path): + log.info("Logs of remote signing:") + with open(logFile, "r", encoding="utf-8") as f: + for line in f: + log.info(line.rstrip()) + + +def publishPyPi(archiveFilePath: Path, projectPath: str, branch: str, repository: str, logDestination: Path) -> bool: + with util.connectToSftpServer() as sftp: + job = PublishPyPiJob( + sftp, + archiveFilePath=archiveFilePath, + token=os.environ.get("CI_JOB_TOKEN"), + projectPath=projectPath, + branch=branch, + repository=repository, + ) + try: + job.start() + job.waitForCompletion(logDestination.parent) + except Exception as e: # or more specific exception + log.error("Error: PublishPyPiJob failed", exc_info=e) + for logFile in job.logFiles: + if logFile.name == "task.log": + logTaskLog(logFile) + if not job.success: + log.error("Error: Publishing to PyPi failed") + return job.success + + +def main() -> int: + options = parseCommandLine() + config.loadConfig(options.config) + util.setUpClientLogging(log, options.verbose) + projectSettingsLocation = config.settings.get("General", "ProjectSettings", "pypipublisher-projects.yaml") + util.loadProjectSettings( + projectSettingsLocation, + relativeTo=Path(options.config).absolute().parent, + ) + + # Ignore merge request pipelines + if os.environ.get("CI_PIPELINE_SOURCE") == "merge_request_event": + log.info("Merge request pipelines are not cleared for publishing. Skipping.") + return 0 + + # Check if it makes sense to attempt publishing to pypi + projectPath = os.environ["CI_PROJECT_PATH"] + branch = os.environ["CI_COMMIT_REF_NAME"] + repository = options.repository + if not projects.settings.exists(projectPath, branch): + log.info( + f"""Branch '{branch}' of project '{projectPath}' is not cleared for publishing. Skipping.\n +You can clear it by adding the branch to {projectSettingsLocation}""" + ) + return 0 + + # Build a tarball of the wheel files and trigger the publishing process + with NamedTemporaryFile() as wheelArchive: + # Open our temporary file as a tarball + archive = tarfile.open(fileobj=wheelArchive, mode="w") + + # Determine the path to be archived and the files to be included + pathToArchive = Path(options.folderToPublish) + filesToInclude = os.listdir(pathToArchive) + + # Start populating it with the wheel files + for filename in filesToInclude: + fullPath = pathToArchive / filename + archive.add(fullPath, arcname=filename, recursive=True) + + # Close it out to ensure everything is flushed to disk + archive.close() + wheelArchive.flush() + + success = publishPyPi(Path(wheelArchive.name), projectPath, branch, repository, pathToArchive) + + return 0 if success else 1 + + +if __name__ == "__main__": + try: + sys.exit(main()) + except Error as e: + print("Error: %s" % e, file=sys.stderr) + sys.exit(1) diff --git a/third_party/ci-notary-service/publishwebsite.py b/third_party/ci-notary-service/publishwebsite.py new file mode 100644 index 0000000..bc493f1 --- /dev/null +++ b/third_party/ci-notary-service/publishwebsite.py @@ -0,0 +1,120 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: BSD-2-Clause +# +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileCopyrightText: 2023 Ben Cooksley +# SPDX-FileContributor: Ingo Klöcker + +import logging +import os +import sys +import tarfile +from pathlib import Path +from tempfile import NamedTemporaryFile + +from sftpnotary import config, projects, util +from sftpnotary.exceptions import Error +from sftpnotary.websitepublisher import PublishWebsiteJob + +log = logging.getLogger("publishwebsite") + + +def parseCommandLine(): + import argparse + + parser = argparse.ArgumentParser(description="Publish files via RSync to a remote server (usually a web server)") + + # debug options + parser.add_argument("-v", "--verbose", action="count", default=0, help="increase the verbosity") + + parser.add_argument("--config", required=True, help="the configuration to use; required") + + parser.add_argument("folderToPublish", help="the folder to be published to the remote server; required") + + options = parser.parse_args() + return options + + +def logTaskLog(logFile: Path): + log.info("Logs of remote signing:") + with open(logFile, "r", encoding="utf-8") as f: + for line in f: + log.info(line.rstrip()) + + +def publishWebsite(websiteArchiveFilePath: Path, projectPath: str, branch: str) -> bool: + with util.connectToSftpServer() as sftp: + job = PublishWebsiteJob( + sftp, + websiteArchiveFilePath=websiteArchiveFilePath, + token=os.environ.get("CI_JOB_TOKEN", ""), + projectPath=projectPath, + branch=branch, + ) + try: + job.start() + job.waitForCompletion() + except Exception as e: # or more specific exception + log.error("Error: PublishWebsiteJob failed", exc_info=e) + for logFile in job.logFiles: + if logFile.name == "task.log": + logTaskLog(logFile) + if not job.success: + log.error("Error: Publishing the website failed") + return job.success + + +def main() -> int: + options = parseCommandLine() + config.loadConfig(options.config) + util.setUpClientLogging(log, options.verbose) + projectSettingsLocation = config.settings.get("General", "ProjectSettings", "websitepublisher-projects.yaml") + util.loadProjectSettings( + projectSettingsLocation, + relativeTo=Path(options.config).absolute().parent, + ) + + # Ignore merge request pipelines + if os.environ.get("CI_PIPELINE_SOURCE") == "merge_request_event": + log.info("Merge request pipelines are not cleared for publishing. Skipping.") + return 0 + + # Check if it makes sense to attempt publishing the website + projectPath = os.environ["CI_PROJECT_PATH"] + branch = os.environ["CI_COMMIT_REF_NAME"] + if not projects.settings.exists(projectPath, branch): + log.info( + f"""Branch '{branch}' of project '{projectPath}' is not cleared for publishing. Skipping.\n +You can clear it by adding the branch to {projectSettingsLocation}""" + ) + return 0 + + # Build a tarball of the website files and trigger the publishing process + with NamedTemporaryFile() as websiteArchive: + # Open our temporary file as a tarball + archive = tarfile.open(fileobj=websiteArchive, mode="w") + + # Determine the path to be archived and the files to be included + pathToArchive = Path(options.folderToPublish) + filesToInclude = os.listdir(pathToArchive) + + # Start populating it with the website files + for filename in filesToInclude: + fullPath = pathToArchive / filename + archive.add(fullPath, arcname=filename, recursive=True) + + # Close it out to ensure everything is flushed to disk + archive.close() + websiteArchive.flush() + + success = publishWebsite(Path(websiteArchive.name), projectPath, branch) + + return 0 if success else 1 + + +if __name__ == "__main__": + try: + sys.exit(main()) + except Error as e: + print("Error: %s" % e, file=sys.stderr) + sys.exit(1) diff --git a/third_party/ci-notary-service/pypipublisher.py b/third_party/ci-notary-service/pypipublisher.py new file mode 100644 index 0000000..5400782 --- /dev/null +++ b/third_party/ci-notary-service/pypipublisher.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: BSD-2-Clause +# +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + +import sys + +from sftpnotary import authentication, config, util +from sftpnotary.exceptions import Error +from sftpnotary.pypipublisher import PublishPyPiWorker + + +def parseCommandLine(): + import argparse + + parser = argparse.ArgumentParser(description="Worker for publishing Python packages to a PyPi repository") + + # debug options + parser.add_argument("-v", "--verbose", action="count", default=0, help="increase the verbosity") + + parser.add_argument("--id", dest="workerId", help="Unique, alpha-numeric identifier of this service worker") + + parser.add_argument("--config") + + options = parser.parse_args() + return options + + +def setUpAuthentication(): + auth = authentication.GitLabJobTokenAuthentication( + apiV4Url=config.settings.get("Authentication", "GitLabAPIv4Url", ""), userAgent="org.kde.pypipublisher" + ) + authentication.setAuthentication(auth) + + +def startWorker(workerId: str): + with util.connectToSftpServer() as sftp: + worker = PublishPyPiWorker(workerId, sftp) + worker.start() + + +def main(): + options = parseCommandLine() + config.loadConfig(options.config) + util.setUpServiceLogging("pypipublisher", options.verbose) + util.loadProjectSettings(config.settings.get("General", "ProjectSettings")) + if config.settings.getboolean("Authentication", "Enabled", False): + setUpAuthentication() + + startWorker(options.workerId) + + return 0 + + +if __name__ == "__main__": + try: + sys.exit(main()) + except Error as e: + print("Error: %s" % e, file=sys.stderr) + sys.exit(1) diff --git a/third_party/ci-notary-service/pyproject.toml b/third_party/ci-notary-service/pyproject.toml new file mode 100644 index 0000000..7060f05 --- /dev/null +++ b/third_party/ci-notary-service/pyproject.toml @@ -0,0 +1,72 @@ +# SPDX-License-Identifier: BSD-2-Clause +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + +[build-system] +requires = ["setuptools>=63.0"] +build-backend = "setuptools.build_meta" + +[project] +name = "sftpnotary" +version = "0.0.1" +description = "An SFTP-backed services provider" +readme = "README.md" +requires-python = ">=3.10" +authors = [ + { name="Ingo Klöcker", email="dev@ingo-kloecker.de" }, +] +classifiers = [ + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", +] +dynamic = ["dependencies"] + +[project.urls] +"Homepage" = "https://invent.kde.org/kloecker/ci-services" +# "Bug Tracker" = "https://bugs.kde.org" + +[tool.bandit] +# exclude tests because bandit doesn't like the asserts +exclude_dirs = ["tests", ".tox", ".venv"] +# disable warning for "import subprocess"; we get warnings on usage +skips = ["B404"] + +[tool.black] +line-length = 120 + +[tool.coverage.run] +branch = true + +[tool.isort] +profile = "black" +line_length = 120 +order_by_type = false +skip_gitignore = true +src_paths = ["sftpnotary", "tests"] + +[tool.mypy] +python_version = "3.10" +# strict = true +show_column_numbers = true +show_error_codes = true + +[[tool.mypy.overrides]] +module = "tests.*" +allow_untyped_defs = true +allow_untyped_calls = true + +[[tool.mypy.overrides]] +module = [ + "pytest" +] +ignore_missing_imports = true + +[tool.setuptools] +packages = ["sftpnotary"] + +[tool.setuptools.dynamic] +dependencies = { file="requirements.txt" } diff --git a/third_party/ci-notary-service/requirements.txt b/third_party/ci-notary-service/requirements.txt new file mode 100644 index 0000000..d5855cd --- /dev/null +++ b/third_party/ci-notary-service/requirements.txt @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +PyYAML +paramiko +requests + +#bcrypt==4.0.1 +#cffi==1.15.1 +#cryptography==40.0.2 +#paramiko==3.1.0 +#pycparser==2.21 +#PyNaCl==1.5.0 diff --git a/third_party/ci-notary-service/requirements_dev.txt b/third_party/ci-notary-service/requirements_dev.txt new file mode 100644 index 0000000..ff53729 --- /dev/null +++ b/third_party/ci-notary-service/requirements_dev.txt @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +bandit[toml]==1.8.6 +black==23.11.0 +coverage[toml] +flake8==6.1.0 +isort==5.12.0 +pre-commit +pytest +tox +yamllint==1.33.0 + +mypy==1.7.0 +types-paramiko +types-PyYAML +types-requests diff --git a/third_party/ci-notary-service/requirements_fdroid.txt b/third_party/ci-notary-service/requirements_fdroid.txt new file mode 100644 index 0000000..e561138 --- /dev/null +++ b/third_party/ci-notary-service/requirements_fdroid.txt @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +-r requirements.txt + +fdroidserver==2.4.0 +androguard==4.1.3 diff --git a/third_party/ci-notary-service/requirements_microsoftstore.txt b/third_party/ci-notary-service/requirements_microsoftstore.txt new file mode 100644 index 0000000..e18d486 --- /dev/null +++ b/third_party/ci-notary-service/requirements_microsoftstore.txt @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +-r requirements.txt + +azure-storage-blob +markdownify + +git+https://invent.kde.org/kloecker/microstore.git diff --git a/third_party/ci-notary-service/requirements_pypi.txt b/third_party/ci-notary-service/requirements_pypi.txt new file mode 100644 index 0000000..9054ef9 --- /dev/null +++ b/third_party/ci-notary-service/requirements_pypi.txt @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +-r requirements.txt + +pkginfo +twine diff --git a/third_party/ci-notary-service/sftpnotary/__init__.py b/third_party/ci-notary-service/sftpnotary/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/third_party/ci-notary-service/sftpnotary/aabsigner.py b/third_party/ci-notary-service/sftpnotary/aabsigner.py new file mode 100644 index 0000000..4459758 --- /dev/null +++ b/third_party/ci-notary-service/sftpnotary/aabsigner.py @@ -0,0 +1,156 @@ +# SPDX-License-Identifier: BSD-2-Clause +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + +import logging +from pathlib import Path +from tempfile import TemporaryDirectory +from typing import Optional + +import sftpnotary.log +from sftpnotary import apkutils, config, projects, util +from sftpnotary.core import SignFileResponse, SignSingleFileJob, SingleFileRequest, TaskProcessor, Worker +from sftpnotary.exceptions import Error +from sftpnotary.sftp import SFTPClient, SFTPError + +log = logging.getLogger(__name__) + +SignAabRequest = SingleFileRequest +SignAabResponse = SignFileResponse + + +class SignAabJob(SignSingleFileJob): + def __init__( + self, + sftp: SFTPClient, + aabFilePath: Path, + token: Optional[str] = None, + projectPath: Optional[str] = None, + branch: Optional[str] = None, + ): + super().__init__(sftp, aabFilePath) + + self.request = SignAabRequest(fileName=aabFilePath.name, token=token, projectPath=projectPath, branch=branch) + + def start(self): + self.uploadUnsignedFile() + self.task.putRequest(self.request) + self.taskQueue.commitTask(self.task) + + def waitForCompletion(self): + self.taskQueue.waitForCompletion(self.task) + log.debug(f"Fetching response of task '{self.task.id}' ...") + response = None + try: + response = self.task.fetchResponse(SignAabResponse) + except SFTPError as e: + log.error("Error: %s", e) + if response is None: + log.error("Error: Got no response. Task failed.") + elif not response.signedFileName: + log.error("Error: No signed file to download.") + elif "/" in response.signedFileName: + log.error(f"Error: Suspicious file name of signed file: {response.signedFileName!r}.") + else: + try: + remotePath = self.task.path() / response.signedFileName + localPath = self.localFilePath # overwrite original (unsigned) file + self.sftp.download(remotePath, localPath) + self.success = True + except SFTPError as e: + log.error("Error: %s", e) + self.downloadLogFiles(self.localFilePath.parent) + self.taskQueue.removeTask(self.task) + + +class SignAabBaseProcessor(TaskProcessor): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.jarsignerPath = config.settings.getPath("GooglePlayPublishing", "JarsignerPath") + + def getProjectSetting(self, name, required=True, default=None): + value = projects.settings.get(self.request.projectPath, self.request.branch, name, default=default) + if required and not value: + raise Error( + f"Project setting '{name}' not set for branch {self.request.branch} " + f"of project {self.request.projectPath}" + ) + return value + + def verifyApplicationId(self, filePaths, allowedApplicationId): + for filePath in filePaths: + applicationId = apkutils.getApplicationId(filePath) + if applicationId != allowedApplicationId: + raise Error( + f"The application ID of {filePath.name} ({applicationId}) did not match the allowed application ID " + f"({allowedApplicationId})." + ) + + def signAab(self, aabFilePath): + workingDirectory = aabFilePath.parent + aabFileName = aabFilePath.name + signedAabFileName = "signed.aab" + + keystore = projects.settings.getPath( + self.request.projectPath, + self.request.branch, + "uploadkeystore", + config.settings.getPath("GooglePlayPublishing", "UploadKeyStore"), + ) + if not keystore: + raise Error( + f"Project setting 'uploadkeystore' not set for branch {self.request.branch} " + f"of project {self.request.projectPath}" + ) + keystorepass = self.getProjectSetting( + "uploadkeystorepass", default=config.settings.get("GooglePlayPublishing", "UploadKeyStorePass") + ) + if keystorepass.startswith("file:~"): + keystorepass = f"file:{Path(keystorepass[5:]).expanduser()}" + keyalias = self.getProjectSetting( + "uploadkeyalias", default=config.settings.get("GooglePlayPublishing", "UploadKeyAlias") + ) + + command = [self.jarsignerPath, "-verbose", "-sigalg", "SHA256withRSA", "-digestalg", "SHA-256"] + command += ["-keystore", Path(keystore)] + if keystorepass.startswith("file:"): + command += ["-storepass:file", keystorepass[5:]] + elif keystorepass.startswith("env:"): + command += ["-storepass:env", keystorepass[4:]] + else: + command += ["-storepass", keystorepass] + command += ["-signedjar", signedAabFileName, aabFileName, keyalias] + commandToLog = sftpnotary.log.maskFollowingItem(command, "-storepass") + util.runCommand(command, commandToLog=commandToLog, cwd=workingDirectory) + + return workingDirectory / signedAabFileName + + +class SignAabProcessor(SignAabBaseProcessor): + requestClass = SignAabRequest + + def doProcess(self): + remoteAabFilePath = self.task.path() / self.request.fileName + with TemporaryDirectory() as workPathName: + workPath = Path(workPathName) + # use simple file names locally to avoid issues with user provided file names + localAabFilePath = workPath / "unsigned.aab" + self.sftp.download(remoteAabFilePath, localAabFilePath) + + allowedApplicationId = projects.settings.get(self.request.projectPath, self.request.branch, "applicationid") + self.verifyApplicationId([localAabFilePath], allowedApplicationId) + localSignedAabFilePath = self.signAab(localAabFilePath) + + try: + # we assume a single suffix + remoteSignedAabFileName = f"{remoteAabFilePath.stem}-signed{remoteAabFilePath.suffix}" + self.sftp.upload(localSignedAabFilePath, self.task.path() / remoteSignedAabFileName) + return SignAabResponse(signedFileName=remoteSignedAabFileName) + except Error as e: + log.error("Error: %s", e) + except SFTPError as e: + log.error("Error: %s", e) + + +class SignAabWorker(Worker): + processorClass = SignAabProcessor diff --git a/third_party/ci-notary-service/sftpnotary/apksigner.py b/third_party/ci-notary-service/sftpnotary/apksigner.py new file mode 100644 index 0000000..ecce7ef --- /dev/null +++ b/third_party/ci-notary-service/sftpnotary/apksigner.py @@ -0,0 +1,138 @@ +# SPDX-License-Identifier: BSD-2-Clause +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + +import logging +from pathlib import Path +from tempfile import TemporaryDirectory +from typing import Optional + +import sftpnotary.log +from sftpnotary import apkutils, config, projects, util +from sftpnotary.core import SignFileResponse, SignSingleFileJob, SingleFileRequest, TaskProcessor, Worker +from sftpnotary.exceptions import Error +from sftpnotary.sftp import SFTPClient, SFTPError + +log = logging.getLogger(__name__) + +SignApkRequest = SingleFileRequest +SignApkResponse = SignFileResponse + + +class SignApkJob(SignSingleFileJob): + def __init__( + self, + sftp: SFTPClient, + apkFilePath: Path, + token: Optional[str] = None, + projectPath: Optional[str] = None, + branch: Optional[str] = None, + ): + super().__init__(sftp, apkFilePath) + + self.request = SignApkRequest(fileName=apkFilePath.name, token=token, projectPath=projectPath, branch=branch) + + def start(self): + self.uploadUnsignedFile() + self.task.putRequest(self.request) + self.taskQueue.commitTask(self.task) + + def waitForCompletion(self): + self.taskQueue.waitForCompletion(self.task) + log.debug(f"Fetching response of task '{self.task.id}' ...") + response = None + try: + response = self.task.fetchResponse(SignApkResponse) + except SFTPError as e: + log.error("Error: %s", e) + if response is None: + log.error("Error: Got no response. Task failed.") + elif not response.signedFileName: + log.error("Error: No signed file to download.") + elif "/" in response.signedFileName: + log.error(f"Error: Suspicious file name of signed file: {response.signedFileName!r}.") + else: + try: + remotePath = self.task.path() / response.signedFileName + localPath = self.localFilePath # overwrite original (unsigned) file + self.sftp.download(remotePath, localPath) + self.success = True + except SFTPError as e: + log.error("Error: %s", e) + self.downloadLogFiles(self.localFilePath.parent) + self.taskQueue.removeTask(self.task) + + +class SignApkProcessor(TaskProcessor): + requestClass = SignApkRequest + + def doProcess(self): + remoteApkFilePath = self.task.path() / self.request.fileName + with TemporaryDirectory() as workPathName: + workPath = Path(workPathName) + # use simple file names locally to avoid issues with user provided file names + localApkFilePath = workPath / "unsigned.apk" + localSignedApkFileName = "signed.apk" + self.sftp.download(remoteApkFilePath, localApkFilePath) + self.verifyApplicationId(localApkFilePath) + self.signApk(localApkFilePath, localSignedApkFileName) + try: + # we assume a single suffix + remoteSignedApkFileName = f"{remoteApkFilePath.stem}-signed{remoteApkFilePath.suffix}" + self.sftp.upload(workPath / localSignedApkFileName, self.task.path() / remoteSignedApkFileName) + return SignApkResponse(signedFileName=remoteSignedApkFileName) + except Error as e: + log.error("Error: %s", e) + except SFTPError as e: + log.error("Error: %s", e) + + def verifyApplicationId(self, apkFilePath): + applicationId = apkutils.getApplicationId(apkFilePath) + allowedApplicationId = projects.settings.get(self.request.projectPath, self.request.branch, "applicationid") + if applicationId != allowedApplicationId: + raise Error( + f"The application ID of the APK ({applicationId}) did not match the allowed application ID " + f"({allowedApplicationId})." + ) + + def signApk(self, apkFilePath, signedApkFileName): + workingDirectory = apkFilePath.parent + apkFileName = apkFilePath.name + alignedApkFileName = "aligned.apk" + sdkToolsPath = config.settings.getPath("ApkSigning", "SDKToolsPath") + + zipalignPath = Path(sdkToolsPath) / "zipalign" if sdkToolsPath else "zipalign" + command = [ + zipalignPath, + "-v", # verbose + "-p", # page-align uncompressed .so files + "4", # align other files to 4 bytes + apkFileName, + alignedApkFileName, + ] + util.runCommand(command, cwd=workingDirectory) + + keystore = projects.settings.getPath( + self.request.projectPath, self.request.branch, "keystore", config.settings.getPath("ApkSigning", "KeyStore") + ) + keystorepass = projects.settings.get( + self.request.projectPath, + self.request.branch, + "keystorepass", + config.settings.get("ApkSigning", "KeyStorePass"), + ) + if keystorepass.startswith("file:~"): + keystorepass = f"file:{Path(keystorepass[5:]).expanduser()}" + apksignerPath = Path(sdkToolsPath) / "apksigner" if sdkToolsPath else "apksigner" + command = [apksignerPath, "sign", "-v"] + if keystore: + command += ["--ks", Path(keystore)] + if keystorepass: + command += ["--ks-pass", keystorepass] + command += ["--out", signedApkFileName, alignedApkFileName] + commandToLog = sftpnotary.log.maskFollowingItem(command, "--ks-pass") + util.runCommand(command, commandToLog=commandToLog, cwd=workingDirectory) + + +class SignApkWorker(Worker): + processorClass = SignApkProcessor diff --git a/third_party/ci-notary-service/sftpnotary/apkutils.py b/third_party/ci-notary-service/sftpnotary/apkutils.py new file mode 100644 index 0000000..07f0db1 --- /dev/null +++ b/third_party/ci-notary-service/sftpnotary/apkutils.py @@ -0,0 +1,193 @@ +# SPDX-License-Identifier: BSD-2-Clause +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + +import logging +import re + +from sftpnotary import config, util +from sftpnotary.exceptions import Error + +log = logging.getLogger(__name__) + + +def getApplicationId(apkOrAabFilePath): + if apkOrAabFilePath.suffix == ".aab": + return getApplicationIdFromAab(apkOrAabFilePath) + elif apkOrAabFilePath.suffix == ".apk": + return getApplicationIdFromApk(apkOrAabFilePath) + + raise Error(f"Unsupported file format {apkOrAabFilePath.suffix}") + + +def getApplicationIdFromAab(aabFilePath): + workingDirectory = aabFilePath.parent + aabFileName = aabFilePath.name + bundletoolJarPath = config.settings.getPath("ApkSigning", "BundletoolJarPath") + command = ["java", "-jar", bundletoolJarPath, "dump", "manifest", "--bundle", aabFileName] + result = util.runCommand(command, cwd=workingDirectory) + if not result.stdout: + raise Error("bundletool did not print the AndroidManifest.xml of the base module") + # XML processing is dangerous; therefore, simply parse the XML as text + # https://docs.python.org/3/library/xml.html#xml-vulnerabilities + for line in result.stdout.splitlines(): + # look for a line like .yml + re.compile(f"{escapedAppId}\\.yml"), + # files in / folders: + # images/featureGraphic.png, images/icon.png + re.compile(f"{escapedAppId}/{localeID}/images/featureGraphic\\.png"), + re.compile(f"{escapedAppId}/{localeID}/images/icon\\.png"), + # images/phoneScreenshots/*.png + re.compile(f"{escapedAppId}/{localeID}/images/phoneScreenshots/{notEmptyStarGlob}\\.png"), + # full_description.txt, short_description.txt, title.txt + re.compile(f"{escapedAppId}/{localeID}/full_description\\.txt"), + re.compile(f"{escapedAppId}/{localeID}/short_description\\.txt"), + re.compile(f"{escapedAppId}/{localeID}/title\\.txt"), + ] + filteredNames = [name for name in filteredNames if any(regex.fullmatch(name) for regex in expectedNamesREs)] + unexpectedNames = sorted(set(names) - set(filteredNames)) + unexpectedNames = [n for n in unexpectedNames if not n.endswith("/")] # remove folder names + if unexpectedNames: + log.warning(f"Found unexpected files in the Fastlane zip file: {unexpectedNames}") + + return filteredNames diff --git a/third_party/ci-notary-service/sftpnotary/appleutils.py b/third_party/ci-notary-service/sftpnotary/appleutils.py new file mode 100644 index 0000000..ba07d8a --- /dev/null +++ b/third_party/ci-notary-service/sftpnotary/appleutils.py @@ -0,0 +1,189 @@ +# SPDX-License-Identifier: BSD-2-Clause +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker +# SPDX-FileCopyrightText: 2023 Julius Künzel + +import logging +import plistlib +import tarfile +from pathlib import Path +from tempfile import TemporaryDirectory +from typing import Type + +from sftpnotary import config, util +from sftpnotary.core import SignFileResponse, SignSingleFileJob, Task, TaskProcessor +from sftpnotary.exceptions import Error +from sftpnotary.sftp import SFTPClient, SFTPError + +log = logging.getLogger(__name__) + + +def getPlistApplicationId(plistFilePath: Path): + with open(plistFilePath, "rb") as plfile: + pl = plistlib.load(plfile) + + applicationId = pl["CFBundleIdentifier"] + return applicationId + + +def getAppApplicationId(appFilePath: Path): + plistFile = appFilePath / "Contents" / "Info.plist" + + return getPlistApplicationId(plistFile) + + +def _extractAppFoldersWithPlistFile(dmgFilePath: Path, extractTo: Path, appGlob: str): + workingDirectory = dmgFilePath.parent + SevenZPath = config.settings.getPath("AppleTools", "SevenZipPath") or "7zz" + + command = [ + SevenZPath, + "x", + f"-i!{appGlob}/*/*.plist", + f"-o{extractTo}", + dmgFilePath, + ] + util.runCommand(command, cwd=workingDirectory) + + return sorted(extractTo.glob(appGlob)) + + +def getDmgApplicationId(dmgFilePath: Path): + with TemporaryDirectory() as tempPathName: + appLocations = [] + appLocations.extend( + _extractAppFoldersWithPlistFile(dmgFilePath, Path(tempPathName) / "extracteddmgapp", appGlob="*/*.app") + ) + appLocations.extend( + _extractAppFoldersWithPlistFile(dmgFilePath, Path(tempPathName) / "extractedapp", appGlob="*.app") + ) + + if len(appLocations) > 1: + raise Error("More than one *.app was found.") + elif not appLocations: + raise Error("No *.app with a *.plist was found to verify the application id of the DMG.") + + return getAppApplicationId(appLocations[0]) + + +def getApplicationId(filePath: Path): + if filePath.suffix == ".app": + return getAppApplicationId(filePath) + elif filePath.suffix == ".dmg": + return getDmgApplicationId(filePath) + else: + raise Error( + f"File {filePath} has unsupported file extension {filePath.suffix}. Can not identify application id" + ) + + +def verifyApplicationId(filePath: Path, allowedApplicationId: str): + applicationId = getApplicationId(filePath) + + if not applicationId: + raise Error( + "The application ID is empty, which may indicate that required " + "MACOSX_BUNDLE_* properties are not set in the associated cmake target." + ) + elif applicationId != allowedApplicationId: + raise Error( + f"The application ID of {filePath.name} ({applicationId}) did not match the allowed application ID " + f"({allowedApplicationId}).\nYou should compare the MACOSX_BUNDLE_GUI_IDENTIFIER " + "cmake target property set in the associated project with those at " + "https://invent.kde.org/sysadmin/ci-utilities/-/tree/master/signing" + ) + + +class AppleJob(SignSingleFileJob): + def __init__(self, sftp: SFTPClient, macAppFilePath: Path, logFolder: Path): + super().__init__(sftp, macAppFilePath) + self.logFolder = logFolder + + def start(self): + self.uploadUnsignedFile() + self.task.putRequest(self.request) + self.taskQueue.commitTask(self.task) + + def waitForCompletion(self): + self.taskQueue.waitForCompletion(self.task) + log.debug(f"Fetching response of task '{self.task.id}' ...") + response = None + try: + response = self.task.fetchResponse(self.responseClass) + except SFTPError as e: + log.error("Error: %s", e) + if response is None: + log.error("Error: Got no response. Task failed.") + elif not response.signedFileName: + log.error("Error: No signed file to download.") + elif "/" in response.signedFileName: + log.error(f"Error: Suspicious file name of signed file: {response.signedFileName!r}.") + else: + try: + remotePath = self.task.path() / response.signedFileName + localPath = self.localFilePath # overwrite original (unsigned) file + self.sftp.download(remotePath, localPath) + self.success = True + except SFTPError as e: + log.error("Error: %s", e) + self.downloadLogFiles(self.logFolder) + self.taskQueue.removeTask(self.task) + + +class AppleTaskProcessor(TaskProcessor): + resultNameSuffix = "" + responseClass: Type[SignFileResponse] + + def extractAppFromTar(self, workPath: Path, archiveFilePath: Path): + # unpack archive + util.extractTarArchive(archiveFilePath, workPath) + appLocations = sorted(workPath.glob("*.app")) + + if len(appLocations) > 1: + raise Error(f"More than one ({len(appLocations)}) *.app was found inside archive.") + elif not appLocations: + raise Error("No *.app was found inside the archive.") + + return appLocations[0] + + def downloadApp(self, workPath: Path, remoteFilePath: Path): + fileExtension = util.getFileSuffix(remoteFilePath) + if fileExtension == ".dmg": + # use simple file names locally to avoid issues with user provided file names + localFilePath = workPath / f"original{fileExtension}" + self.sftp.download(remoteFilePath, localFilePath) + else: + archiveFilePath = workPath / f"archive{fileExtension}" + self.sftp.download(remoteFilePath, archiveFilePath) + if not tarfile.is_tarfile(archiveFilePath): + raise Error( + f"The file proposed for signing or notarization has the extension {fileExtension} " + "and is no archive. Only .dmg and .app (inside tar archive) are supported." + ) + + localFilePath = self.extractAppFromTar(workPath, archiveFilePath) + return localFilePath + + def uploadApp(self, workPath: Path, localProcessedFilePath: Path, originalRemotePath: Path, localOrignalPath: Path): + self.task: Task + fileExtension = util.getFileSuffix(originalRemotePath) + if localProcessedFilePath.suffix == ".app": + # repack archive + signedArchivePath = workPath / f"archive-{self.resultNameSuffix}{fileExtension}" + with tarfile.open(name=signedArchivePath, mode="w") as tar: + # Add our signed/notarized *.app to an archive. We use the name of the orignal app + # (eg. kdenlive.app) instead of the local work name "processed.app". + # For other file types we use a suffix like "kdenlive-signed.app", + # for *.app files we do the same, but to the archive and not the archives content + tar.add(localProcessedFilePath, arcname=localOrignalPath.name, recursive=True) + localProcessedFilePath = signedArchivePath + try: + remoteSignedFileName = ( + f"{util.removeFileSuffix(originalRemotePath.name)}-{self.resultNameSuffix}{fileExtension}" + ) + self.sftp.upload(localProcessedFilePath, self.task.path() / remoteSignedFileName) + return self.responseClass(signedFileName=remoteSignedFileName) + except Error as e: + log.error("Error: %s", e) + except SFTPError as e: + log.error("Error: %s", e) diff --git a/third_party/ci-notary-service/sftpnotary/authentication.py b/third_party/ci-notary-service/sftpnotary/authentication.py new file mode 100644 index 0000000..a1eb890 --- /dev/null +++ b/third_party/ci-notary-service/sftpnotary/authentication.py @@ -0,0 +1,96 @@ +# SPDX-License-Identifier: BSD-2-Clause +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + +import logging +from typing import Any, Optional + +import requests + +from sftpnotary import projects + +log = logging.getLogger(__name__) + +authentication = None + + +def setAuthentication(auth): + global authentication + authentication = auth + + +class AuthenticationFailed(Exception): + pass + + +class GitLabJobTokenAuthentication: + def __init__(self, apiV4Url: str, userAgent: Optional[str] = None): + self.apiV4Url = apiV4Url + self.userAgent = userAgent + + def authenticate(self, *, request, **_): + jobData = self.getJob(request.token) + if jobData is None: + raise AuthenticationFailed("Failed to retrieve job. The job is no longer running or the token is invalid.") + + projectId = jobData.get("pipeline", {}).get("project_id") + if projectId is None: + raise AuthenticationFailed("Job data does not include the project ID (pipeline.project_id).") + pipelineSource = jobData.get("pipeline", {}).get("source") + if pipelineSource is None: + raise AuthenticationFailed("Job data does not include the pipeline source (pipeline.source).") + # instead of trying to figure out the real project path and branch of an MR (possibly originating from a clone) + # we reject all merge request jobs + if pipelineSource == "merge_request_event": + raise AuthenticationFailed("Merge requests are not cleared for this request.") + projectData = self.getProject(projectId) + if projectData is None: + raise AuthenticationFailed("Failed to retrieve project for job.") + + projectPath = projectData.get("path_with_namespace") + branch = jobData.get("ref") + + if branch != request.branch: + raise AuthenticationFailed( + f"Branch in request ({request.branch}) does not match the job's branch ({branch})." + ) + if projectPath != request.projectPath: + raise AuthenticationFailed( + f"Project path in request ({request.projectPath}) does not match the job's project path " + f"({projectPath})." + ) + if not projects.settings.exists(projectPath, branch): + raise AuthenticationFailed(f"Branch '{branch}' of project '{projectPath}' is not cleared for this request.") + + def apiRequest(self, path: str, **kwargs: Any) -> Any: + apiEndpoint = f"{self.apiV4Url}{path}" + headers = kwargs.setdefault("headers", {}) + if self.userAgent: + headers.update({"User-Agent": self.userAgent}) + timeout = kwargs.setdefault("timeout", 5) # seconds + del kwargs["timeout"] + # pass timeout explicitly to satisfy bandit + r = requests.get(apiEndpoint, timeout=timeout, **kwargs) + r.raise_for_status() + return r.json() + + def getJob(self, jobToken: str): + # Fails if job token is invalid or job is no longer running. + headers = { + "Authorization": "Bearer " + jobToken, + } + try: + return self.apiRequest("/job", headers=headers) + except requests.RequestException as e: + log.error("Error: Failed to retrieve job.") + log.debug("Error details:", exc_info=e) + + def getProject(self, projectId: Optional[int]): + if projectId is None: + raise TypeError("Project ID must be a number.") + + try: + return self.apiRequest(f"/projects/{projectId}") + except requests.RequestException as e: + log.error("Error: Failed to retrieve project for job.") + log.debug("Error details:", exc_info=e) diff --git a/third_party/ci-notary-service/sftpnotary/buildpublisher.py b/third_party/ci-notary-service/sftpnotary/buildpublisher.py new file mode 100644 index 0000000..2834a41 --- /dev/null +++ b/third_party/ci-notary-service/sftpnotary/buildpublisher.py @@ -0,0 +1,163 @@ +# SPDX-License-Identifier: BSD-2-Clause +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileCopyrightText: 2023 Ben Cooksley +# SPDX-FileContributor: Ingo Klöcker + +import dataclasses +import logging +import os +import tarfile +from pathlib import Path +from tempfile import TemporaryDirectory +from typing import Optional + +from sftpnotary import projects, util +from sftpnotary.core import Job, Request, Response, TaskProcessor, Worker +from sftpnotary.exceptions import Error, InvalidParameter +from sftpnotary.sftp import SFTPClient, SFTPError + +log = logging.getLogger(__name__) + + +@dataclasses.dataclass +class PublishBuildRequest(Request): + buildArchiveFileName: Optional[str] = None + platform: Optional[str] = None + + def validate(self): + # Ensure we don't have an evil build artifact name... + util.validateFileName(self.buildArchiveFileName, strict=True) + + # Ensure the platform name is valid + validPlatforms = [ + "windows", + "linux", + "macos-x86_64", + "macos-arm64", + "macos-universal", + "android-x86_64", + "android-armeabi-v7a", + "android-arm64-v8a", + "snap-image", + # Krita specific + "windows-qt5", + "linux-qt5", + "macos-universal-qt5", + # Temporary Kdenlive specific + "msvc-experimental", + ] + + if self.platform not in validPlatforms: + raise InvalidParameter(name="buildPlatform", value=self.platform) + + +PublishBuildResponse = Response + + +class PublishBuildJob(Job): + def __init__( + self, + sftp: SFTPClient, + buildArchiveFilePath: Path, + token: str, + projectPath: str, + branch: str, + platform: str, + ): + super().__init__(sftp) + + self.buildArchiveFilePath = buildArchiveFilePath + self.request = PublishBuildRequest( + buildArchiveFileName=None, + token=token, + projectPath=projectPath, + branch=branch, + platform=platform, + ) + self.resultPath = self.buildArchiveFilePath.parent + + def start(self): + buildArchiveFileName = self.buildArchiveFilePath.name + self.sftp.upload(self.buildArchiveFilePath, self.task.path() / buildArchiveFileName) + self.request.buildArchiveFileName = buildArchiveFileName + self.task.putRequest(self.request) + self.taskQueue.commitTask(self.task) + + def waitForCompletion(self): + self.taskQueue.waitForCompletion(self.task) + log.debug(f"Fetching response of task '{self.task.id}' ...") + response = None + try: + response = self.task.fetchResponse(PublishBuildResponse) + except SFTPError as e: + log.error("Error: %s", e) + if response is None: + log.error("Error: Got no response. Task failed.") + else: + self.success = True + self.downloadLogFiles(self.resultPath) + self.taskQueue.removeTask(self.task) + + +class PublishBuildProcessor(TaskProcessor): + requestClass = PublishBuildRequest + + def getProjectSetting(self, name, required=True): + value = projects.settings.get(self.request.projectPath, self.request.branch, name) + if required and not value: + raise Error( + f"Project setting '{name}' not set for branch {self.request.branch} " + f"of project {self.request.projectPath}" + ) + return value + + def doProcess(self): + # Get the details for where we will publish the build artifacts to + rsyncDestination = self.getProjectSetting("rsyncDestination") + + # Retrieve the project, branch and platform + projectPath = self.request.projectPath + branch = self.request.branch + platform = self.request.platform + + # Convert any slashes in the branch name to dashes to keep folder names tidy + branch = branch.replace("/", "-") + + with TemporaryDirectory() as workPathName: + workPath = Path(workPathName) + + localBuildArchiveFilePath = workPath / self.request.buildArchiveFileName + self.sftp.download(self.task.path() / self.request.buildArchiveFileName, localBuildArchiveFilePath) + + # Setup a path for us to unpack the build artifacts archive into... + unpackedBuildArtifactsPath = workPath / "unpacked" + os.makedirs(unpackedBuildArtifactsPath) + + # Unpack the build archive.... + archive = tarfile.open(name=localBuildArchiveFilePath, mode="r") + # Set "nosec B202" because of https://github.com/PyCQA/bandit/issues/1038#issuecomment-1635863856 + archive.extractall(filter="tar", path=unpackedBuildArtifactsPath) # nosec B202 + archive.close() + + # Determine the final rsync destination + # We allow for the project path, branch and platform to be inserted via Python named string format variables + # This avoids having to repeat ourselves in the configuration file + finalRsyncDestination = rsyncDestination.format(projectPath=projectPath, branch=branch, platform=platform) + + # Build up the rsync command to run then run it + # The entire contents of + rsyncCommand = [ + "rsync", + "--archive", + "--checksum", + "--delete", + "--mkpath", + "--verbose", + str(unpackedBuildArtifactsPath) + "/", + finalRsyncDestination.rstrip("/") + "/", + ] + util.runCommand(rsyncCommand, cwd=workPathName) + + +class PublishBuildWorker(Worker): + processorClass = PublishBuildProcessor diff --git a/third_party/ci-notary-service/sftpnotary/config.py b/third_party/ci-notary-service/sftpnotary/config.py new file mode 100644 index 0000000..84d0478 --- /dev/null +++ b/third_party/ci-notary-service/sftpnotary/config.py @@ -0,0 +1,73 @@ +# -*- coding: utf-8 -*- +# SPDX-License-Identifier: BSD-2-Clause +# SPDX-FileCopyrightText: 2014 Hannah von Reth + +# central instance for managing settings regarding craft + +import configparser +import os +import sys +from pathlib import Path +from typing import List, Optional, Union + + +def loadConfig(iniPath): + global settings + settings = Config(iniPath) + + +class Config: + def __init__(self, iniPath=None): + self._config = configparser.ConfigParser(interpolation=None) + if iniPath: + self.iniPath = Path(iniPath) + self._readSettings() + + def _readSettings(self): + if not os.path.exists(self.iniPath): + print("Could not find config: %s" % self.iniPath, file=sys.stderr) + return + + self._config.read(self.iniPath, encoding="utf-8") + + def __contains__(self, key): + return self._config and self._config.has_option(*key) + + def get(self, group, key, default=None): + return self._config.get(group, key, fallback=default) + + @staticmethod + def _parseList(s: str) -> List[str]: + return [v.strip() for v in s.split(";") if v] + + def getList(self, group, key, default=None): + return Config._parseList(self.get(group, key, default)) + + def getPath(self, group: str, key: str, default: Optional[Union[Path, str]] = None) -> Optional[Path]: + v = self.get(group, key, default) + if isinstance(v, str): + v = Path(v).expanduser() + return v + + def getSection(self, group): + if self._config.has_section(group): + return self._config.items(group) + else: + return [] + + def getboolean(self, group, key, default=False): + return self._config.getboolean(group, key, fallback=default) + + def set(self, group, key, value): + if value is None: + return + if not self._config.has_section(group): + self._config.add_section(group) + self._config[group][key] = str(value) + + def setDefault(self, group, key, value): + if (group, key) not in self: + self.set(group, key, value) + + +settings = Config() diff --git a/third_party/ci-notary-service/sftpnotary/core.py b/third_party/ci-notary-service/sftpnotary/core.py new file mode 100644 index 0000000..e57b22c --- /dev/null +++ b/third_party/ci-notary-service/sftpnotary/core.py @@ -0,0 +1,415 @@ +# SPDX-License-Identifier: BSD-2-Clause +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + +import dataclasses +import json +import logging +import os +import stat +import time +from pathlib import Path, PurePath, PurePosixPath +from tempfile import TemporaryDirectory +from typing import List, Optional + +import sftpnotary.log +from sftpnotary import authentication, util +from sftpnotary.exceptions import Error +from sftpnotary.sftp import ConnectionLostError, SFTPClient + +log = logging.getLogger(__name__) + + +@dataclasses.dataclass +class MetaData: + def asDict(self) -> dict: + return dataclasses.asdict(self) + + def asJson(self) -> str: + # disable escaping of non-ASCII characters + return json.dumps(dataclasses.asdict(self), ensure_ascii=False) + + @classmethod + def fromDict(cls, d: dict): + fields = dataclasses.fields(cls) + initKwargs = {field.name: d[field.name] for field in fields if field.name in d} + unknownFields = sorted(list(set(d.keys()) - set(initKwargs.keys()))) + if unknownFields: + log.debug(f"Ignored the following unknown entries in the dict: {', '.join(unknownFields)}") + return cls(**initKwargs) + + @classmethod + def fromJson(cls, s: str): + return cls.fromDict(json.loads(s)) + + +@dataclasses.dataclass +class Request(MetaData): + token: Optional[str] = None + projectPath: Optional[str] = None + branch: Optional[str] = None + + def validate(self): + pass + + +@dataclasses.dataclass +class SingleFileRequest(Request): + fileName: Optional[str] = None + + def validate(self): + util.validateFileName(self.fileName) + + +@dataclasses.dataclass +class Response(MetaData): + pass + + +@dataclasses.dataclass +class SignFileResponse(Response): + signedFileName: Optional[str] = None + + +class Task: + def __init__(self, id: str, basePath: PurePath): + self.id = id + self.basePath = basePath + self.queue = None + + def path(self) -> PurePath: + return self.basePath / self.id + + def requestPath(self) -> PurePath: + return self.path() / "request.json" + + def responsePath(self) -> PurePath: + return self.path() / "response.json" + + def putRequest(self, request): + self.queue.uploadJson(request.asJson(), self.requestPath()) + + def fetchRequest(self, requestClass): + data = self.queue.fetchJson(self.requestPath()) + + log.debug(f"Request: {data}") + return requestClass.fromJson(data) + + def putResponse(self, response): + self.queue.uploadJson(response.asJson(), self.responsePath()) + + def fetchResponse(self, responseClass): + data = self.queue.fetchJson(self.responsePath()) + + log.debug(f"Response: {data}") + return responseClass.fromJson(data) + + +def _ensureFolderExists(sftp: SFTPClient, path: PurePath): + try: + sftp.stat(str(path)) + return + except FileNotFoundError: + log.debug("Folder '%s' does not exist. Creating ...", path) + try: + sftp.mkdir(str(path)) + except OSError as e: + raise Error(f"Failed to create folder '{path}' ({e!r})") + + +class TaskQueue: + def __init__(self, sftp: SFTPClient): + self.sftp = sftp + self.newPath = PurePosixPath("tmp") + self.pendingPath = PurePosixPath("queue") + self.donePath = PurePosixPath("done") + self.trashPath = PurePosixPath("trash") + _ensureFolderExists(self.sftp, self.newPath) + _ensureFolderExists(self.sftp, self.pendingPath) + _ensureFolderExists(self.sftp, self.donePath) + _ensureFolderExists(self.sftp, self.trashPath) + + def createTask(self): + timestamp = time.strftime("%Y%m%dT%H%M%S", time.gmtime()) + if "CI_JOB_ID" in os.environ: + clientId = f"{os.environ['CI_PROJECT_PATH_SLUG']}_{os.environ['CI_JOB_ID']}" + else: + clientId = os.uname().nodename + task = Task(id=f"{timestamp}-{clientId}", basePath=self.newPath) + task.queue = self + self.sftp.mkdir(str(task.path())) + return task + + def commitTask(self, task: Task): + log.info(f"Committing task '{task.id}' ...") + if task.basePath != self.newPath: + raise Error(f"Task '{task.id}' not in folder for new tasks (task.path: {task.path()})") + + try: + targetPath = self.pendingPath / task.id + self.sftp.posix_rename(str(task.path()), str(targetPath)) + task.basePath = self.pendingPath + except OSError as e: + raise Error(f"Failed to commit task '{task.id}' ({e!r})") + return task + + def _getFirstTaskInQueue(self): + entries = sorted(self.sftp.listdir(str(self.pendingPath))) + if len(entries) > 0: + task = Task(entries[0], self.pendingPath) + task.queue = self + return task + + def getNextTask(self): + while True: + log.debug("Checking queue for next task ...") + task = self._getFirstTaskInQueue() + if task is not None: + log.debug(f"Found task {task.id}") + yield task + time.sleep(5) + + def takeTask(self, task: Task, targetPath: PurePath): + log.info(f"Taking task {task.id} ...") + try: + self.sftp.posix_rename(str(task.path()), str(targetPath / task.id)) + task.basePath = targetPath + return task + except FileNotFoundError: + # likely no error, but another worker took the task + log.info(f"Failed to take task '{task.id}'.") + return + + def uploadJson(self, data: str, remotePath: PurePath): + self.sftp.uploadBytes(data.encode(), remotePath) + + def fetchJson(self, remotePath: PurePath) -> str: + return self.sftp.downloadBytes(remotePath).decode() + + def waitForCompletion(self, task: Task): + while True: + log.debug(f"Checking if task '{task.id}' is done ...") + try: + attrs = self.sftp.stat(str(self.donePath / task.id)) # raises FileNotFoundError + log.debug(f"Got attributes: {attrs}") + task.basePath = self.donePath + return task + except FileNotFoundError: + pass + except ConnectionLostError: + log.warning("Lost connection to SFTP server. Reconnecting ...") + self.sftp.reconnect() + + time.sleep(5) + + def setDone(self, task: Task): + log.info(f"Setting task '{task.id}' to done ...") + + try: + self.sftp.posix_rename(str(task.path()), str(self.donePath / task.id)) + task.basePath = self.donePath + return task + except OSError as e: + raise Error(f"Failed to set task '{task.id}' to done ({e!r})") + + def removeTask(self, task: Task): + log.info(f"Moving task '{task.id}' to trash ...") + try: + self.sftp.posix_rename(str(task.path()), str(self.trashPath / task.id)) + task.basePath = self.trashPath + return task + except OSError as e: + raise Error(f"Failed to move task '{task.id}' to trash ({e!r})") + + def cleanUp(self, taskFolder: PurePath, maxAgeInDays: int = 0): + log.debug(f"Cleaning up task folder '{taskFolder}' ...") + now = time.time() + cutOffTime = now - maxAgeInDays * 24 * 60 * 60 + entriesAttributes = self.sftp.listdir_attr(taskFolder) + for entryAttributes in entriesAttributes: + entryName = entryAttributes.filename + if not stat.S_ISDIR(entryAttributes.st_mode): + log.debug(f"Removing unexpected file '{entryName}'") + self.sftp.remove(taskFolder / entryName) + elif entryAttributes.st_mtime < cutOffTime: + log.debug(f"Removing task '{entryName}' ...") + self.sftp.recursiveRemoveDirectory(taskFolder / entryName) + + def cleanUpTaskFolders(self, maxAgeInDays: int = 1): + # remove old tasks from all of the standard task folders + self.cleanUp(self.newPath, maxAgeInDays) + self.cleanUp(self.pendingPath, maxAgeInDays) + self.cleanUp(self.donePath, maxAgeInDays) + self.cleanUp(self.trashPath, maxAgeInDays) + + +def ProgressLogger(message: str): + def printProgress(current: int, total: int): + log.debug(message, current, total) + + return printProgress + + +class Job: + def __init__(self, sftp: SFTPClient): + self.sftp = sftp + self._taskQueue = None + self._task = None + self.success: bool = False + self.request: Optional[Request] = None # created by the actual job + self.logFiles: List[Path] = [] + + @property + def taskQueue(self): + if self._taskQueue is None: + self._taskQueue = TaskQueue(self.sftp) + return self._taskQueue + + @property + def task(self): + if self._task is None: + self._task = self.taskQueue.createTask() + return self._task + + def listLogFiles(self) -> List[PurePath]: + logFiles = [] + for attr in self.sftp.listdir_iter(str(self.task.path())): + if attr.filename.endswith(".log"): + logFiles.append(self.task.path() / attr.filename) + return logFiles + + def downloadLogFiles(self, destinationFolder: Path) -> None: + self.logFiles.clear() + for logFile in self.listLogFiles(): + localPath = destinationFolder / logFile.name + self.sftp.download(logFile, localPath) + self.logFiles.append(localPath) + + +class SignSingleFileJob(Job): + def __init__(self, sftp: SFTPClient, filePath: Path): + super().__init__(sftp) + + self.localFilePath = Path(filePath) + + def uploadUnsignedFile(self): + localPath = self.localFilePath + remotePath = self.task.path() / self.request.fileName + self.sftp.upload(localPath, remotePath) + + +class Worker: + def __init__(self, workerId: str, sftp: SFTPClient): + self.workerId = workerId + self.sftp = sftp + self._processingPath = None + self._taskQueue = None + + @property + def processingPath(self): + if self._processingPath is None: + path = PurePosixPath(f"processing-{self.workerId}") + _ensureFolderExists(self.sftp, path) + self._processingPath = path + return self._processingPath + + @property + def taskQueue(self): + if self._taskQueue is None: + self._taskQueue = TaskQueue(self.sftp) + return self._taskQueue + + def start(self): + # remove leftovers in the worker's processing folder + self.taskQueue.cleanUp(self.processingPath) + # remove old tasks from the different task folders + self.taskQueue.cleanUpTaskFolders() + + while True: + try: + self._runTaskLoop() + except ConnectionLostError: + log.warning("Lost connection to SFTP server. Reconnecting ...") + self.sftp.reconnect() + + def _runTaskLoop(self): + for task in self.taskQueue.getNextTask(): + task = self.taskQueue.takeTask(task, self.processingPath) + if task is not None: + processor = self.processorClass(self.sftp) + processor.process(task) + self.taskQueue.setDone(task) + # remove old tasks from the different task folders + self.taskQueue.cleanUpTaskFolders() + + +class TaskProcessor: + tries = 1 + + def __init__(self, sftp: SFTPClient): + self.sftp = sftp + self.task: Optional[Task] = None + self.request: Optional[Request] = None + + def process(self, task: Task): + self.task = task + with TemporaryDirectory() as tmpdirname: + debugFilePath = Path(tmpdirname) / "task-debug.log" + logFilePath = Path(tmpdirname) / "task.log" + with sftpnotary.log.captureTaskDebugLog(debugFilePath), sftpnotary.log.captureTaskLog(logFilePath): + self.processInner() + self.sftp.upload(debugFilePath, self.task.path() / debugFilePath.name) + self.sftp.upload(logFilePath, self.task.path() / logFilePath.name) + + def processInner(self): + log.debug(f"Fetching request of task '{self.task.id}' ...") + try: + self.request = self.task.fetchRequest(self.requestClass) + except Exception as e: + log.error(f"Error: Fetching request of task '{self.task.id}' failed.") + log.debug("Error details:", exc_info=e) + return + + try: + self.request.validate() + except Exception as e: + log.error(f"Error: Request of task '{self.task.id}' is invalid.") + log.debug("Error details:", exc_info=e) + return + + if authentication.authentication is not None: + log.debug("Authenticating request ...") + try: + authentication.authentication.authenticate(request=self.request) + except Exception as e: + log.error(f"Error: Authenticating request of task '{self.task.id}' failed.") + log.debug("Error details:", exc_info=e) + return + + log.info(f"Processing task '{self.task.id}' ...") + + done = False + tries = self.tries + while not done and tries > 0: + try: + response = self.doProcess() + if response is None: + response = Response() + self.task.putResponse(response) + done = True + except Exception as e: + tries -= 1 + if tries > 0: + log.error("Error: Processing task '%s' failed with %r. Retrying ...", self.task.id, e) + else: + log.error("Error: Processing task '%s' failed with %r. Giving up.", self.task.id, e) + log.debug("Error details:", exc_info=e) + if not done: + log.debug("Marking task '%s' as failed.", self.task.id) + # mark as failed + pass + + log.info(f"Finished processing task '{self.task.id}' ...") + + def doProcess(self): + raise NotImplementedError("You need to use a suitable subclass!") diff --git a/third_party/ci-notary-service/sftpnotary/entitlements_whitelist.py b/third_party/ci-notary-service/sftpnotary/entitlements_whitelist.py new file mode 100644 index 0000000..fbbe5c5 --- /dev/null +++ b/third_party/ci-notary-service/sftpnotary/entitlements_whitelist.py @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: BSD-2-Clause +# SPDX-FileCopyrightText: 2026 KDE e.V. + +"""Whitelist of allowed macOS entitlements for KDE projects.""" + +import plistlib + +# Allowed entitlement keys - any entitlement not in this list is rejected +ALLOWED_ENTITLEMENTS = { + # Allow loading libraries with different code signatures + # Required e.g. for Python/scripting apps that load user-installed packages + "com.apple.security.cs.disable-library-validation", + # Allow access to the microphone + # Required e.g. for Kdenlive + "com.apple.security.device.audio-input", +} + + +def validate_entitlements_file(file_path): + """ + Parse and validate an entitlements plist file. + + Args: + file_path: Path to the .entitlements file + + Raises: + ValueError: If any entitlement is not in the whitelist + """ + with open(file_path, "rb") as f: + entitlements = plistlib.load(f) + + for key in entitlements.keys(): + if key not in ALLOWED_ENTITLEMENTS: + raise ValueError(f"Entitlement not allowed: {key}") diff --git a/third_party/ci-notary-service/sftpnotary/exceptions.py b/third_party/ci-notary-service/sftpnotary/exceptions.py new file mode 100644 index 0000000..950944e --- /dev/null +++ b/third_party/ci-notary-service/sftpnotary/exceptions.py @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: BSD-2-Clause +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + + +class Error(Exception): + pass + + +class InvalidFileName(Error): + def __init__(self, fileName=None): + super().__init__(fileName) + self.fileName = fileName + + def __str__(self): + if self.fileName is None: + return "No file name" + else: + return f"Invalid file name: {self.fileName!r}" + + +class InvalidParameter(Error): + def __init__(self, name, value=None): + super().__init__(name, value) + self.name = name + self.value = value + + def __str__(self): + if self.value is None: + return f"Parameter not specified: {self.name!r}" + else: + return f"Invalid parameter '{self.name!r}' value: {self.value!r}" diff --git a/third_party/ci-notary-service/sftpnotary/fdroidpublisher.py b/third_party/ci-notary-service/sftpnotary/fdroidpublisher.py new file mode 100644 index 0000000..eb2b465 --- /dev/null +++ b/third_party/ci-notary-service/sftpnotary/fdroidpublisher.py @@ -0,0 +1,262 @@ +# SPDX-License-Identifier: BSD-2-Clause +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + +import dataclasses +import logging +import os +import time +import zipfile +from pathlib import Path +from tempfile import TemporaryDirectory +from typing import List, Optional + +from sftpnotary import apkutils, config, projects, util +from sftpnotary.core import Job, Request, Response, TaskProcessor, Worker +from sftpnotary.exceptions import Error, InvalidFileName +from sftpnotary.sftp import SFTPClient, SFTPError + +log = logging.getLogger(__name__) + + +@dataclasses.dataclass +class PublishOnFDroidRequest(Request): + apkFileNames: Optional[List[str]] = None + fastlaneFileName: Optional[str] = None + + def validate(self): + if self.apkFileNames is None: + raise InvalidFileName() + for apkFileName in self.apkFileNames: + util.validateFileName(apkFileName, strict=True) + util.validateFileName(self.fastlaneFileName, strict=True) + + +PublishOnFDroidResponse = Response + + +class PublishOnFDroidJob(Job): + def __init__( + self, + sftp: SFTPClient, + apkFilePaths: List[Path], + fastlaneFilePath: Path, + token: Optional[str] = None, + projectPath: Optional[str] = None, + branch: Optional[str] = None, + ): + super().__init__(sftp) + + self.apkFilePaths = apkFilePaths + self.fastlaneFilePath = fastlaneFilePath + self.request = PublishOnFDroidRequest( + apkFileNames=[], + fastlaneFileName=None, + token=token, + projectPath=projectPath, + branch=branch, + ) + self.resultPath = self.apkFilePaths[0].parent + + def start(self): + for apkFilePath in self.apkFilePaths: + apkFileName = apkFilePath.name + self.sftp.upload(apkFilePath, self.task.path() / apkFileName) + self.request.apkFileNames.append(apkFileName) + fastlaneFileName = self.fastlaneFilePath.name + self.sftp.upload(self.fastlaneFilePath, self.task.path() / fastlaneFileName) + self.request.fastlaneFileName = fastlaneFileName + self.task.putRequest(self.request) + self.taskQueue.commitTask(self.task) + + def waitForCompletion(self): + self.taskQueue.waitForCompletion(self.task) + log.debug(f"Fetching response of task '{self.task.id}' ...") + response = None + try: + response = self.task.fetchResponse(PublishOnFDroidResponse) + except SFTPError as e: + log.error("Error: %s", e) + if response is None: + log.error("Error: Got no response. Task failed.") + else: + self.success = True + self.downloadLogFiles(self.resultPath) + self.taskQueue.removeTask(self.task) + + +def removeOldFiles(path, maxAgeInDays): + oldFilesPurgeThreshold = time.time() - (3600 * 24 * maxAgeInDays) + log.debug(f"Removing files that are older than {maxAgeInDays} days.") + for root, dirs, files in os.walk(path, topdown=False, onerror=None, followlinks=False): + # first iterate over all files + for name in files: + filePath = Path(root) / name + # ignore anything that's not a regular file + if filePath.is_symlink() or not filePath.is_file(): + log.debug(f"Ignoring {filePath} which is not a regular file.") + continue + + # purge ancient files + if os.path.getmtime(filePath) < oldFilesPurgeThreshold: + log.info(f"Removing outdated file: {filePath}") + filePath.unlink() + + # then delete empty subfolders + for name in dirs: + filePath = Path(root) / name + try: + # try to remove the folder + filePath.rmdir() + log.info(f"Removed empty folder: {filePath}") + except OSError: + # ignore failed removal; maybe the folder wasn't empty + pass + + +class PublishOnFDroidProcessor(TaskProcessor): + requestClass = PublishOnFDroidRequest + + def __init__(self, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + + self.sdkToolsPath = config.settings.getPath("ApkSigning", "SDKToolsPath") + if self.sdkToolsPath is None: + raise Error("SDKToolsPath not set in config.") + self.sdkPath = self.sdkToolsPath.parent.parent + + def getProjectSetting(self, name, required=True): + value = projects.settings.get(self.request.projectPath, self.request.branch, name) + if required and not value: + raise Error( + f"Project setting '{name}' not set for branch {self.request.branch} " + f"of project {self.request.projectPath}" + ) + return value + + def doProcess(self): + repoName = self.getProjectSetting("repository") + + with TemporaryDirectory() as workPathName: + workPath = Path(workPathName) + + localApkFilePaths = [] + for apkFileName in self.request.apkFileNames: + localApkFilePath = workPath / apkFileName + self.sftp.download(self.task.path() / apkFileName, localApkFilePath) + localApkFilePaths.append(localApkFilePath) + localFastlaneFilePath = workPath / self.request.fastlaneFileName + self.sftp.download(self.task.path() / self.request.fastlaneFileName, localFastlaneFilePath) + + self.verifyApplicationId(localApkFilePaths) + self.publishApks(localApkFilePaths, localFastlaneFilePath, repoName) + + def verifyApplicationId(self, apkFilePaths): + allowedApplicationId = projects.settings.get(self.request.projectPath, self.request.branch, "applicationid") + for apkFilePath in apkFilePaths: + applicationId = apkutils.getApplicationId(apkFilePath) + if applicationId != allowedApplicationId: + raise Error( + f"The application ID of the APK ({applicationId}) did not match the allowed application ID " + f"({allowedApplicationId})." + ) + + def publishApks(self, apkFilePaths, fastlaneFilePath, repoName): + workingDirectory = fastlaneFilePath.parent + localRepoPath = config.settings.getPath("FDroidPublishing", "LocalRepoPrefix") / repoName / "fdroid" + metadataPath = localRepoPath / "metadata" + fastlaneDirPath = localRepoPath.parent / "fastlane" + + # Make sure the repository has been set up. The local repository should be the folder which contains the repo/ + # folder. + if not (localRepoPath / "repo").is_dir(): + raise Error( + "The specified F-Droid repository does not exist. Please run 'fdroid init' to setup the repository." + ) + + # Move the APKs into the local repository + # Run "mv" instead of a using a Python function because the limitations of os.rename, os.replace, shutil.move, + # etc., gives me headaches + command = ["mv", "-f"] + apkFilePaths + [localRepoPath / "repo"] + util.runCommand(command, cwd=workingDirectory) + + # Create fastlane directory (if it doesn't exist yet) and move fastlane zip files into it + os.makedirs(fastlaneDirPath, exist_ok=True) + command = ["mv", "-f", fastlaneFilePath, fastlaneDirPath / fastlaneFilePath.name] + util.runCommand(command, cwd=workingDirectory) + + # Remove files that haven't been updated in a long time, e.g. because of + # renamed or removed builds + maxAgeInDays = int(config.settings.get(f"FDroidRepository {repoName}", "Expiry", "365")) + removeOldFiles(localRepoPath / "repo", maxAgeInDays=maxAgeInDays) + + # Let F-Droid prepare the metadata skeletons for us + # We'll then fill in these templates with the information from the APK files + self.runFdroidCommand(["update", "-c"], repoPath=localRepoPath) + + # Remove old APKs that have been moved to the archive repo + localArchivePath = localRepoPath / "archive" + oldApkPaths = localArchivePath.glob("*.apk") + for oldApkPath in oldApkPaths: + log.info(f"Removing old APK: {oldApkPath}") + oldApkPath.unlink() + + # Extract the meta data of all apps from the fastlane files + self.prepareMetaDataForAllApks(localRepoPath / "repo", fastlaneDirPath, metadataPath) + + # Ask F-Droid to do a full update pass + self.runFdroidCommand(["update"], repoPath=localRepoPath) + + # Publish the repository on a webserver for clients to use + self.runFdroidCommand(["deploy", "-v"], repoPath=localRepoPath) + + def runFdroidCommand(self, command, *, repoPath): + command = ["fdroid"] + command + # prepend the Android SDK Tools path to PATH to ensure that `fdroid` finds the correct `apksigner` + environment = { + **os.environ, + "ANDROID_HOME": str(self.sdkPath), + "PATH": str(self.sdkToolsPath) + os.pathsep + os.environ["PATH"], + } + util.runCommand(command, cwd=repoPath, env=environment) + + # def prepareMetaDataForAllApks(self, repoFolder: Path, fastlaneDirPath: Path, metadataPath: Path): + def prepareMetaDataForAllApks(self, repoFolder, fastlaneDirPath, metadataPath): + processedApplications = set() + + # Extract the metadata for all APKs in the repository. + with os.scandir(repoFolder) as dirEntryIterator: + for entry in dirEntryIterator: + # ignore anything that's not a regular file named *.apk + if not entry.is_file(follow_symlinks=False) or not entry.name.endswith(".apk"): + continue + + # First, determine the ID of the application we have here + # This is needed in order to locate the metadata files within the APK that have the information we need + applicationId = apkutils.getApplicationId(Path(entry.path)) + + # Skip APKs of already processed applications + if applicationId in processedApplications: + log.debug(f"Meta data for {applicationId} already extracted") + continue + + # Now we know we have a file that we are interested in; process it + self.processApkFile(applicationId, fastlaneDirPath, metadataPath) + processedApplications.add(applicationId) + + def processApkFile(self, applicationId: str, fastlaneDirPath: Path, metadataPath: Path): + log.info(f"Preparing meta data for {applicationId}") + + # Check if we have metadata provided by the build process, and if so apply that + zipName = fastlaneDirPath / f"fastlane-{applicationId}.zip" + if os.path.exists(zipName): + log.info(f"Using meta data from build process: {zipName.name}") + with zipfile.ZipFile(zipName, "r") as zipFile: + filePaths = apkutils.filterFastlaneFileNames(zipFile.namelist(), applicationId) + zipFile.extractall(path=metadataPath, members=filePaths) + else: + log.error(f"Missing meta data package {zipName}") + + +class PublishOnFDroidWorker(Worker): + processorClass = PublishOnFDroidProcessor diff --git a/third_party/ci-notary-service/sftpnotary/flatpaksigner.py b/third_party/ci-notary-service/sftpnotary/flatpaksigner.py new file mode 100644 index 0000000..7730961 --- /dev/null +++ b/third_party/ci-notary-service/sftpnotary/flatpaksigner.py @@ -0,0 +1,419 @@ +# SPDX-License-Identifier: BSD-2-Clause +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + +import base64 +import configparser +import dataclasses +import logging +from pathlib import Path +from tempfile import TemporaryDirectory +from typing import Optional + +from sftpnotary import config, projects, util +from sftpnotary.core import Job, Request, Response, TaskProcessor, Worker +from sftpnotary.exceptions import Error +from sftpnotary.sftp import SFTPClient, SFTPError + +log = logging.getLogger(__name__) + + +@dataclasses.dataclass +class SignFlatpakRequest(Request): + fileName: Optional[str] = None + localeBundleFileName: Optional[str] = None + debugBundleFileName: Optional[str] = None + + def validate(self): + util.validateFileName(self.fileName, strict=True) + if self.localeBundleFileName: + util.validateFileName(self.localeBundleFileName, strict=True) + if self.debugBundleFileName: + util.validateFileName(self.debugBundleFileName, strict=True) + + +SignFlatpakResponse = Response + + +def fileNameOrNone(path: Optional[Path]): + if path is not None: + return path.name + return None + + +class SignFlatpakJob(Job): + def __init__( + self, + sftp: SFTPClient, + flatpakFilePath: Path, + localeBundlePath: Optional[Path] = None, + debugBundlePath: Optional[Path] = None, + token: Optional[str] = None, + projectPath: Optional[str] = None, + branch: Optional[str] = None, + ): + super().__init__(sftp) + + self.flatpakBundlePath = flatpakFilePath + self.localeBundlePath = localeBundlePath + self.debugBundlePath = debugBundlePath + + self.request = SignFlatpakRequest( + fileName=flatpakFilePath.name, + localeBundleFileName=fileNameOrNone(localeBundlePath), + debugBundleFileName=fileNameOrNone(debugBundlePath), + token=token, + projectPath=projectPath, + branch=branch, + ) + + def start(self): + self.sftp.upload(self.flatpakBundlePath, self.task.path() / self.request.fileName) + if self.localeBundlePath: + self.sftp.upload(self.localeBundlePath, self.task.path() / self.request.localeBundleFileName) + if self.debugBundlePath: + self.sftp.upload(self.debugBundlePath, self.task.path() / self.request.debugBundleFileName) + self.task.putRequest(self.request) + self.taskQueue.commitTask(self.task) + + def waitForCompletion(self): + self.taskQueue.waitForCompletion(self.task) + log.debug(f"Fetching response of task '{self.task.id}' ...") + response = None + try: + response = self.task.fetchResponse(SignFlatpakResponse) + except SFTPError as e: + log.error("Error: %s", e) + if response is None: + log.error("Error: Got no response. Task failed.") + else: + self.success = True + self.downloadLogFiles(self.flatpakBundlePath.parent) + self.taskQueue.removeTask(self.task) + + +def getRefFromFlatpakBundleHeader(header): + # This code is based on the code of the function `build_bundle()` in + # `app/flatpak-builtins-build-bundle.c` of flatpak. It reads the "ref" of + # the flatpak bundle from a serialized GVariant array. + if len(header) < 32: + raise Exception("Truncated or invalid Flatpak bundle (smaller than 32 bytes)") + # Flatpak bundles start with "flatpak\0" 01 00 89 e5 (or e5 89 00 01 in big endian) + # where the 01 can be used as a version, so that we ignore it + if not header.startswith(b"flatpak\0"): + raise Exception("Invalid Flatpak bundle header (doesn't start with 'flatpak')") + if header[9:12] != b"\x00\x89\xe5" and header[8:11] != b"\xe5\x89\x00": + raise Exception("Invalid Flatpak bundle header (wrong magic number)") + refKey = header.find(b"ref\0", 16) + if refKey == -1: + raise Exception("Start of 'ref' entry not found") + refValueStart = refKey + 8 # 0-terminated "ref" padded to 8 bytes + refValueEnd = header.find(b"\0", refValueStart) + if refValueEnd == -1: + raise Exception("End of 'ref' value not found") + ref = header[refValueStart:refValueEnd].decode(errors="replace") + return ref + + +def getRefFromFlatpakBundle(flatpakFilePath): + with open(flatpakFilePath, "rb") as f: + b = f.read(256) + try: + return getRefFromFlatpakBundleHeader(b) + except Exception as e: + log.debug("Error:", exc_info=e) + return None + + +def getAppIdFromRef(ref): + if ref is None: + raise Error("Failed to get application ID from flatpak bundle") + refParts = ref.split("/") + return refParts[1] if len(refParts) > 1 else "" + + +def getBranchFromRef(ref): + if ref is None: + raise Error("Failed to get branch from flatpak bundle") + refParts = ref.split("/") + return refParts[3] if len(refParts) > 3 else "" + + +def generateFlatpakref(cwd, appId, branch, repoUrlPrefix, repoName, runtimeRepoUrl, publicKeyPath, isRuntime): + # See https://docs.flatpak.org/en/latest/repositories.html#flatpakref-files + flatpakrefConfig = configparser.ConfigParser() + # overwrite optionxform to avoid key conversion to lowercase + flatpakrefConfig.optionxform = lambda option: option + ref = {} + ref["Name"] = appId + ref["Branch"] = branch + ref["Title"] = f"{appId} from {repoName}" + ref["SuggestRemoteName"] = repoName + ref["RuntimeRepo"] = runtimeRepoUrl + ref["IsRuntime"] = "true" if isRuntime else "false" + + if not repoUrlPrefix.endswith("/"): + repoUrlPrefix += "/" + + ref["Url"] = f"{repoUrlPrefix}{repoName}/" + + with open(publicKeyPath, "rb") as f: + encoded = base64.b64encode(f.read()) + ref["GPGKey"] = encoded.decode("utf-8") + + flatpakrefConfig["Flatpak Ref"] = ref + + filename = f"{appId}.flatpakref" + with open(cwd / filename, "w") as outputfile: + flatpakrefConfig.write(outputfile) + + return filename + + +def generateFlatpakrepo(cwd, repoUrlPrefix, repoName, iconFileName, publicKeyPath): + # See https://docs.flatpak.org/en/latest/hosting-a-repository.html#flatpakrepo-files + flatpakrepoConfig = configparser.ConfigParser() + # overwrite optionxform to avoid key conversion to lowercase + flatpakrepoConfig.optionxform = lambda option: option + ref = {} + ref["Title"] = repoName + ref["Homepage"] = "https://kde.org/" + ref["Comment"] = f"KDE {repoName} Flatpak repository" + ref["Description"] = f"KDE {repoName} Flatpak repository" + + if not repoUrlPrefix.endswith("/"): + repoUrlPrefix += "/" + + ref["Url"] = f"{repoUrlPrefix}{repoName}/" + if iconFileName: + ref["Icon"] = f"{repoUrlPrefix}{repoName}/{iconFileName}" + + with open(publicKeyPath, "rb") as f: + encoded = base64.b64encode(f.read()) + ref["GPGKey"] = encoded.decode("utf-8") + + flatpakrepoConfig["Flatpak Repo"] = ref + + filename = f"{repoName}.flatpakrepo" + with open(cwd / filename, "w") as outputfile: + flatpakrepoConfig.write(outputfile) + + return filename + + +class SignFlatpakProcessor(TaskProcessor): + requestClass = SignFlatpakRequest + + def getProjectSetting(self, name, required=True): + value = projects.settings.get(self.request.projectPath, self.request.branch, name) + if required and not value: + projectSettingsLocation = config.settings.get( + "General", + "ProjectSettings", + "flatpaksigner-projects.yaml next to the service's config file on the server", + ) + raise Error( + f"Project setting '{name}' not set for branch {self.request.branch} " + f"of project {self.request.projectPath}. Check configuration in {projectSettingsLocation}." + ) + return value + + def doProcess(self): + repoName = self.getProjectSetting("repository") + signingKey = self.getProjectSetting("signingkey") + + remoteFilePath = self.task.path() / self.request.fileName + with TemporaryDirectory() as workPathName: + workPath = Path(workPathName) + # use simple file names locally to avoid issues with user provided file names + localFilePath = workPath / "unsigned.flatpak" + self.sftp.download(remoteFilePath, localFilePath) + self.verifyApplicationId(localFilePath) + localLocaleBundlePath = None + if self.request.localeBundleFileName: + remoteLocaleBundlePath = self.task.path() / self.request.localeBundleFileName + localLocaleBundlePath = workPath / "locale.flatpak" + self.sftp.download(remoteLocaleBundlePath, localLocaleBundlePath) + self.verifyApplicationId(localLocaleBundlePath, expectedSuffix=".Locale") + localDebugBundlePath = None + if self.request.debugBundleFileName: + remoteDebugBundlePath = self.task.path() / self.request.debugBundleFileName + localDebugBundlePath = workPath / "debug.flatpak" + self.sftp.download(remoteDebugBundlePath, localDebugBundlePath) + self.verifyApplicationId(localDebugBundlePath, expectedSuffix=".Debug") + self.signFlatpak(localFilePath, localLocaleBundlePath, localDebugBundlePath, repoName, signingKey) + + def verifyApplicationId(self, flatpakFilePath, expectedSuffix=None): + ref = getRefFromFlatpakBundle(flatpakFilePath) + applicationId = getAppIdFromRef(ref) + allowedApplicationIds = self.getProjectSetting("applicationid") + if isinstance(allowedApplicationIds, str): + allowedApplicationIds = [allowedApplicationIds] + if expectedSuffix: + # append expected suffix to allowed application IDs and make them AppStream compatible + allowedApplicationIds = [appId.replace("-", "_") + expectedSuffix for appId in allowedApplicationIds] + if applicationId not in allowedApplicationIds: + projectSettingsLocation = config.settings.get( + "General", + "ProjectSettings", + "flatpaksigner-projects.yaml next to the service's config file on the server", + ) + raise Error( + f"The application ID of the Flatpak ({applicationId}) did not match any of the allowed application IDs " + f"({', '.join(allowedApplicationIds)}). Check configuration in {projectSettingsLocation}." + ) + + def signFlatpak(self, flatpakFilePath, localeBundlePath, debugBundlePath, repoName, signingKey): + workingDirectory = flatpakFilePath.parent + flatpakFileName = flatpakFilePath.name + remoteRepoPath = Path(config.settings.get("FlatpakSigning", "RemoteRepoPrefix")) / repoName + localRepoPath = workingDirectory / repoName + + # 1. Fetch the remote repository + # rsync the remote base path including only the wanted project repo; + # this way rsync doesn't fail if there isn't a repo for the project yet + command = [ + "rsync", + "-Ha", + "--delete", + f"--include={remoteRepoPath.name}", + f"--include={remoteRepoPath.name}/**", + "--exclude=*", + f"{remoteRepoPath.parent}/", + f"{localRepoPath.parent}/", + ] + util.runCommand(command, cwd=workingDirectory) + + # 1.5 Create a new local repo if there wasn't a remote repo + if not localRepoPath.exists(): + command = [ + "ostree", + "init", + f"--repo={localRepoPath}", + "--mode", + "archive-z2", + ] + util.runCommand(command, cwd=workingDirectory) + + # 2. Import the file bundle into the local repository signing the commit + command = [ + "flatpak", + "build-import-bundle", + "--update-appstream", + f"--gpg-sign={signingKey}", + f"{localRepoPath}", + f"{flatpakFileName}", + ] + util.runCommand(command, cwd=workingDirectory) + + # 2.1 Import the locale bundle into the local repository signing the commit + if localeBundlePath: + command = [ + "flatpak", + "build-import-bundle", + "--update-appstream", + f"--gpg-sign={signingKey}", + f"{localRepoPath}", + f"{localeBundlePath.name}", + ] + util.runCommand(command, cwd=workingDirectory) + + # 2.2 Import the debug bundle into the local repository signing the commit + if debugBundlePath: + command = [ + "flatpak", + "build-import-bundle", + "--update-appstream", + f"--gpg-sign={signingKey}", + f"{localRepoPath}", + f"{debugBundlePath.name}", + ] + util.runCommand(command, cwd=workingDirectory) + + # 3. Generate static deltas for all references + command = [ + "flatpak", + "build-update-repo", + "--prune", + "--prune-depth=10", + "--generate-static-deltas", + f"--gpg-sign={signingKey}", + f"{localRepoPath}", + ] + util.runCommand(command, cwd=workingDirectory) + + # 4. Push changes to the remote repository + command = [ + "rsync", + "-Ha", + "--delete", + f"{localRepoPath}/", + f"{remoteRepoPath}/", + ] + util.runCommand(command, cwd=workingDirectory) + + # 5. Create a .flatpakref file + ref = getRefFromFlatpakBundle(flatpakFilePath) + applicationId = getAppIdFromRef(ref) + branch = getBranchFromRef(ref) + repoUrlPrefix = config.settings.get("FlatpakSigning", "RepoURLPrefix") + publicKey = config.settings.getPath("FlatpakSigning", "RepoKeysLocation") / f"{signingKey}.gpg" + runtimeRepoUrl = projects.settings.get(self.request.projectPath, self.request.branch, "runtimerepourl") + isRuntime = projects.settings.getBool(self.request.projectPath, self.request.branch, "isruntime", False) + + refFileName = generateFlatpakref( + cwd=workingDirectory, + appId=applicationId, + branch=branch, + repoUrlPrefix=repoUrlPrefix, + repoName=repoName, + runtimeRepoUrl=runtimeRepoUrl, + publicKeyPath=publicKey, + isRuntime=isRuntime, + ) + + # 6. Push .flatpakref to the server + command = [ + "rsync", + "-Ha", + f"{workingDirectory}/{refFileName}", + f"{remoteRepoPath}/{refFileName}", + ] + util.runCommand(command, cwd=workingDirectory) + + # 7. Upload icon + iconPath = config.settings.getPath("FlatpakSigning", "RepoIconFile") + if iconPath is None: + iconFileName = "" + else: + iconFileName = "icon.svg" + + command = [ + "rsync", + "-Ha", + iconPath, + f"{remoteRepoPath}/{iconFileName}", + ] + util.runCommand(command, cwd=workingDirectory) + + # 8. Create a .flatpakrepo file + repoFileName = generateFlatpakrepo( + cwd=workingDirectory, + repoUrlPrefix=repoUrlPrefix, + repoName=repoName, + iconFileName=iconFileName, + publicKeyPath=publicKey, + ) + + # 9. Push .flatpakrepo to the server + command = [ + "rsync", + "-Ha", + f"{workingDirectory}/{repoFileName}", + f"{remoteRepoPath}/{repoFileName}", + ] + util.runCommand(command, cwd=workingDirectory) + + +class SignFlatpakWorker(Worker): + processorClass = SignFlatpakProcessor diff --git a/third_party/ci-notary-service/sftpnotary/googleplaypublisher.py b/third_party/ci-notary-service/sftpnotary/googleplaypublisher.py new file mode 100644 index 0000000..67ec7b9 --- /dev/null +++ b/third_party/ci-notary-service/sftpnotary/googleplaypublisher.py @@ -0,0 +1,343 @@ +# SPDX-License-Identifier: BSD-2-Clause +# SPDX-FileCopyrightText: 2021 Volker Krause +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + +import dataclasses +import logging +import os +import re +import shutil +import zipfile +from pathlib import Path +from tempfile import TemporaryDirectory +from typing import List, Optional + +from sftpnotary import apkutils, config, projects, util +from sftpnotary.aabsigner import SignAabBaseProcessor +from sftpnotary.core import Job, Request, Response, Worker +from sftpnotary.exceptions import Error, InvalidFileName +from sftpnotary.sftp import SFTPClient, SFTPError + +log = logging.getLogger(__name__) + + +@dataclasses.dataclass +class PublishOnGooglePlayRequest(Request): + fileNames: Optional[List[str]] = None # can be *.aab or *.apk files + fastlaneFileName: Optional[str] = None + + def validate(self): + if not self.fileNames: + raise InvalidFileName() + for fileName in self.fileNames: + util.validateFileName(fileName, strict=True) + if not fileName.endswith(".aab") and not fileName.endswith(".apk"): + raise InvalidFileName(fileName) + haveAAB = any(f for f in self.fileNames if f.endswith(".aab")) + if haveAAB and len(self.fileNames) > 1: + raise Error("Invalid request: Too many .aab files or .aab and .apk files given") + util.validateFileName(self.fastlaneFileName, strict=True) + + +PublishOnGooglePlayResponse = Response + + +class PublishOnGooglePlayJob(Job): + def __init__( + self, + sftp: SFTPClient, + filePaths: List[Path], + fastlaneFilePath: Path, + token: Optional[str] = None, + projectPath: Optional[str] = None, + branch: Optional[str] = None, + ): + super().__init__(sftp) + + self.filePaths = filePaths + self.fastlaneFilePath = fastlaneFilePath + self.request = PublishOnGooglePlayRequest( + fileNames=[], + fastlaneFileName=None, + token=token, + projectPath=projectPath, + branch=branch, + ) + self.resultPath = self.filePaths[0].parent + + def start(self): + for filePath in self.filePaths: + fileName = filePath.name + self.sftp.upload(filePath, self.task.path() / fileName) + self.request.fileNames.append(fileName) + fastlaneFileName = self.fastlaneFilePath.name + self.sftp.upload(self.fastlaneFilePath, self.task.path() / fastlaneFileName) + self.request.fastlaneFileName = fastlaneFileName + self.task.putRequest(self.request) + self.taskQueue.commitTask(self.task) + + def waitForCompletion(self): + self.taskQueue.waitForCompletion(self.task) + log.debug(f"Fetching response of task '{self.task.id}' ...") + response = None + try: + response = self.task.fetchResponse(PublishOnGooglePlayResponse) + except SFTPError as e: + log.error("Error: %s", e) + if response is None: + log.error("Error: Got no response. Task failed.") + else: + self.success = True + self.downloadLogFiles(self.resultPath) + self.taskQueue.removeTask(self.task) + + +GEM_FILE_TEMPLATE = """ +source "https://rubygems.org" +gem "fastlane" +""" + +APP_FILE_TEMPLATE = """ +json_key_file("{credentialsFilePath}") +package_name("{applicationId}") +""" + +FAST_FILE_TEMPLATE = """ +lane :upload_metadata do + google_version_code = google_play_track_version_codes(track: 'beta')[0] + supply( + package_name: "{applicationId}", + track: "beta", + skip_upload_apk: true, + skip_upload_aab: true, + skip_upload_changelogs: true, + skip_upload_metadata: false, + skip_upload_images: {skipImages}, + skip_upload_screenshots: {skipImages}, + version_code: google_version_code + ) +end +""" + + +class PublishOnGooglePlayProcessor(SignAabBaseProcessor): + requestClass = PublishOnGooglePlayRequest + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.fastlaneUpdatePath = config.settings.getPath("GooglePlayPublishing", "FastlaneDirectory") + self.fastlaneWorkPath = config.settings.getPath("GooglePlayPublishing", "FastlaneWorkingDirectory") + self.credentialsFilePath = config.settings.getPath("GooglePlayPublishing", "Credentials") + self.bundleExecutable = config.settings.getPath("GooglePlayPublishing", "BundleExecutable") + self.bundlePath = config.settings.getPath("GooglePlayPublishing", "BundlePath") + self.bundleAppConfig = config.settings.getPath("GooglePlayPublishing", "BundleAppConfig") + + self.applicationId = "" + + def doProcess(self): + self.updateFastlane() + + with TemporaryDirectory() as tempPathName: + tempPath = Path(tempPathName) + + # download the AAB or APKs + localFilePaths = [] + for fileName in self.request.fileNames: + localFilePath = tempPath / fileName + self.sftp.download(self.task.path() / fileName, localFilePath) + localFilePaths.append(localFilePath) + localApkFilePaths = [p for p in localFilePaths if p.suffix == ".apk"] + localAabFilePath = None if localApkFilePaths else localFilePaths[0] + # download the fastlane metadata file + localFastlaneFilePath = tempPath / self.request.fastlaneFileName + self.sftp.download(self.task.path() / self.request.fastlaneFileName, localFastlaneFilePath) + + allowedApplicationId = projects.settings.get(self.request.projectPath, self.request.branch, "applicationid") + if localAabFilePath: + self.verifyApplicationId([localAabFilePath], allowedApplicationId) + self.applicationId = allowedApplicationId + signedAabFilePath = self.signAab(localAabFilePath) + self.publishAab(signedAabFilePath, localFastlaneFilePath) + else: + self.verifyApplicationId(localApkFilePaths, allowedApplicationId) + self.applicationId = allowedApplicationId + self.publishApks(localApkFilePaths, localFastlaneFilePath) + + def updateFastlane(self): + command = [self.bundleExecutable, "update", "fastlane"] + workPath = self.fastlaneUpdatePath + environment = { + **os.environ, + "BUNDLE_EXECUTABLE": self.bundleExecutable, + "BUNDLE_PATH": self.bundlePath, + "BUNDLE_APP_CONFIG": self.bundleAppConfig, + } + try: + util.runCommand(command, cwd=workPath, env=environment) + except Error: + # continue the publishing process even if the update of Fastlane failed + pass + + def configureFastlane(self, fastlaneFilePath): + workPath = self.fastlaneWorkPath / self.applicationId + os.makedirs(workPath / "fastlane", exist_ok=True) + + # write Gemfile + with open(workPath / "Gemfile", "w") as f: + f.write(GEM_FILE_TEMPLATE) + # remove Gemfile.lock, otherwise the shared updates won't be visible in this remains + # pinned to the first fastlane version it ever saw + lockfile = workPath / "Gemfile.lock" + lockfile.unlink(missing_ok=True) + + # write Appfile + with open(workPath / "fastlane" / "Appfile", "w") as f: + f.write( + APP_FILE_TEMPLATE.format(credentialsFilePath=self.credentialsFilePath, applicationId=self.applicationId) + ) + + self.updateMetaData(fastlaneFilePath) + + def publishAab(self, aabFilePath, fastlaneFilePath): + self.configureFastlane(fastlaneFilePath) + + log.info("Uploading AAB") + self.runFastlaneCommand( + [ + "supply", + "--aab", + aabFilePath, + "--track", + "beta", + "--release_status", + "draft", + "--skip_upload_images", + "true", + "--skip_upload_screenshots", + "true", + ] + ) + + def publishApks(self, apkFilePaths, fastlaneFilePath): + self.configureFastlane(fastlaneFilePath) + + log.info("Uploading APKs") + self.runFastlaneCommand( + [ + "supply", + "--apk_paths", + ",".join(str(p) for p in apkFilePaths), + "--track", + "beta", + "--release_status", + "draft", + "--skip_upload_images", + "true", + "--skip_upload_screenshots", + "true", + ] + ) + + def updateMetaData(self, fastlaneFilePath): + workPath = self.fastlaneWorkPath / self.applicationId + + # Remove meta data from previous run; otherwise, nothing is downloaded + # Moreover, we get rid of translations with invalid locale IDs that were + # not yet filtered out in the previous run + metaDataPath = workPath / "fastlane" / "metadata" / "android" + if metaDataPath.exists(): + shutil.rmtree(metaDataPath) + + # + # Download existing meta data for comparison + # + log.info("Downloading existing metadata") + self.runFastlaneCommand(["supply", "init"]) + # Running "fastlane supply init" fails if there is no release in the production track + # (https://github.com/fastlane/fastlane/issues/21505). + # As workaround one can create a production release but save it as draft. + + # + # check whether there are metadata updates + # + textChanged = False + imageChanged = False + with zipfile.ZipFile(fastlaneFilePath, "r") as zipFile: + fileNames = apkutils.filterFastlaneFileNames(zipFile.namelist(), self.applicationId) + for fileName in fileNames: + # directories or top-level elements + if "/" not in fileName or fileName.endswith("/"): + continue + + # determine the file name in the fastlane structure (without trailing folder) + _, relativeFileName = fileName.split("/", maxsplit=1) + outFileName = workPath / "fastlane" / "metadata" / "android" / relativeFileName + # adjust file names for screenshots + outFileName = Path( + re.sub( + r"/android/([^/]*)/images/([^/]*)/(\d)-.*\.png", + r"/android/\1/images/\2/\3_\1.png", + str(outFileName), + ) + ) + + with zipFile.open(fileName) as inFile: + inData = inFile.read() + + outData = b"" + if outFileName.exists(): + with open(outFileName, "rb") as outFile: + outData = outFile.read() + + if inData == outData: + log.debug(f"comparing '{fileName}' and '{outFileName}'... no change") + continue + + log.debug(f"comparing '{fileName}' and '{outFileName}'... needs updating") + outFileName.parent.mkdir(parents=True, exist_ok=True) + with open(outFileName, "wb") as outFile: + outFile.write(inData) + + # remember what we need to update + if outFileName.suffix == ".png": + imageChanged = True + else: + textChanged = True + + # + # Upload metadata changes if necessary + # + if not textChanged and not imageChanged: + log.info("Skipping upload of metadata") + log.debug("No metadata changes found.") + else: + log.info("Uploading metadata") + log.debug(f"Needs image asset upload: {imageChanged}") + # write Fastfile + with open(workPath / "fastlane" / "Fastfile", "w") as f: + f.write( + FAST_FILE_TEMPLATE.format( + applicationId=self.applicationId, skipImages=("false" if imageChanged else "true") + ) + ) + # submit updates + self.runFastlaneCommand(["upload_metadata"]) + # Running "fastlane upload_metadata" fails if there is no release in the beta track. + # As workaround one can create a beta release but save it as draft. + + def runFastlaneCommand(self, command): + command = [self.bundleExecutable, "exec", "fastlane"] + command + workPath = self.fastlaneWorkPath / self.applicationId + environment = { + **os.environ, + "BUNDLE_EXECUTABLE": self.bundleExecutable, + "BUNDLE_PATH": self.bundlePath, + "BUNDLE_APP_CONFIG": self.bundleAppConfig, + } + util.runCommand(command, cwd=workPath, env=environment) + + +class PublishOnGooglePlayWorker(Worker): + processorClass = PublishOnGooglePlayProcessor diff --git a/third_party/ci-notary-service/sftpnotary/log.py b/third_party/ci-notary-service/sftpnotary/log.py new file mode 100644 index 0000000..eb1f4ec --- /dev/null +++ b/third_party/ci-notary-service/sftpnotary/log.py @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: BSD-2-Clause +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + +import logging +from contextlib import contextmanager +from pathlib import Path +from typing import Union + +standardFormat = "%(asctime)s %(levelname)s %(name)s %(message)s" + +_taskLogFormatter = None + + +@contextmanager +def captureTaskLog(logFilePath: Union[str, Path]): + with open(logFilePath, "w", encoding="utf-8") as logFile: + # set up a logging handler for capturing messages when processing a task + handler = logging.StreamHandler(logFile) + handler.setLevel(logging.INFO) + if _taskLogFormatter is not None: + handler.setFormatter(_taskLogFormatter) + logging.getLogger("sftpnotary").addHandler(handler) + yield + logging.getLogger("sftpnotary").removeHandler(handler) + + +@contextmanager +def captureTaskDebugLog(logFilePath: Union[str, Path]): + with open(logFilePath, "w", encoding="utf-8") as logFile: + # set up a logging handler for capturing debug logs when processing a task + handler = logging.StreamHandler(logFile) + handler.setLevel(logging.DEBUG) + if _taskLogFormatter is not None: + handler.setFormatter(_taskLogFormatter) + logging.getLogger("sftpnotary").addHandler(handler) + yield + logging.getLogger("sftpnotary").removeHandler(handler) + + +def setNameForTaskLogs(name: str): + global _taskLogFormatter + _taskLogFormatter = logging.Formatter(f"%(asctime)s %(levelname)s {name} %(message)s") + + +def maskFollowingItem(v: list, x: str, mask="[MASKED]") -> list: + """Returns a list where the item following the item that is equal to x + in v is replaced with mask. + + If a replacement is made, then a copy of v is returned. v is never + modified. Does nothing if x is not found in v. + + This function is mostly useful for masking sensitive information like + passwords in command line arguments when they are logged.""" + if x in v: + copy = list(v) + indexToMask = copy.index(x) + 1 + copy[indexToMask] = mask + return copy + + return v diff --git a/third_party/ci-notary-service/sftpnotary/macappnotarizer.py b/third_party/ci-notary-service/sftpnotary/macappnotarizer.py new file mode 100644 index 0000000..d5556ac --- /dev/null +++ b/third_party/ci-notary-service/sftpnotary/macappnotarizer.py @@ -0,0 +1,80 @@ +# SPDX-License-Identifier: BSD-2-Clause +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker +# SPDX-FileCopyrightText: 2023 Julius Künzel + +import logging +from pathlib import Path +from tempfile import TemporaryDirectory +from typing import Optional + +import sftpnotary.log +from sftpnotary import appleutils, config, projects, util +from sftpnotary.core import SignFileResponse, SingleFileRequest, Worker +from sftpnotary.sftp import SFTPClient + +log = logging.getLogger(__name__) + +NotarizeMacAppRequest = SingleFileRequest +NotarizeMacAppResponse = SignFileResponse + + +class NotarizeMacAppJob(appleutils.AppleJob): + def __init__( + self, + sftp: SFTPClient, + macAppFilePath: Path, + logFolder: Path, + token: Optional[str] = None, + projectPath: Optional[str] = None, + branch: Optional[str] = None, + ): + super().__init__(sftp, macAppFilePath, logFolder) + + self.request = NotarizeMacAppRequest( + fileName=macAppFilePath.name, token=token, projectPath=projectPath, branch=branch + ) + self.responseClass = NotarizeMacAppResponse + + +class NotarizeMacAppProcessor(appleutils.AppleTaskProcessor): + requestClass = NotarizeMacAppRequest + responseClass = NotarizeMacAppResponse + resultNameSuffix = "notarized" + + def doProcess(self): + remoteFilePath = self.task.path() / self.request.fileName + + with TemporaryDirectory() as workPathName: + workPath = Path(workPathName) + + localFilePath = self.downloadApp(workPath, remoteFilePath) + + allowedApplicationId = projects.settings.get(self.request.projectPath, self.request.branch, "applicationid") + appleutils.verifyApplicationId(localFilePath, allowedApplicationId) + self.notarizeMacApp(localFilePath) + + return self.uploadApp(workPath, localFilePath, remoteFilePath, localFilePath) + + def notarizeMacApp(self, filePath): + workingDirectory = filePath.parent + fileName = filePath.name + + rcodesignPath = config.settings.getPath("AppleTools", "RCodesignPath") or "rcodesign" + + command = [rcodesignPath, "notary-submit", "-v"] + + apiKey = config.settings.get("MacAppNotarization", "ApiKey") + if apiKey.startswith("file:"): + apiKey = Path(apiKey[5:]).expanduser() + command += ["--api-key-file", apiKey] + else: + command += ["--api-key", apiKey] + + command += ["--staple", fileName] + commandToLog = sftpnotary.log.maskFollowingItem(command, "--api-key") + util.runCommand(command, commandToLog=commandToLog, cwd=workingDirectory) + + +class NotarizeMacAppWorker(Worker): + processorClass = NotarizeMacAppProcessor diff --git a/third_party/ci-notary-service/sftpnotary/macappsigner.py b/third_party/ci-notary-service/sftpnotary/macappsigner.py new file mode 100644 index 0000000..dc5091f --- /dev/null +++ b/third_party/ci-notary-service/sftpnotary/macappsigner.py @@ -0,0 +1,138 @@ +# SPDX-License-Identifier: BSD-2-Clause +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker +# SPDX-FileCopyrightText: 2023 Julius Künzel + +import dataclasses +import logging +from pathlib import Path +from tempfile import TemporaryDirectory +from typing import Optional + +import sftpnotary.log +from sftpnotary import appleutils, config, projects, util +from sftpnotary.core import SignFileResponse, SingleFileRequest, Worker +from sftpnotary.entitlements_whitelist import validate_entitlements_file +from sftpnotary.exceptions import InvalidFileName +from sftpnotary.sftp import SFTPClient + +log = logging.getLogger(__name__) + + +@dataclasses.dataclass +class SignMacAppRequest(SingleFileRequest): + """Extends SingleFileRequest to include optional entitlements file name for mac app signing.""" + + entitlementsFileName: Optional[str] = None + + def validate(self): + super().validate() + if self.entitlementsFileName: + util.validateFileName(self.entitlementsFileName) + # Must end with .entitlements + if not self.entitlementsFileName.endswith(".entitlements"): + raise InvalidFileName(f"Entitlements file must end with .entitlements: {self.entitlementsFileName}") + # Must match .entitlements pattern + if self.projectPath: + expectedName = f"{self.projectPath.split('/')[-1]}.entitlements" + if self.entitlementsFileName != expectedName: + raise InvalidFileName( + f"Entitlements file name must match project: " + f"expected {expectedName}, got {self.entitlementsFileName}" + ) + + +SignMacAppResponse = SignFileResponse + + +class SignMacAppJob(appleutils.AppleJob): + def __init__( + self, + sftp: SFTPClient, + macAppFilePath: Path, + logFolder: Path, + entitlementsFilePath: Optional[Path] = None, + token: Optional[str] = None, + projectPath: Optional[str] = None, + branch: Optional[str] = None, + ): + super().__init__(sftp, macAppFilePath, logFolder) + + self.entitlementsFilePath = entitlementsFilePath + self.request = SignMacAppRequest( + fileName=macAppFilePath.name, + entitlementsFileName=(entitlementsFilePath.name if entitlementsFilePath else None), + token=token, + projectPath=projectPath, + branch=branch, + ) + self.responseClass = SignMacAppResponse + + def start(self): + self.uploadUnsignedFile() + if self.entitlementsFilePath: + remotePath = self.task.path() / self.entitlementsFilePath.name + self.sftp.upload(self.entitlementsFilePath, remotePath) + self.task.putRequest(self.request) + self.taskQueue.commitTask(self.task) + + +class SignMacAppProcessor(appleutils.AppleTaskProcessor): + requestClass = SignMacAppRequest + responseClass = SignMacAppResponse + resultNameSuffix = "signed" + + def doProcess(self): + remoteFilePath = self.task.path() / self.request.fileName + + with TemporaryDirectory() as workPathName: + workPath = Path(workPathName) + + localFilePath = self.downloadApp(workPath, remoteFilePath) + localSignedFilePath = workPath / f"processed{localFilePath.suffix}" + + # Download entitlements if provided + entitlementsPath = None + if self.request.entitlementsFileName: + remoteEntitlementsPath = self.task.path() / self.request.entitlementsFileName + entitlementsPath = workPath / self.request.entitlementsFileName + self.sftp.download(remoteEntitlementsPath, entitlementsPath) + validate_entitlements_file(entitlementsPath) + log.info(f"Validated entitlements: {self.request.entitlementsFileName}") + + allowedApplicationId = projects.settings.get(self.request.projectPath, self.request.branch, "applicationid") + appleutils.verifyApplicationId(localFilePath, allowedApplicationId) + self.signMacApp(localFilePath, localSignedFilePath.name, entitlementsPath) + + return self.uploadApp(workPath, localSignedFilePath, remoteFilePath, localFilePath) + + def signMacApp(self, sourceFilePath, signedFileName, entitlementsPath: Optional[Path] = None): + workingDirectory = sourceFilePath.parent + sourceFileName = sourceFilePath.name + rcodesignPath = config.settings.getPath("AppleTools", "RCodesignPath") or "rcodesign" + + keystore = config.settings.getPath("MacAppSigning", "KeyStore") + keystorepass = config.settings.get("MacAppSigning", "KeyStorePass") + command = [rcodesignPath, "sign", "-v", "--for-notarization"] + if keystore and keystore.suffix in [".pem", ".crt", ".key"]: + command += ["--pem-file", Path(keystore)] + elif keystore and keystore.suffix in [".p12", ".pfx"]: + command += ["--p12-file", Path(keystore)] + if keystorepass: + if keystorepass.startswith("file:"): + keystorepass = Path(keystorepass[5:]).expanduser() + command += ["--p12-password-file", keystorepass] + else: + command += ["--p12-password", keystorepass] + + # Apply entitlements if provided + if entitlementsPath and entitlementsPath.exists(): + command += ["--entitlements-xml-path", entitlementsPath] + + command += [sourceFileName, signedFileName] + commandToLog = sftpnotary.log.maskFollowingItem(command, "--p12-password") + util.runCommand(command, commandToLog=commandToLog, cwd=workingDirectory) + + +class SignMacAppWorker(Worker): + processorClass = SignMacAppProcessor diff --git a/third_party/ci-notary-service/sftpnotary/microsoftstoreclient.py b/third_party/ci-notary-service/sftpnotary/microsoftstoreclient.py new file mode 100644 index 0000000..91b0c20 --- /dev/null +++ b/third_party/ci-notary-service/sftpnotary/microsoftstoreclient.py @@ -0,0 +1,56 @@ +# SPDX-License-Identifier: BSD-2-Clause +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + +import logging +from pathlib import Path +from typing import Optional + +from sftpnotary.core import Job +from sftpnotary.microsoftstoredata import PublishOnMicrosoftStoreRequest, PublishOnMicrosoftStoreResponse +from sftpnotary.sftp import SFTPClient, SFTPError + +log = logging.getLogger(__name__) + + +class PublishOnMicrosoftStoreJob(Job): + def __init__( + self, + sftp: SFTPClient, + appxFilePath: Path, + token: Optional[str] = None, + projectPath: Optional[str] = None, + branch: Optional[str] = None, + ): + super().__init__(sftp) + + self.appxFilePath = appxFilePath + self.request = PublishOnMicrosoftStoreRequest( + fileName=None, + token=token, + projectPath=projectPath, + branch=branch, + ) + self.resultPath = self.appxFilePath.parent + + def start(self): + appxFileName = self.appxFilePath.name + self.sftp.upload(self.appxFilePath, self.task.path() / appxFileName) + self.request.fileName = appxFileName + self.task.putRequest(self.request) + self.taskQueue.commitTask(self.task) + + def waitForCompletion(self): + self.taskQueue.waitForCompletion(self.task) + log.debug(f"Fetching response of task '{self.task.id}' ...") + response = None + try: + response = self.task.fetchResponse(PublishOnMicrosoftStoreResponse) + except SFTPError as e: + log.error("Error: %s", e) + if response is None: + log.error("Error: Got no response. Task failed.") + else: + self.success = True + self.downloadLogFiles(self.resultPath) + self.taskQueue.removeTask(self.task) diff --git a/third_party/ci-notary-service/sftpnotary/microsoftstoredata.py b/third_party/ci-notary-service/sftpnotary/microsoftstoredata.py new file mode 100644 index 0000000..3f4ece5 --- /dev/null +++ b/third_party/ci-notary-service/sftpnotary/microsoftstoredata.py @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: BSD-2-Clause +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + +import dataclasses +from typing import Optional + +from sftpnotary import util +from sftpnotary.core import Request, Response + + +@dataclasses.dataclass +class PublishOnMicrosoftStoreRequest(Request): + fileName: Optional[str] = None + + def validate(self): + util.validateFileName(self.fileName, strict=True) + + +PublishOnMicrosoftStoreResponse = Response diff --git a/third_party/ci-notary-service/sftpnotary/microsoftstoreservice.py b/third_party/ci-notary-service/sftpnotary/microsoftstoreservice.py new file mode 100644 index 0000000..dac1afa --- /dev/null +++ b/third_party/ci-notary-service/sftpnotary/microsoftstoreservice.py @@ -0,0 +1,68 @@ +# SPDX-License-Identifier: BSD-2-Clause +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + +import json +import logging +from pathlib import Path +from tempfile import TemporaryDirectory + +from sftpnotary import config, microsoftstoresubmission, projects +from sftpnotary.core import TaskProcessor, Worker +from sftpnotary.exceptions import Error +from sftpnotary.microsoftstoredata import PublishOnMicrosoftStoreRequest, PublishOnMicrosoftStoreResponse + +log = logging.getLogger(__name__) + + +class PublishOnMicrosoftStoreProcessor(TaskProcessor): + requestClass = PublishOnMicrosoftStoreRequest + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + credentialsPath = config.settings.getPath("MicrosoftStorePublishing", "Credentials") + if credentialsPath is None: + raise Error("Credentials not set in config.") + with open(credentialsPath, "r") as credentialsFile: + credentials = json.load(credentialsFile) + self.tenantId = credentials["tenant_id"] + self.clientId = credentials["client_id"] + self.clientSecret = credentials["client_secret"] + + def getProjectSetting(self, name, required=True): + value = projects.settings.get(self.request.projectPath, self.request.branch, name) + if required and not value: + raise Error( + f"Project setting '{name}' not set for branch {self.request.branch} " + f"of project {self.request.projectPath}" + ) + return value + + def doProcess(self): + appstreamId = self.getProjectSetting("appstreamid") + keepProps = self.getProjectSetting("keep", required=False) or [] + if not isinstance(keepProps, list): + raise Error("Project setting 'keep' must be a list") + keepProps = [s.lower() for s in keepProps] + + with TemporaryDirectory() as workPathName: + workPath = Path(workPathName) + + localAppxFilePath = workPath / self.request.fileName + self.sftp.download(self.task.path() / self.request.fileName, localAppxFilePath) + + microsoftstoresubmission.submitApp( + localAppxFilePath, + appstreamId=appstreamId, + keep=keepProps, + tenantId=self.tenantId, + clientId=self.clientId, + clientSecret=self.clientSecret, + ) + + return PublishOnMicrosoftStoreResponse() + + +class PublishOnMicrosoftStoreWorker(Worker): + processorClass = PublishOnMicrosoftStoreProcessor diff --git a/third_party/ci-notary-service/sftpnotary/microsoftstoresubmission.py b/third_party/ci-notary-service/sftpnotary/microsoftstoresubmission.py new file mode 100644 index 0000000..90dbdd4 --- /dev/null +++ b/third_party/ci-notary-service/sftpnotary/microsoftstoresubmission.py @@ -0,0 +1,874 @@ +# SPDX-License-Identifier: BSD-2-Clause +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + +import json +import logging +import os +from pathlib import Path +from tempfile import TemporaryDirectory +from urllib.parse import urlparse +from zipfile import ZipFile + +import requests +from azure.storage.blob import BlobClient +from markdownify import markdownify # type: ignore +from microstore.MicrosoftStoreClient import APIError, AuthorizationError, MicrosoftStoreClient # type: ignore + + +class Error(Exception): + pass + + +logger = logging.getLogger(__name__) + +# Maps AppStream language ID to Microsoft language ID +appstream_to_microsoft_language = { + "en": "en-us", # the apps.kde.org appdata is actually a bit mangled the real key would be C not 'en' + "sr": "sr-cyrl", + "sr-la": "sr-Latn", # preserve capital letter (by default we downcase) + "ca-va": "ca-es-valencia", + "az": "az-arab", +} +# Languages that are supported by Microsoft Store +# (https://docs.microsoft.com/en-us/windows/uwp/publish/supported-languages): +microsoft_languages = [ + # Arabic + "ar", + "ar-sa", + "ar-ae", + "ar-bh", + "ar-dz", + "ar-eg", + "ar-iq", + "ar-jo", + "ar-kw", + "ar-lb", + "ar-ly", + "ar-ma", + "ar-om", + "ar-qa", + "ar-sy", + "ar-tn", + "ar-ye", + # Afrikaans + "af", + "af-za", + # Albanian + "sq", + "sq-al", + # Amharic + "am", + "am-et", + # Armenian + "hy", + "hy-am", + # Assamese + "as", + "as-in", + # Azerbaijani + "az-arab", + "az-arab-az", + "az-cyrl", + "az-cyrl-az", + "az-latn", + "az-latn-az", + # Basque (Basque) + "eu", + "eu-es", + # Belarusian + "be", + "be-by", + # Bangla + "bn", + "bn-bd", + "bn-in", + # Bosnian + "bs", + "bs-cyrl", + "bs-cyrl-ba", + "bs-latn", + "bs-latn-ba", + # Bulgarian + "bg", + "bg-bg", + # Catalan + "ca", + "ca-es", + "ca-es-valencia", + # Cherokee + "chr-cher", + "chr-cher-us", + "chr-latn", + # Chinese (Simplified) + "zh-Hans", + "zh-cn", + "zh-hans-cn", + "zh-sg", + "zh-hans-sg", + # Chinese (Traditional) + "zh-Hant", + "zh-hk", + "zh-mo", + "zh-tw", + "zh-hant-hk", + "zh-hant-mo", + "zh-hant-tw", + # Croatian + "hr", + "hr-hr", + "hr-ba", + # Czech + "cs", + "cs-cz", + # Danish + "da", + "da-dk", + # Dari + "prs", + "prs-af", + "prs-arab", + # Dutch + "nl", + "nl-nl", + "nl-be", + # English + "en", + "en-au", + "en-ca", + "en-gb", + "en-ie", + "en-in", + "en-nz", + "en-sg", + "en-us", + "en-za", + "en-bz", + "en-hk", + "en-id", + "en-jm", + "en-kz", + "en-mt", + "en-my", + "en-ph", + "en-pk", + "en-tt", + "en-vn", + "en-zw", + "en-053", + "en-021", + "en-029", + "en-011", + "en-018", + "en-014", + # Estonian + "et", + "et-ee", + # Filipino + "fil", + "fil-latn", + "fil-ph", + # Finnish + "fi", + "fi-fi", + # French + "fr", + "fr-be", + "fr-ca", + "fr-ch", + "fr-fr", + "fr-lu", + "fr-015", + "fr-cd", + "fr-ci", + "fr-cm", + "fr-ht", + "fr-ma", + "fr-mc", + "fr-ml", + "fr-re", + "frc-latn", + "frp-latn", + "fr-155", + "fr-029", + "fr-021", + "fr-011", + # Galician + "gl", + "gl-es", + # Georgian + "ka", + "ka-ge", + # German + "de", + "de-at", + "de-ch", + "de-de", + "de-lu", + "de-li", + # Greek + "el", + "el-gr", + # Gujarati + "gu", + "gu-in", + # Hausa + "ha", + "ha-latn", + "ha-latn-ng", + # Hebrew + "he", + "he-il", + # Hindi + "hi", + "hi-in", + # Hungarian + "hu", + "hu-hu", + # Icelandic + "is", + "is-is", + # Igbo + "ig-latn", + "ig-ng", + # Indonesian + "id", + "id-id", + # Inuktitut (Latin) + "iu-cans", + "iu-latn", + "iu-latn-ca", + # Irish + "ga", + "ga-ie", + # isiXhosa + "xh", + "xh-za", + # isiZulu + "zu", + "zu-za", + # Italian + "it", + "it-it", + "it-ch", + # Japanese + "ja", + "ja-jp", + # Kannada + "kn", + "kn-in", + # Kazakh + "kk", + "kk-kz", + # Khmer + "km", + "km-kh", + # K'iche', + "quc-latn", + "qut-gt", + "qut-latn", + # Kinyarwanda + "rw", + "rw-rw", + # KiSwahili + "sw", + "sw-ke", + # Konkani + "kok", + "kok-in", + # Korean + "ko", + "ko-kr", + # Kurdish + "ku-arab", + "ku-arab-iq", + # Kyrgyz + "ky-kg", + "ky-cyrl", + # Lao + "lo", + "lo-la", + # Latvian + "lv", + "lv-lv", + # Lithuanian + "lt", + "lt-lt", + # Luxembourgish + "lb", + "lb-lu", + # Macedonian + "mk", + "mk-mk", + # Malay + "ms", + "ms-bn", + "ms-my", + # Malayalam + "ml", + "ml-in", + # Maltese + "mt", + "mt-mt", + # Maori + "mi", + "mi-latn", + "mi-nz", + # Marathi + "mr", + "mr-in", + # Mongolian (Cyrillic) + "mn-cyrl", + "mn-mong", + "mn-mn", + "mn-phag", + # Nepali + "ne", + "ne-np", + # Norwegian + "nb", + "nb-no", + "nn", + "nn-no", + "no", + "no-no", + # Odia + "or", + "or-in", + # Persian + "fa", + "fa-ir", + # Polish + "pl", + "pl-pl", + # Portuguese (Brazil) + "pt-br", + # Portuguese (Portugal) + "pt", + "pt-pt", + # Punjabi + "pa", + "pa-arab", + "pa-arab-pk", + "pa-deva", + "pa-in", + # Quechua + "quz", + "quz-bo", + "quz-ec", + "quz-pe", + # Romanian + "ro", + "ro-ro", + # Russian + "ru", + "ru-ru", + # Scottish Gaelic + "gd-gb", + "gd-latn", + # Serbian (Latin) + "sr-Latn", + "sr-latn-cs", + "sr", + "sr-latn-ba", + "sr-latn-me", + "sr-latn-rs", + # Serbian (Cyrillic) + "sr-cyrl", + "sr-cyrl-ba", + "sr-cyrl-cs", + "sr-cyrl-me", + "sr-cyrl-rs", + # Sesotho sa Leboa + "nso", + "nso-za", + # Setswana + "tn", + "tn-bw", + "tn-za", + # Sindhi + "sd-arab", + "sd-arab-pk", + "sd-deva", + # Sinhala + "si", + "si-lk", + # Slovak + "sk", + "sk-sk", + # Slovenian + "sl", + "sl-si", + # Spanish + "es", + "es-cl", + "es-co", + "es-es", + "es-mx", + "es-ar", + "es-bo", + "es-cr", + "es-do", + "es-ec", + "es-gt", + "es-hn", + "es-ni", + "es-pa", + "es-pe", + "es-pr", + "es-py", + "es-sv", + "es-us", + "es-uy", + "es-ve", + "es-019", + "es-419", + # Swedish + "sv", + "sv-se", + "sv-fi", + # Tajik (Cyrillic) + "tg-arab", + "tg-cyrl", + "tg-cyrl-tj", + "tg-latn", + # Tamil + "ta", + "ta-in", + # Tatar + "tt-arab", + "tt-cyrl", + "tt-latn", + "tt-ru", + # Telugu + "te", + "te-in", + # Thai + "th", + "th-th", + # Tigrinya + "ti", + "ti-et", + # Turkish + "tr", + "tr-tr", + # Turkmen + "tk-cyrl", + "tk-latn", + "tk-tm", + "tk-latn-tr", + "tk-cyrl-tr", + # Ukrainian + "uk", + "uk-ua", + # Urdu + "ur", + "ur-pk", + # Uyghur + "ug-arab", + "ug-cn", + "ug-cyrl", + "ug-latn", + # Uzbek (Latin) + "uz", + "uz-cyrl", + "uz-latn", + "uz-latn-uz", + # Vietnamese + "vi", + "vi-vn", + # Welsh + "cy", + "cy-gb", + # Wolof + "wo", + "wo-sn", + # Yoruba + "yo-latn", + "yo-ng", +] +# Languages supported by KDE that are not supported by Microsoft: +# * ast (Asturian), ia (Interlingua), ie (Interlingue) are not supported by Microsoft +# * some SR variants are not a thing outside the KDE bubble +# * x-test + + +def getAppStreamData(appstreamId): + r = requests.get(f"https://apps.kde.org/appdata/{appstreamId}.json", timeout=5) + r.raise_for_status() + return r.json() + + +def createListing(title): + return { + "baseListing": { + "copyrightAndTrademarkInfo": "", + "keywords": [], + "licenseTerms": "", + "privacyPolicy": "", + "supportContact": "", + "websiteUrl": "", + "description": "", + "features": [], + "releaseNotes": "", + "images": [], + "recommendedHardware": [], + "minimumHardware": [], + "title": title, + "shortDescription": "", + "shortTitle": "", + "sortTitle": "", + "voiceTitle": "", + "devStudio": "", + } + } + + +def downloadFile(url, downloadPath): + if url is None: + return None + + localPath = downloadPath / Path(urlparse(url).path).name + if localPath.exists(): + logger.debug(f"File {localPath} already exists. Skipping download.") + return localPath + + logger.debug(f"Downloading {url}") + r = requests.get(url, timeout=5) + if not r.ok: + logger.warning(f"Failed to download {url}") + return None + logger.debug(f"Writing file to {localPath}") + os.makedirs(downloadPath, exist_ok=True) + with open(localPath, "wb") as f: + f.write(r.content) + return localPath + + +def reformatDescription(description): + description = description.strip() + if description.startswith("<"): + # convert any linebreaks in the HTML code to spaces (linebreaks are + # meaningless in HTML, but markdownify does not touch them) + description = description.replace("\n", " ") + # convert HTML description to Markdown (Microsoft Store only supports + # plain text, but some Markdown looks nicer) + description = markdownify(description, heading_style="UNDERLINED").strip() + # remove leading (and trailing) whitespace from all lines + description = "\n".join(line.strip() for line in description.split("\n")) + return description + + +def updateBaseListingForLanguage(lang, storeLang, baseListing, defaultBaseListing, appstreamData, downloadPath, keep): + # update description for listing + storeDescription = baseListing.get("description", "") + if "description" not in keep or not storeDescription: + description = appstreamData.get("Description", {}).get(lang, "") + if description: + baseListing["description"] = reformatDescription(description) + elif storeDescription: + logger.debug(f"No description for {lang}. Keeping existing description in listing for language.") + else: + logger.debug(f"No description for {lang}. Skipping update of listing for language.") + return None + + # copyrightAndTrademarkInfo - AppStream does not provide this + + # update keywords for listing + if "keywords" not in keep or not baseListing["keywords"]: + baseListing["keywords"] = appstreamData.get("Keywords", {}).get(lang, []) + + # update licenseTerms for listing + if "licenseterms" not in keep or not baseListing["licenseTerms"]: + baseListing["licenseTerms"] = appstreamData.get("ProjectLicense", "") + + # privacyPolicy - This value is obsolete. The privacy policy URL must be set in Partner Center. + + # supportContact - This value is obsolete. The support contact URL or email address must be set in Partner Center. + + # websiteUrl - This value is obsolete. The URL of the web page for your app must be set in Partner Center. + + # features - AppStream does not provide a list of features (https://github.com/ximion/appstream/issues/388) + + # update releaseNotes for listing + if "releasenotes" not in keep or not baseListing["releaseNotes"]: + releases = appstreamData.get("Releases") + if releases: # not None and not empty + latestRelease = releases[0] + releaseNotes = latestRelease.get("description", {}).get(lang, "") or defaultBaseListing["releaseNotes"] + if not releaseNotes: + latestVersion = latestRelease.get("version") + if latestVersion: + releaseNotes = f"Update to version {latestVersion}" + baseListing["releaseNotes"] = reformatDescription(releaseNotes) + else: + baseListing["releaseNotes"] = "" + + # update images for listing + if "images" not in keep or not baseListing["images"]: + newScreenshots = [] + # prefer Windows-specific screenshots with environment="windows" + for screenshot in appstreamData.get("Screenshots", []): + if screenshot.get("environment") != "windows": + continue + url = screenshot.get("source-image", {}).get("url") + imagePath = downloadFile(url, downloadPath / "images") + if imagePath is not None: + description = screenshot.get("caption", {}).get(lang, "") or screenshot.get("caption", {}).get("en", "") + newScreenshots.append( + { + "fileName": "images/" + imagePath.name, + "fileStatus": "PendingUpload", + "description": description, + "imageType": "Screenshot", + } + ) + # use standard screenshots if there are no Windows-specific screenshots + if not newScreenshots: + for screenshot in appstreamData.get("Screenshots", []): + if not screenshot.get("default", False): + continue + url = screenshot.get("source-image", {}).get("url") + imagePath = downloadFile(url, downloadPath / "images") + if imagePath is not None: + description = screenshot.get("caption", {}).get(lang, "") or screenshot.get("caption", {}).get( + "en", "" + ) + # assume screenshot for mobile if image filename contains 'mobile' + imageType = "MobileScreenshot" if "mobile" in imagePath.name else "Screenshot" + newScreenshots.append( + { + "fileName": "images/" + imagePath.name, + "fileStatus": "PendingUpload", + "description": description, + "imageType": imageType, + } + ) + # Microsoft Store supports "up to 9 desktop screenshots [and up to 8 screenshots for the other device families]" + if len(newScreenshots) > 9: + logger.info( + f"Microsoft Store supports up to 9 desktop screenshots. Ignoring {len(newScreenshots) - 9} screenshots." + ) + newScreenshots = newScreenshots[:9] + if newScreenshots: + # replace old screenshots with new ones + baseListing["images"] = [ + image for image in baseListing["images"] if not image["imageType"].endswith("Screenshot") + ] + baseListing["images"].extend(newScreenshots) + + # update additional logos and images + imageTypes = ( + "StoreLogo9x16", + "StoreLogoSquare", + "Icon", + "PromotionalArt16x9", + ) + for imageType in imageTypes: + url = appstreamData.get("Custom", {}).get(f"KDE::windows_store::{imageType}") + if url is None: + continue + imagePath = downloadFile(url, downloadPath / "images") + if imagePath is not None: + # replace old image with new one + baseListing["images"] = [image for image in baseListing["images"] if image["imageType"] != imageType] + baseListing["images"].append( + { + "fileName": "images/" + imagePath.name, + "fileStatus": "PendingUpload", + "imageType": imageType, + } + ) + + # recommendedHardware, minimumHardware - AppStream does not provide these + + # title - title must be a reserved name; keep what's there + + # update shortDescription for listing (only used for games) + if "shortdescription" not in keep or not baseListing["shortDescription"]: + baseListing["shortDescription"] = appstreamData.get("Summary", {}).get(lang, "") + + # shortTitle, sortTitle, voiceTitle - AppStream does not provide these + + # update devStudio for listing + if "devstudio" not in keep or not baseListing["devStudio"]: + baseListing["devStudio"] = ( + appstreamData.get("DeveloperName", {}).get(lang, "") or defaultBaseListing["devStudio"] + ) + + logger.debug(f"Listing for {storeLang}: %s", json.dumps(baseListing)) + return baseListing + + +def updateSubmissionWithAppStreamData(submissionData, appstreamData, downloadPath, keep, title): + listings = submissionData["listings"] + defaultBaseListing = listings["en-us"]["baseListing"] + + if keep: + logger.debug("Keeping the following values of the existing listings: %s", ", ".join(keep)) + + # first update the (base) listing for en/en-us (the default listing) + updateBaseListingForLanguage( + "en", "en-us", defaultBaseListing, defaultBaseListing, appstreamData, downloadPath, keep + ) + + for lang in appstreamData["Name"]: + if lang == "en": + continue + storeLang = appstream_to_microsoft_language.get(lang, lang) + if storeLang not in microsoft_languages: + logger.debug(f"Skipping language {lang} that is not supported by the Microsoft Store") + continue + + listing = listings.get(storeLang) + if listing is None: + listing = createListing(title) + baseListing = listing["baseListing"] + updatedBaseListing = updateBaseListingForLanguage( + lang, storeLang, baseListing, defaultBaseListing, appstreamData, downloadPath, keep + ) + # we keep existing listings even if updateBaseListingForLanguage doesn't like them + if updatedBaseListing is not None: + listings[storeLang] = listing + + return submissionData + + +def uploadPackagesFiles(zipFilePath, fileUploadUrl): + logger.debug(f"Uploading {zipFilePath} to {fileUploadUrl}") + blobClient = BlobClient.from_blob_url(fileUploadUrl) + with open(zipFilePath, "rb") as data: + result = blobClient.upload_blob(data, blob_type="BlockBlob") + logger.debug("Upload result: %s", result) + + +def _submitApp(client, *, appstreamId, appxuploadFile, storeId, keep, dryRun, skipCommit, **kwargs): + if not os.path.isfile(appxuploadFile): + raise Error(f"File not found: {appxuploadFile}") + + if dryRun: + logger.info("Running in dry-run mode") + + # fetch AppStream metadata of the app + logger.info(f"Fetching AppStream metadata for {appstreamId}") + appstreamData = getAppStreamData(appstreamId) + if not storeId: + # get the Store ID of the app from the AppStream data + storeUrl = appstreamData.get("Custom", {}).get("KDE::windows_store") + if storeUrl is None: + raise Error("No KDE::windows_store entry found in AppStream data.") + storeId = os.path.basename(urlparse(storeUrl).path) + logger.debug(f"Using Store ID {storeId}") + + # get app data + logger.info("Retrieving information about the app from the Microsoft Store") + appData = client.getAppData(storeId) + + lastSubmissionId = appData.get("lastPublishedApplicationSubmission", {}).get("id") + if not lastSubmissionId: + raise Error("The first submission needs to be done manually in the Microsoft Partner Center.") + + # delete existing pending submission + pendingSubmissionId = appData.get("pendingApplicationSubmission", {}).get("id") + if pendingSubmissionId: # not None and not empty + logger.info("Deleting existing pending submission") + if not dryRun: + client.deleteSubmission(storeId, pendingSubmissionId) + + # create a new submission (as copy of the last submission) + logger.info("Creating new submission") + if not dryRun: + submissionData = client.createSubmission(storeId) + else: + submissionData = client.getSubmission(storeId, lastSubmissionId) + submissionData["id"] = int(submissionData["id"]) + 1 + submissionData["fileUploadUrl"] = "https://localhost" + submissionId = submissionData["id"] + logger.debug(f"submission ID: {submissionId}") + + # remove some entries from the submission data + fileUploadUrl = submissionData["fileUploadUrl"] + logger.debug(f"fileUploadUrl: {fileUploadUrl}") + del submissionData["fileUploadUrl"] # remove fileUploadUrl + # remove deprecated "pricing.sales" entry + if "pricing" in submissionData and "sales" in submissionData["pricing"]: + del submissionData["pricing"]["sales"] + + with TemporaryDirectory() as tmpdirname: + tempPath = Path(tmpdirname) + # set data for new submission + submissionData = updateSubmissionWithAppStreamData( + submissionData, appstreamData, tempPath, keep, title=appData["primaryName"] + ) + # add information about the app package (if it has not yet been uploaded) + appPackageName = os.path.basename(appxuploadFile) + if any( + p["fileName"] == appPackageName and p["fileStatus"] == "Uploaded" + for p in submissionData["applicationPackages"] + ): + # the app package has already been uploaded + logger.info(f"{appPackageName} has already been uploaded") + appPackageName = None + else: + logger.info(f"Adding {appPackageName} to list of application packages") + submissionData["applicationPackages"].append( + { + "fileName": appPackageName, # relative to root of uploaded ZIP file + "fileStatus": "PendingUpload", + } + ) + + # request manual publication + submissionData["targetPublishMode"] = "Manual" + + # update the submission + logger.info("Updating submission") + if not dryRun: + client.updateSubmission(storeId, submissionId, submissionData) + else: + print(f"Updated submission data:\n{json.dumps(submissionData, indent=4)}") + + # upload images and packages in a zip file + logger.info("Packaging files to upload") + zipFilePath = tempPath / "blob.zip" + # we use the default ZIP_STORED compression because the files should already be fairly compressed + with ZipFile(zipFilePath, "w") as zipFile: + if "images" not in keep: + for imagePath in (tempPath / "images").iterdir(): + logger.debug(f"Adding {imagePath} to {zipFilePath}") + zipFile.write(imagePath, arcname="images/" + imagePath.name) + if appPackageName: + logger.debug(f"Adding {appPackageName} to {zipFilePath}") + zipFile.write(appxuploadFile, arcname=appPackageName) + + logger.info("Uploading packaged files") + if not dryRun: + uploadPackagesFiles(zipFilePath, fileUploadUrl) + + # commit the submission + if not skipCommit: + logger.info("Committing submission") + if not dryRun: + client.commitSubmission(storeId, submissionId, waitUntilCommitIsCompleted=True) + else: + logger.info("Skipped committing the submission") + + +def submitApp(appxuploadFile, appstreamId, keep, tenantId, clientId, clientSecret): + client = MicrosoftStoreClient(tenantId, clientId, clientSecret) + try: + _submitApp( + client, + appxuploadFile=appxuploadFile, + appstreamId=appstreamId, + storeId=None, + keep=keep, + dryRun=False, + skipCommit=False, + ) + return + except AuthorizationError as e: + message = f"Authentication failed: {e}. Check server logs for details." + except APIError as e: + message = f"API request failed: {e}. Check server logs for details." + raise Error(message) diff --git a/third_party/ci-notary-service/sftpnotary/projects.py b/third_party/ci-notary-service/sftpnotary/projects.py new file mode 100644 index 0000000..81baa75 --- /dev/null +++ b/third_party/ci-notary-service/sftpnotary/projects.py @@ -0,0 +1,124 @@ +# SPDX-License-Identifier: BSD-2-Clause +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + +import logging +from pathlib import Path +from typing import Any, Dict, IO, List, Optional, Union + +import yaml + +log = logging.getLogger(__name__) + + +class Error(Exception): + pass + + +def readProjectSettings(yamlStream: Union[str, IO]) -> None: + global settings + settings = ProjectSettings(yamlStream) + + +class ProjectSettings: + # Possible boolean values (same as configparser) + BOOLEAN_STATES = { + "1": True, + "yes": True, + "true": True, + "on": True, + "0": False, + "no": False, + "false": False, + "off": False, + } + + def __init__(self, yamlStream: Union[str, IO]): + self._projects: Dict[str, Dict[str, Dict[str, str]]] = {} + self._readSettings(yamlStream) + + def _readSettings(self, yamlStream): + try: + # Set "nosec B506" to silence false positive warning "Use of unsafe yaml load. + # Allows instantiation of arbitrary objects. Consider yaml.safe_load()." + # We use yaml.load with BaseLoader which is even safer than SafeLoader. + d = yaml.load(yamlStream, yaml.BaseLoader) # nosec B506 + except Exception as e: + log.error("Error: Failed to read project settings.") + log.debug("Error details:", exc_info=e) + return + if d is None: + # PyYAML didn't find any documents in the stream + return + + defaultSettings = d.get("defaults", {}) + defaultBranches = [] + if "branches" in defaultSettings: + defaultBranches = defaultSettings["branches"] + del defaultSettings["branches"] + + projects = {} + for p in d: + if p == "defaults": + continue + projects[p] = _readProject(d[p] or {}, defaultBranches, defaultSettings) + + self._projects = projects + + def exists(self, projectPath: str, branch: Optional[str] = None) -> bool: + if branch is None: + return projectPath in self._projects + return branch in self._projects.get(projectPath, {}) + + def get(self, projectPath: str, branch: str, key: str, default: Any = None) -> Any: + p = self._projects.get(projectPath) + if p is None: + raise Error(f"Unknown project '{projectPath}'") + b = p.get(branch) + if b is None: + raise Error(f"Unknown branch '{branch}' of project '{projectPath}'") + return b.get(key, default) + + def getBool(self, projectPath: str, branch: str, key: str, default: bool) -> bool: + value = self.get(projectPath, branch, key, default) + if isinstance(value, str): + if value.lower() not in self.BOOLEAN_STATES: + raise ValueError("Not a boolean: %s" % value) + value = self.BOOLEAN_STATES[value.lower()] + return value + + def getPath( + self, projectPath: str, branch: str, key: str, default: Optional[Union[Path, str]] = None + ) -> Optional[Path]: + v = self.get(projectPath, branch, key, default) + if isinstance(v, str): + v = Path(v).expanduser() + return v + + +def _readProject(projectSettings: dict, defaultBranches: List[str], defaultSettings: dict): + project = {} + branches = projectSettings.get("branches") + if branches is not None: + del projectSettings["branches"] + + for b in branches: + # initialize with the default settings + branchSettings = defaultSettings.copy() + # update with the project settings + branchSettings.update(projectSettings.copy()) + # update with the branch-specific settings + branchSettings.update(branches[b] or {}) + project[b] = branchSettings + + # add the default branches + for b in defaultBranches: + if b not in project: + branchSettings = defaultSettings.copy() + branchSettings.update(projectSettings.copy()) + project[b] = branchSettings + + return project + + +settings = ProjectSettings("") diff --git a/third_party/ci-notary-service/sftpnotary/pypipublisher.py b/third_party/ci-notary-service/sftpnotary/pypipublisher.py new file mode 100644 index 0000000..d2fecb3 --- /dev/null +++ b/third_party/ci-notary-service/sftpnotary/pypipublisher.py @@ -0,0 +1,178 @@ +# SPDX-License-Identifier: BSD-2-Clause +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileCopyrightText: 2023 Ben Cooksley +# SPDX-FileCopyrightText: 2024 Julius Künzel +# SPDX-FileContributor: Ingo Klöcker + +import dataclasses +import logging +import os +import tarfile +from pathlib import Path +from tempfile import TemporaryDirectory +from typing import Optional + +from pkginfo import BDist, SDist, Wheel + +from sftpnotary import config, projects, util +from sftpnotary.core import Job, Request, Response, TaskProcessor, Worker +from sftpnotary.exceptions import Error, InvalidParameter +from sftpnotary.sftp import SFTPClient, SFTPError + +log = logging.getLogger(__name__) + + +@dataclasses.dataclass +class PublishPyPiRequest(Request): + archiveFileName: Optional[str] = None + repository: Optional[str] = None + + def validate(self): + util.validateFileName(self.archiveFileName, strict=True) + + # Ensure the repository name is valid + validRepoNames = [ + "pypi", + "testpypi", + ] + + if self.repository not in validRepoNames: + raise InvalidParameter(name="repository", value=self.repository) + + +PublishPyPiResponse = Response + + +class PublishPyPiJob(Job): + def __init__( + self, + sftp: SFTPClient, + archiveFilePath: Path, + token: Optional[str] = None, + projectPath: Optional[str] = None, + branch: Optional[str] = None, + repository: Optional[str] = None, + ): + super().__init__(sftp) + + self.archiveFilePath = archiveFilePath + self.request = PublishPyPiRequest( + archiveFileName=None, token=token, projectPath=projectPath, branch=branch, repository=repository + ) + self.resultPath = self.archiveFilePath.parent + + def start(self): + archiveFileName = self.archiveFilePath.name + self.sftp.upload(self.archiveFilePath, self.task.path() / archiveFileName) + self.request.archiveFileName = archiveFileName + self.task.putRequest(self.request) + self.taskQueue.commitTask(self.task) + + def waitForCompletion(self, logFileDestination: Path): + self.taskQueue.waitForCompletion(self.task) + log.debug(f"Fetching response of task '{self.task.id}' ...") + response = None + try: + response = self.task.fetchResponse(PublishPyPiResponse) + except SFTPError as e: + log.error("Error: %s", e) + if response is None: + log.error("Error: Got no response. Task failed.") + else: + self.success = True + self.downloadLogFiles(logFileDestination) + self.taskQueue.removeTask(self.task) + + +def getPythonPackageName(pkgpath): + if str(pkgpath).endswith(".tar.gz"): + dist = SDist + elif str(pkgpath).endswith(".whl"): + dist = Wheel + elif str(pkgpath).endswith(".egg"): + dist = BDist + else: + return None + pkg = dist(pkgpath) + + return pkg.name + + +class PublishPyPiProcessor(TaskProcessor): + requestClass = PublishPyPiRequest + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.configFile = config.settings.getPath("PyPiPublishing", "ConfigFilePath") + + if not self.configFile: + raise Error("No config file has not been set but it is mandatory") + + def getProjectSetting(self, name, required=True): + value = projects.settings.get(self.request.projectPath, self.request.branch, name) + if required and not value: + raise Error( + f"Project setting '{name}' not set for branch {self.request.branch} " + f"of project {self.request.projectPath}" + ) + return value + + def doProcess(self): + with TemporaryDirectory() as workPathName: + workPath = Path(workPathName) + + repository = self.request.repository + + localArchiveFilePath = workPath / self.request.archiveFileName + self.sftp.download(self.task.path() / self.request.archiveFileName, localArchiveFilePath) + + # Setup a path for us to unpack the archive into... + unpackedFilesPath = workPath / "unpacked-files" + os.makedirs(unpackedFilesPath) + + # Unpack the archive.... + archive = tarfile.open(name=localArchiveFilePath, mode="r") + # Set "nosec B202" because of https://github.com/PyCQA/bandit/issues/1038#issuecomment-1635863856 + archive.extractall(filter="tar", path=unpackedFilesPath) # nosec B202 + archive.close() + + self.verifyPackageNameDir(unpackedFilesPath) + + # Build up the command to run then run it + command = [ + "python3", + "-m", + "twine", + "upload", + "--non-interactive", + "--disable-progress-bar", + "--verbose", + "--config-file", + self.configFile, + "--repository", + repository, + str(unpackedFilesPath) + "/*", + ] + + util.runCommand(command, cwd=workPathName) + + def verifyPackageNameDir(self, dirPath): + for root, dirs, files in os.walk(dirPath): + for fileName in files: + self.verifyPackageNameFile(Path(root) / fileName) + + def verifyPackageNameFile(self, packageFilePath): + packageName = getPythonPackageName(packageFilePath) + allowedPackageNames = self.getProjectSetting("packagename") + if isinstance(allowedPackageNames, str): + allowedPackageNames = [allowedPackageNames] + if packageName not in allowedPackageNames: + raise Error( + f"The package name of {packageFilePath.name} ({packageName}) did not match any of " + f"the allowed package names ({', '.join(allowedPackageNames)})." + ) + + +class PublishPyPiWorker(Worker): + processorClass = PublishPyPiProcessor diff --git a/third_party/ci-notary-service/sftpnotary/sftp.py b/third_party/ci-notary-service/sftpnotary/sftp.py new file mode 100644 index 0000000..b8ddc86 --- /dev/null +++ b/third_party/ci-notary-service/sftpnotary/sftp.py @@ -0,0 +1,320 @@ +# SPDX-License-Identifier: BSD-2-Clause +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + +import io +import logging +import os +import stat +import time +from functools import wraps +from pathlib import Path, PurePath +from typing import Optional, Union + +from paramiko import RSAKey, SSHClient +from paramiko.client import AutoAddPolicy +from paramiko.common import o777 +from paramiko.ssh_exception import SSHException + +log = logging.getLogger(__name__) + + +class SFTPError(Exception): + pass + + +class ConnectionLostError(SFTPError): + pass + + +class ClosingContextManager: + def __enter__(self): + return self + + def __exit__(self, type, value, traceback): + self.close() + + +def ProgressLogger(message: str, interval: int = 1): + lastLog = time.time() + + def printProgress(current: int, total: int): + nonlocal lastLog + now = time.time() + if current == total or now > lastLog + interval: + lastLog = now + log.debug(message, current, total) + + return printProgress + + +def toSftpPath(path: Union[str, PurePath]): + if isinstance(path, PurePath): + return str(path.as_posix()) + return path + + +def detectLostConnection(f): + @wraps(f) + def wrapper(self, *args, **kwargs): + try: + return f(self, *args, **kwargs) + except OSError: + # probably a socket error; check if the connection was closed + if self.closed: + raise ConnectionLostError("Lost connection to SFTP server.") + else: + raise + + return wrapper + + +class SFTPClient(ClosingContextManager): + def __init__(self): + super().__init__() + + self._connectInfo = None + self._sshClient = None + self._sftpClient = None + self.basePath = None + + @property + def sftpClient(self): + if self._sftpClient is None: + self._sftpClient = self._sshClient.open_sftp() + if self.basePath is not None: + try: + path = toSftpPath(self.basePath) + self._sftpClient.chdir(path) + path = None + except FileNotFoundError: + log.debug(f"Folder '{path}' does not exist. Trying to create it ...") + if path is not None: + try: + self._sftpClient.mkdir(path) + self._sftpClient.chdir(path) + except OSError as e: + raise SFTPError( + f"Failed to create folder '{path}' on the SFTP server ({e!r}). Create it manually." + ) + return self._sftpClient + + def close(self): + if self._sftpClient is not None: + self._sftpClient.close() + self._sftpClient = None + if self._sshClient is not None: + self._sshClient.close() + self._sshClient = None + + @property + def closed(self): + return self._sftpClient is None or self._sftpClient.get_channel()._closed + + def connect( + self, + hostname: str, + basePath: Union[str, PurePath], + knownHostsFile: Optional[Union[str, Path]] = None, + rsaKeyFile: Optional[Union[str, Path]] = None, + **kwargs, + ): + self._connectInfo = { + "args": (hostname, basePath), + "kwargs": {**kwargs, "knownHostsFile": knownHostsFile, "rsaKeyFile": rsaKeyFile}, + } + + self.basePath = basePath + + connectArgs = dict(**kwargs) + if rsaKeyFile is not None: + if isinstance(rsaKeyFile, Path): + rsaKeyFile = str(rsaKeyFile) + # explicitly load the RSA key file because using SSHClient.connect with key_file fails + # (https://github.com/paramiko/paramiko/issues/1839) + if isinstance(rsaKeyFile, str) and rsaKeyFile.startswith("env:"): + envVarValue = os.environ[rsaKeyFile[4:]] + # guess whether it's a file path or an actual RSA key + if envVarValue.startswith("-----"): + # looks like a private (RSA) key + privateKey = io.StringIO(envVarValue) + connectArgs["pkey"] = RSAKey.from_private_key(privateKey) + else: + connectArgs["pkey"] = RSAKey.from_private_key_file(envVarValue) + else: + connectArgs["pkey"] = RSAKey.from_private_key_file(rsaKeyFile) + connectArgs["allow_agent"] = False # use agent only if we do not have a key + self._sshClient = SSHClient() + if isinstance(knownHostsFile, Path): + knownHostsFile = str(knownHostsFile) + self._sshClient.load_system_host_keys(knownHostsFile) + if knownHostsFile is None: + # Set "nosec B507" as this is intentional behaviour + self._sshClient.set_missing_host_key_policy(AutoAddPolicy()) # nosec B507 + self._sshClient.connect(hostname, **connectArgs) + self.sftpClient + + def reconnect(self, maxTries: int = -1, timeout: int = 30 * 60): + if self._connectInfo is None: + # connect() was never called + log.warning("Connect info is None. Ignoring reconnect request.") + return + + # ensure that the previous connection is closed properly + self.close() + + tries = 0 + endTime = time.time() + timeout + maxCoolingOffPeriod = 60 + coolingOffPeriod = 1.0 + while True: + tries += 1 + e: Optional[Exception] = None + try: + self.connect(*self._connectInfo["args"], **self._connectInfo["kwargs"]) + return + except SSHException as ex: + e = ex + except OSError as ex: + e = ex + if maxTries > 0 and tries >= maxTries: + raise SFTPError(f"Failed to reconnect to the SFTP server ({e!r}). Giving up after {maxTries} retries.") + now = time.time() + if now > endTime: + raise SFTPError(f"Failed to reconnect to the SFTP server ({e!r}). Giving up after {timeout} seconds.") + coolingOffPeriod = min(coolingOffPeriod, endTime - now) + log.debug(f"Failed to reconnect to the SFTP server ({e!r}). Retrying in {coolingOffPeriod} s ...") + time.sleep(coolingOffPeriod) + coolingOffPeriod = min(coolingOffPeriod * 2, maxCoolingOffPeriod) + + def download(self, remotePath: Union[str, PurePath], localPath: Union[str, Path]): + if isinstance(localPath, str): + localPath = Path(localPath) + log.info(f"Downloading file {remotePath!s} to {localPath!s} ...") + try: + self.sftpClient.get( + toSftpPath(remotePath), toSftpPath(localPath), ProgressLogger("Downloaded %s bytes of %s bytes") + ) + except Exception as e: + # remove a potentially existing partially downloaded file + localPath.unlink(missing_ok=True) + raise SFTPError(f"Failed to download file '{remotePath!s}' from the SFTP server ({e!r})") + + def downloadBytes(self, remotePath: Union[str, PurePath]): + log.info(f"Downloading file {remotePath!s} ...") + try: + with io.BytesIO() as dataStream: + self.sftpClient.getfo( + toSftpPath(remotePath), dataStream, callback=ProgressLogger("Downloaded %s bytes of %s bytes") + ) + return dataStream.getvalue() + except Exception as e: + raise SFTPError(f"Failed to download file '{remotePath!s}' from the SFTP server ({e!r})") + + def upload(self, localPath: Union[str, PurePath], remotePath: Union[str, PurePath]): + log.info(f"Uploading file {localPath!s} to {remotePath!s} ...") + + maxTries = 3 + tries = 0 + while True: + exception = None + try: + self.sftpClient.put( + toSftpPath(localPath), toSftpPath(remotePath), ProgressLogger("Uploaded %s bytes of %s bytes") + ) + return + except EOFError as e: + tries += 1 + exception = e + except Exception as e: + raise SFTPError(f"Failed to upload file '{localPath!s}' to the SFTP server ({e!r})") + + if tries < maxTries: + log.error("Error: Uploading file '%s' failed with %r. Retrying ...", localPath, exception) + self.reconnect() + try: + self.sftpClient.remove(toSftpPath(remotePath)) + except FileNotFoundError: + pass + else: + raise SFTPError(f"Failed to upload file '{localPath!s}' to the SFTP server ({exception!r})") + + def uploadBytes(self, data: bytes, remotePath: Union[str, PurePath]): + dataSize = len(data) + log.info(f"Uploading {dataSize} bytes to {remotePath!s} ...") + + maxTries = 3 + tries = 0 + while True: + dataStream = io.BytesIO(data) + exception = None + try: + self.sftpClient.putfo( + dataStream, + toSftpPath(remotePath), + file_size=dataSize, + callback=ProgressLogger("Uploaded %s bytes of %s bytes"), + ) + return + except EOFError as e: + tries += 1 + exception = e + except Exception as e: + raise SFTPError(f"Failed to upload data to the SFTP server ({e!r})") + + if tries < maxTries: + log.error(f"Error: Uploading data failed with {exception!r}. Retrying ...") + self.reconnect() + try: + self.sftpClient.remove(toSftpPath(remotePath)) + except FileNotFoundError: + pass + else: + raise SFTPError(f"Failed to upload data to the SFTP server ({exception!r})") + + @detectLostConnection + def listdir(self, path: Union[str, PurePath] = "."): + return self.sftpClient.listdir(toSftpPath(path)) + + @detectLostConnection + def listdir_attr(self, path: Union[str, PurePath] = "."): + return self.sftpClient.listdir_attr(toSftpPath(path)) + + @detectLostConnection + def listdir_iter(self, path: Union[str, PurePath] = ".", read_aheads=50): + return self.sftpClient.listdir_iter(toSftpPath(path), read_aheads=read_aheads) + + @detectLostConnection + def lstat(self, path: Union[str, PurePath]): + return self.sftpClient.lstat(toSftpPath(path)) + + @detectLostConnection + def mkdir(self, path: Union[str, PurePath], mode=o777): + return self.sftpClient.mkdir(toSftpPath(path), mode=mode) + + @detectLostConnection + def posix_rename(self, oldpath: Union[str, PurePath], newpath: Union[str, PurePath]): + return self.sftpClient.posix_rename(toSftpPath(oldpath), toSftpPath(newpath)) + + @detectLostConnection + def remove(self, path: Union[str, PurePath]): + return self.sftpClient.remove(toSftpPath(path)) + + @detectLostConnection + def rmdir(self, path: Union[str, PurePath]): + return self.sftpClient.rmdir(toSftpPath(path)) + + def recursiveRemoveDirectory(self, path: Union[str, PurePath]): + path = PurePath(path) + entriesAttributes = self.listdir_attr(path) + for entryAttributes in entriesAttributes: + entryPath = path / entryAttributes.filename + if stat.S_ISDIR(entryAttributes.st_mode): + self.recursiveRemoveDirectory(entryPath) + else: + self.remove(entryPath) + self.rmdir(path) + + @detectLostConnection + def stat(self, path: Union[str, PurePath]): + return self.sftpClient.stat(toSftpPath(path)) diff --git a/third_party/ci-notary-service/sftpnotary/util.py b/third_party/ci-notary-service/sftpnotary/util.py new file mode 100644 index 0000000..d914f8c --- /dev/null +++ b/third_party/ci-notary-service/sftpnotary/util.py @@ -0,0 +1,147 @@ +# SPDX-License-Identifier: BSD-2-Clause +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + +import logging +import os +import subprocess +import tarfile +from contextlib import contextmanager +from pathlib import Path +from typing import Iterator, List, Optional, Union + +import requests + +import sftpnotary.log +from sftpnotary import config, projects +from sftpnotary.exceptions import Error, InvalidFileName +from sftpnotary.sftp import SFTPClient + +log = logging.getLogger(__name__) + + +def setUpServiceLogging(serviceName: str, verbosity: int) -> None: + # if verbosity level is greater than 2 then decrease the root logger level + rootLoggerLevel = max(logging.DEBUG, logging.WARNING - 10 * max(0, verbosity - 2)) + logFilePath = config.settings.getPath("Logging", "LogFile") + logging.basicConfig( + format=sftpnotary.log.standardFormat, + level=rootLoggerLevel, + filename=str(logFilePath) if logFilePath is not None else None, + ) + + # default to WARNING level for the sftpnotary logger + logLevel = max(logging.DEBUG, logging.WARNING - 10 * verbosity) + logging.getLogger("sftpnotary").setLevel(logLevel) + sftpnotary.log.setNameForTaskLogs(serviceName) + + +def setUpClientLogging(clientLogger: logging.Logger, verbosity: int) -> None: + # if verbosity level is greater than 1 then decrease the root logger level + rootLoggerLevel = max(logging.DEBUG, logging.WARNING - 10 * max(0, verbosity - 1)) + logging.basicConfig(format="%(asctime)s %(levelname)s %(name)s %(message)s", level=rootLoggerLevel) + + # default to INFO level for the client logger and the sftpnotary logger + logLevel = max(logging.DEBUG, logging.INFO - 10 * verbosity) + clientLogger.setLevel(logLevel) + logging.getLogger("sftpnotary").setLevel(logLevel) + + +@contextmanager +def connectToSftpServer(): + with SFTPClient() as sftp: + sftp.connect( + config.settings.get("SFTP", "Server"), + config.settings.get("SFTP", "BasePath"), + port=config.settings.get("SFTP", "Port", 22), + username=config.settings.get("SFTP", "Username"), + knownHostsFile=config.settings.getPath("SFTP", "KnownHostsFile"), + rsaKeyFile=config.settings.getPath("SFTP", "RsaKeyFile"), + ) + yield sftp + + +def loadProjectSettings(path: Optional[Union[str, Path]], relativeTo: Optional[Path] = None): + if path is None: + return + if isinstance(path, str) and path.startswith(("https://", "http://")): + log.debug(f"Fetching project settings: {path}") + r = requests.get(path, timeout=5) + r.raise_for_status() + projects.readProjectSettings(r.text) + else: + projectSettingsPath = Path(path).expanduser() + if not projectSettingsPath.is_absolute() and relativeTo is not None: + projectSettingsPath = Path(relativeTo) / projectSettingsPath + with open(projectSettingsPath, "r") as f: + projects.readProjectSettings(f) + + +def runCommand(command, commandToLog=None, **kwargs) -> subprocess.CompletedProcess: + try: + log.info(f"Running {command if commandToLog is None else commandToLog} ...") + kwargs.update({"capture_output": True, "check": True, "text": True}) + result = subprocess.run(command, **kwargs) # nosec subprocess_without_shell_equals_true + log.info("The process exited successfully") + log.debug(f"stdout:\n{result.stdout}") + log.debug(f"stderr:\n{result.stderr}") + return result + except subprocess.CalledProcessError as e: + log.error(f"The process exited with {e.returncode}") + log.debug(f"stdout:\n{e.stdout}") + log.debug(f"stderr:\n{e.stderr}") + raise Error(f"Running {command[0]} failed") + + +def collectArgumentsUpToSize(arguments: List[str], maxSize: int) -> Iterator[List[str]]: + currentSize = 0 + firstFile = 0 + for i, argument in enumerate(arguments): + argumentSize = len(argument) + if argumentSize > maxSize: + raise Error(f"Size of argument {argument!r} exceeds available size {maxSize}.") + if currentSize + argumentSize <= maxSize: + currentSize += argumentSize + 1 + continue + yield arguments[firstFile:i] + firstFile = i + currentSize = argumentSize + 1 + + yield arguments[firstFile:] + + +def validateFileName(fileName: str, strict: bool = False) -> None: + """Verify that the file name does not contain Unix path separators to + prevent directory traversal problems on the SFTP server. + + If strict is True, then only printable ASCII characters are allowed and + the file name must not contain spaces.""" + if fileName is None: + raise InvalidFileName() + if not fileName or "/" in fileName: + raise InvalidFileName(fileName) + if strict and (" " in fileName or not fileName.isascii() or not fileName.isprintable()): + raise InvalidFileName(fileName) + + +def getFileSuffix(filePath: Path): + for ext in [".tar.gz"]: + if filePath.name.endswith(ext): + return ext + + return filePath.suffix + + +def removeFileSuffix(fileName: str): + suffixLen = len(getFileSuffix(Path(fileName))) + if suffixLen: + return fileName[:-suffixLen] + else: + return fileName + + +def extractTarArchive(archivePath: Path, targetPath: Path): + os.makedirs(targetPath, exist_ok=True) + with tarfile.open(name=archivePath, mode="r") as archive: + # Set "nosec B202" because of https://github.com/PyCQA/bandit/issues/1038#issuecomment-1635863856 + archive.extractall(filter="data", path=targetPath) # nosec B202 diff --git a/third_party/ci-notary-service/sftpnotary/websitepublisher.py b/third_party/ci-notary-service/sftpnotary/websitepublisher.py new file mode 100644 index 0000000..55f0488 --- /dev/null +++ b/third_party/ci-notary-service/sftpnotary/websitepublisher.py @@ -0,0 +1,133 @@ +# SPDX-License-Identifier: BSD-2-Clause +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileCopyrightText: 2023 Ben Cooksley +# SPDX-FileContributor: Ingo Klöcker + +import dataclasses +import logging +import os +import tarfile +from pathlib import Path +from tempfile import TemporaryDirectory +from typing import Optional + +from sftpnotary import projects, util +from sftpnotary.core import Job, Request, Response, TaskProcessor, Worker +from sftpnotary.exceptions import Error +from sftpnotary.sftp import SFTPClient, SFTPError + +log = logging.getLogger(__name__) + + +@dataclasses.dataclass +class PublishWebsiteRequest(Request): + websiteArchiveFileName: Optional[str] = None + + def validate(self): + util.validateFileName(self.websiteArchiveFileName, strict=True) + + +PublishWebsiteResponse = Response + + +class PublishWebsiteJob(Job): + def __init__( + self, + sftp: SFTPClient, + websiteArchiveFilePath: Path, + token: str, + projectPath: str, + branch: str, + ): + super().__init__(sftp) + + self.websiteArchiveFilePath = websiteArchiveFilePath + self.request = PublishWebsiteRequest( + websiteArchiveFileName=None, + token=token, + projectPath=projectPath, + branch=branch, + ) + self.resultPath = self.websiteArchiveFilePath.parent + + def start(self): + websiteArchiveFileName = self.websiteArchiveFilePath.name + self.sftp.upload(self.websiteArchiveFilePath, self.task.path() / websiteArchiveFileName) + self.request.websiteArchiveFileName = websiteArchiveFileName + self.task.putRequest(self.request) + self.taskQueue.commitTask(self.task) + + def waitForCompletion(self): + self.taskQueue.waitForCompletion(self.task) + log.debug(f"Fetching response of task '{self.task.id}' ...") + response = None + try: + response = self.task.fetchResponse(PublishWebsiteResponse) + except SFTPError as e: + log.error("Error: %s", e) + if response is None: + log.error("Error: Got no response. Task failed.") + else: + self.success = True + self.downloadLogFiles(self.resultPath) + self.taskQueue.removeTask(self.task) + + +class PublishWebsiteProcessor(TaskProcessor): + requestClass = PublishWebsiteRequest + + def getProjectSetting(self, name, required=True): + value = projects.settings.get(self.request.projectPath, self.request.branch, name) + if required and not value: + raise Error( + f"Project setting '{name}' not set for branch {self.request.branch} " + f"of project {self.request.projectPath}" + ) + return value + + def doProcess(self): + # Get the details for where we will publish the website to + rsyncDestination = self.getProjectSetting("rsyncDestination") + websiteDomain = self.getProjectSetting("domain") + + # Make sure the website domain we have been given is valid... + if not websiteDomain: + raise Error(f"Website domain has not been set for branch {self.request.branch} and is mandatory") + + with TemporaryDirectory() as workPathName: + workPath = Path(workPathName) + + localWebsiteArchiveFilePath = workPath / self.request.websiteArchiveFileName + self.sftp.download(self.task.path() / self.request.websiteArchiveFileName, localWebsiteArchiveFilePath) + + # Setup a path for us to unpack the website archive into... + unpackedWebsitePath = workPath / "unpacked-site" + os.makedirs(unpackedWebsitePath) + + # Unpack the website archive.... + archive = tarfile.open(name=localWebsiteArchiveFilePath, mode="r") + # Set "nosec B202" because of https://github.com/PyCQA/bandit/issues/1038#issuecomment-1635863856 + archive.extractall(filter="tar", path=unpackedWebsitePath) # nosec B202 + archive.close() + + # Determine the final rsync destination + # We allow for the website domain to be optionally added into this via use of %s + # This avoids having to repeat ourselves in the configuration file + finalRsyncDestination = rsyncDestination % websiteDomain + + # Build up the rsync command to run then run it + # The entire contents of + rsyncCommand = [ + "rsync", + "--archive", + "--checksum", + "--delete", + "--verbose", + str(unpackedWebsitePath) + "/", + finalRsyncDestination.rstrip("/") + "/", + ] + util.runCommand(rsyncCommand, cwd=workPathName) + + +class PublishWebsiteWorker(Worker): + processorClass = PublishWebsiteProcessor diff --git a/third_party/ci-notary-service/sftpnotary/windowsbinariessigner.py b/third_party/ci-notary-service/sftpnotary/windowsbinariessigner.py new file mode 100644 index 0000000..53e3456 --- /dev/null +++ b/third_party/ci-notary-service/sftpnotary/windowsbinariessigner.py @@ -0,0 +1,340 @@ +# SPDX-License-Identifier: BSD-2-Clause +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + +import logging +import os +import re +import shutil +from pathlib import Path +from tempfile import NamedTemporaryFile, TemporaryDirectory +from typing import Dict, List, Optional +from zipfile import ZipFile + +import sftpnotary.log +from sftpnotary import config, projects, util +from sftpnotary.core import Job, SignFileResponse, SingleFileRequest, TaskProcessor, Worker +from sftpnotary.exceptions import Error +from sftpnotary.sftp import SFTPClient, SFTPError + +log = logging.getLogger(__name__) + +SignWindowsBinariesRequest = SingleFileRequest +SignWindowsBinariesResponse = SignFileResponse + + +class SignWindowsBinariesJob(Job): + archiveName = "binaries.zip" + + def __init__( + self, + sftp: SFTPClient, + filePaths: List[Path], + logFolder: Path, + token: Optional[str] = None, + projectPath: Optional[str] = None, + branch: Optional[str] = None, + ): + super().__init__(sftp) + + self.filePaths = filePaths + self.workingDirectory: Optional[TemporaryDirectory] = None + if len(self.filePaths) == 1: + self.request = SignWindowsBinariesRequest( + fileName=self.filePaths[0].name, token=token, projectPath=projectPath, branch=branch + ) + else: + self.request = SignWindowsBinariesRequest( + fileName=self.archiveName, token=token, projectPath=projectPath, branch=branch + ) + self.logFolder = logFolder + self.originalFilePaths: Dict[str, Path] = {} + + def start(self): + if len(self.filePaths) == 1: + self.localFilePath = self.filePaths[0] + else: + self.workingDirectory = TemporaryDirectory() + self.localFilePath = Path(self.workingDirectory.name) / self.archiveName + self.packageBinaries(self.localFilePath) + + self.sftp.upload(self.localFilePath, self.task.path() / self.request.fileName) + self.task.putRequest(self.request) + self.taskQueue.commitTask(self.task) + + def packageBinaries(self, archivePath): + # put all files to sign into a zip archive; to avoid problems with paths + # and weird file names we use consecutive numbers with the original extension + # as names in the archive + with ZipFile(archivePath, "w") as zipFile: + for number, binaryPath in enumerate(self.filePaths, start=1): + arcName = str(number) + binaryPath.suffix + self.originalFilePaths[arcName] = binaryPath + log.debug(f"Adding {binaryPath} as {arcName} to {archivePath.name}") + zipFile.write(binaryPath, arcname=arcName) + + def extractSignedBinaries(self, archivePath): + log.debug(f"Extracting signed binaries from {archivePath.name}") + # ZipFile cannot extract a file with another filename than the one listed + # in the archive; therefore, we extract all expected files to our working + # directory (which only contains the archive) and then we "move" the + # extracted signed binaries to their original locations + extractPath = Path(self.workingDirectory.name) + with ZipFile(archivePath, "r") as zipFile: + filesToExtract = [arcName for arcName in zipFile.namelist() if arcName in self.originalFilePaths] + zipFile.extractall(path=extractPath, members=filesToExtract) + for arcName in filesToExtract: + originalFilePath = self.originalFilePaths[arcName] + log.debug(f"Moving {arcName} to {originalFilePath}") + # use shutil.copyfile() + os.unlink() because there's no sane way to do a 'mv' + # that overwrites existing files and that works across filesystem boundaries + shutil.copyfile(extractPath / arcName, originalFilePath) + os.unlink(extractPath / arcName) + + def waitForCompletion(self): + self.taskQueue.waitForCompletion(self.task) + log.debug(f"Fetching response of task '{self.task.id}' ...") + response = None + try: + response = self.task.fetchResponse(SignWindowsBinariesResponse) + except SFTPError as e: + log.error("Error: %s", e) + if response is None: + log.error("Error: Got no response. Task failed.") + elif not response.signedFileName: + log.error("Error: No signed file to download.") + elif "/" in response.signedFileName: + log.error(f"Error: Suspicious file name of signed file: {response.signedFileName!r}.") + else: + try: + remotePath = self.task.path() / response.signedFileName + localPath = self.localFilePath # overwrite original (unsigned) file + self.sftp.download(remotePath, localPath) + + if len(self.filePaths) > 1: + self.extractSignedBinaries(self.localFilePath) + + self.success = True + except SFTPError as e: + log.error("Error: %s", e) + if self.workingDirectory is not None: + self.workingDirectory.cleanup() + self.downloadLogFiles(self.logFolder) + self.taskQueue.removeTask(self.task) + + +# expected file names are a number optionally followed by a suffix; +# in particular, they have no path components +_expectedFileNamesRegExp = re.compile(r"\d+(?:\.\w*)", re.ASCII) + + +def filterBinaries(fileNames: List[str]) -> List[str]: + return [fileName for fileName in fileNames if _expectedFileNamesRegExp.fullmatch(fileName)] + + +def extractUnsignedBinaries(archivePath, extractPath): + with ZipFile(archivePath, "r") as zipFile: + filesToExtract = filterBinaries(zipFile.namelist()) + zipFile.extractall(path=extractPath, members=filesToExtract) + log.debug(f"Extracted files {filesToExtract} from {archivePath.name} to {extractPath}") + return filesToExtract + + +def packageSignedBinaries(archivePath, filePaths): + with ZipFile(archivePath, "w") as zipFile: + for signedFilePath in filePaths: + arcName = signedFilePath.name + log.debug(f"Adding {signedFilePath.name} to {archivePath.name}") + zipFile.write(signedFilePath, arcname=arcName) + + +class SignWindowsBinariesProcessor(TaskProcessor): + requestClass = SignWindowsBinariesRequest + + def doProcess(self): + # 1. download the binary/installer or the archive with the binaries to sign + # 2. extract the binaries to sign (if necessary) + # 3. sign the binaries + # 4. package the signed binaries (if necessary) + # 5. upload the signed binary/installer or the archive with the signed binaries + remoteUnsignedFilePath = self.task.path() / self.request.fileName + signSingleFile = remoteUnsignedFilePath.suffix != ".zip" + with TemporaryDirectory(dir=config.settings.get("General", "TempDirectory")) as workPathName: + workPath = Path(workPathName) + + if signSingleFile: + # use simple file names locally to avoid issues with user provided file names + localFilePath = workPath / ("file" + remoteUnsignedFilePath.suffix) + self.sftp.download(remoteUnsignedFilePath, localFilePath) + + if localFilePath.suffix == ".appx": + self.verifyApplicationId(localFilePath) + + self.signFiles([localFilePath.name], path=localFilePath.parent) + + localSignedFilePath = localFilePath + # we assume a single suffix + remoteSignedFileName = f"{remoteUnsignedFilePath.stem}-signed{remoteUnsignedFilePath.suffix}" + else: + # use simple file names locally to avoid issues with user provided file names + localUnsignedFilePath = workPath / "unsigned.zip" + self.sftp.download(remoteUnsignedFilePath, localUnsignedFilePath) + + extractPath = workPath / "files" + os.mkdir(extractPath) + fileNames = extractUnsignedBinaries(localUnsignedFilePath, extractPath) + + self.signFiles(fileNames, path=extractPath) + + filePaths = [extractPath / extractedFile for extractedFile in fileNames] + localSignedFilePath = workPath / "signed.zip" + packageSignedBinaries(localSignedFilePath, filePaths) + + remoteSignedFileName = localSignedFilePath.name + + try: + self.sftp.upload(localSignedFilePath, self.task.path() / remoteSignedFileName) + return SignWindowsBinariesResponse(signedFileName=remoteSignedFileName) + except Error as e: + log.error("Error: %s", e) + except SFTPError as e: + log.error("Error: %s", e) + + def verifyApplicationId(self, appxFilePath): + allowedApplicationId = projects.settings.get(self.request.projectPath, self.request.branch, "applicationid") + applicationId = self.getApplicationId(appxFilePath) + if applicationId != allowedApplicationId: + raise Error( + f"The application ID of the APPX ({applicationId}) does not match the allowed application ID " + f"({allowedApplicationId})." + ) + + def getApplicationId(self, appxFilePath) -> str: + with ZipFile(appxFilePath) as appx: + with appx.open("AppxManifest.xml") as manifest: + # XML processing is dangerous; therefore, simply parse the XML as text + # https://docs.python.org/3/library/xml.html#xml-vulnerabilities + for line in manifest.readlines(): + # look for a line like + +import logging +import os +import sys +from pathlib import Path +from typing import Optional + +from sftpnotary import config, projects, util +from sftpnotary.aabsigner import SignAabJob +from sftpnotary.exceptions import Error + +log = logging.getLogger("signaab") + + +def parseCommandLine(): + import argparse + + parser = argparse.ArgumentParser(description="Sign Android app bundle with signing service") + + # debug options + parser.add_argument("-v", "--verbose", action="count", default=0, help="increase the verbosity") + + parser.add_argument("--config") + + parser.add_argument("aab", help="the .aab file to sign") + + options = parser.parse_args() + return options + + +def logTaskLog(logFile: Path): + log.info("Logs of remote signing:") + with open(logFile, "r", encoding="utf-8") as f: + for line in f: + log.info(line.rstrip()) + + +def signAab(aab: Path, projectPath: Optional[str], branch: Optional[str]) -> bool: + with util.connectToSftpServer() as sftp: + job = SignAabJob( + sftp, + aabFilePath=aab, + token=os.environ.get("CI_JOB_TOKEN"), + projectPath=projectPath, + branch=branch, + ) + try: + job.start() + job.waitForCompletion() + except Exception as e: # or more specific exception + log.error("Error: SignAabJob failed", exc_info=e) + for logFile in job.logFiles: + if logFile.name == "task.log": + logTaskLog(logFile) + if not job.success: + log.error("Error: Signing AAB failed") + return job.success + + +def main() -> int: + options = parseCommandLine() + config.loadConfig(options.config) + util.setUpClientLogging(log, options.verbose) + projectSettingsLocation = config.settings.get("General", "ProjectSettings", "aabsigner-projects.yaml") + util.loadProjectSettings( + projectSettingsLocation, + relativeTo=Path(options.config).absolute().parent, + ) + + # Ignore merge request pipelines + if os.environ.get("CI_PIPELINE_SOURCE") == "merge_request_event": + log.info("Merge request pipelines are not cleared for signing. Skipping.") + return 0 + + # Check if it makes sense to attempt signing the AAB + projectPath = os.environ["CI_PROJECT_PATH"] + branch = os.environ["CI_COMMIT_REF_NAME"] + if not projects.settings.exists(projectPath, branch): + log.info( + f"""Branch '{branch}' of project '{projectPath}' is not cleared for signing. Skipping.\n +You can clear it by adding the branch to {projectSettingsLocation}""" + ) + return 0 + + success = signAab(Path(options.aab), projectPath, branch) + + return 0 if success else 1 + + +if __name__ == "__main__": + try: + sys.exit(main()) + except Error as e: + print("Error: %s" % e, file=sys.stderr) + sys.exit(1) diff --git a/third_party/ci-notary-service/signapk.py b/third_party/ci-notary-service/signapk.py new file mode 100644 index 0000000..bd870d2 --- /dev/null +++ b/third_party/ci-notary-service/signapk.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: BSD-2-Clause +# +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + +import logging +import os +import sys +from pathlib import Path +from typing import Optional + +from sftpnotary import config, projects, util +from sftpnotary.apksigner import SignApkJob +from sftpnotary.exceptions import Error + +log = logging.getLogger("signapk") + + +def parseCommandLine(): + import argparse + + parser = argparse.ArgumentParser(description="Sign APK with signing service") + + # debug options + parser.add_argument("-v", "--verbose", action="count", default=0, help="increase the verbosity") + + parser.add_argument("--config") + + parser.add_argument("apk", help="the .apk file to sign") + + options = parser.parse_args() + return options + + +def logTaskLog(logFile: Path): + log.info("Logs of remote signing:") + with open(logFile, "r", encoding="utf-8") as f: + for line in f: + log.info(line.rstrip()) + + +def signApk(apk: Path, projectPath: Optional[str], branch: Optional[str]) -> bool: + with util.connectToSftpServer() as sftp: + job = SignApkJob( + sftp, + apkFilePath=apk, + token=os.environ.get("CI_JOB_TOKEN"), + projectPath=projectPath, + branch=branch, + ) + try: + job.start() + job.waitForCompletion() + except Exception as e: # or more specific exception + log.error("Error: SignApkJob failed", exc_info=e) + for logFile in job.logFiles: + if logFile.name == "task.log": + logTaskLog(logFile) + if not job.success: + log.error("Error: Signing APK failed") + return job.success + + +def main() -> int: + options = parseCommandLine() + config.loadConfig(options.config) + util.setUpClientLogging(log, options.verbose) + projectSettingsLocation = config.settings.get("General", "ProjectSettings", "apksigner-projects.yaml") + util.loadProjectSettings( + projectSettingsLocation, + relativeTo=Path(options.config).absolute().parent, + ) + + # Ignore merge request pipelines + if os.environ.get("CI_PIPELINE_SOURCE") == "merge_request_event": + log.info("Merge request pipelines are not cleared for signing. Skipping.") + return 0 + + # Check if it makes sense to attempt signing the APK + projectPath = os.environ["CI_PROJECT_PATH"] + branch = os.environ["CI_COMMIT_REF_NAME"] + if not projects.settings.exists(projectPath, branch): + log.info( + f"""Branch '{branch}' of project '{projectPath}' is not cleared for signing. Skipping.\n +You can clear it by adding the branch to {projectSettingsLocation}""" + ) + return 0 + + success = signApk(Path(options.apk), projectPath, branch) + + return 0 if success else 1 + + +if __name__ == "__main__": + try: + sys.exit(main()) + except Error as e: + print("Error: %s" % e, file=sys.stderr) + sys.exit(1) diff --git a/third_party/ci-notary-service/signflatpak.py b/third_party/ci-notary-service/signflatpak.py new file mode 100644 index 0000000..3da9caf --- /dev/null +++ b/third_party/ci-notary-service/signflatpak.py @@ -0,0 +1,116 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: BSD-2-Clause +# +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + +import logging +import os +import sys +from pathlib import Path +from typing import Optional + +from sftpnotary import config, projects, util +from sftpnotary.exceptions import Error +from sftpnotary.flatpaksigner import getRefFromFlatpakBundle, SignFlatpakJob + +log = logging.getLogger("signflatpak") + + +def parseCommandLine(): + import argparse + + parser = argparse.ArgumentParser(description="Sign Flatpak bundle with signing service and publish it in a repo") + + # debug options + parser.add_argument("-v", "--verbose", action="count", default=0, help="increase the verbosity") + + parser.add_argument("--config", required=True) + + parser.add_argument( + "--debug-bundle", type=Path, dest="debugBundle", help="the .flatpak bundle with the debug symbols" + ) + parser.add_argument( + "--locale-bundle", type=Path, dest="localeBundle", help="the .flatpak bundle with the translations" + ) + + parser.add_argument("flatpak", type=Path, help="the .flatpak bundle to sign") + + options = parser.parse_args() + return options + + +def logTaskLog(logFile: Path): + log.info("Logs of remote signing:") + with open(logFile, "r", encoding="utf-8") as f: + for line in f: + log.info(line.rstrip()) + + +def signFlatpak( + flatpak: Path, localeBundle: Optional[Path], debugBundle: Optional[Path], projectPath: str, branch: str +) -> bool: + log.debug(f"Flatpak ref of {flatpak}: {getRefFromFlatpakBundle(flatpak)}") + if localeBundle: + log.debug(f"Flatpak ref of {localeBundle}: {getRefFromFlatpakBundle(localeBundle)}") + if debugBundle: + log.debug(f"Flatpak ref of {debugBundle}: {getRefFromFlatpakBundle(debugBundle)}") + with util.connectToSftpServer() as sftp: + job = SignFlatpakJob( + sftp, + flatpakFilePath=flatpak, + localeBundlePath=localeBundle, + debugBundlePath=debugBundle, + token=os.environ.get("CI_JOB_TOKEN"), + projectPath=projectPath, + branch=branch, + ) + try: + job.start() + job.waitForCompletion() + except Exception as e: # or more specific exception + log.error("Error: SignFlatpakJob failed", exc_info=e) + for logFile in job.logFiles: + if logFile.name == "task.log": + logTaskLog(logFile) + if not job.success: + log.error("Error: Signing Flatpak bundle failed") + return job.success + + +def main() -> int: + options = parseCommandLine() + config.loadConfig(options.config) + util.setUpClientLogging(log, options.verbose) + projectSettingsLocation = config.settings.get("General", "ProjectSettings", "flatpaksigner-projects.yaml") + util.loadProjectSettings( + projectSettingsLocation, + relativeTo=Path(options.config).absolute().parent, + ) + + # Ignore merge request pipelines + if os.environ.get("CI_PIPELINE_SOURCE") == "merge_request_event": + log.info("Merge request pipelines are not cleared for signing. Skipping.") + return 0 + + # Check if it makes sense to attempt signing the flatpak + projectPath = os.environ["CI_PROJECT_PATH"] + branch = os.environ["CI_COMMIT_REF_NAME"] + if not projects.settings.exists(projectPath, branch): + log.info( + f"""Branch '{branch}' of project '{projectPath}' is not cleared for signing flatpaks. Skipping.\n +You can clear it by adding the branch to {projectSettingsLocation}""" + ) + return 0 + + success = signFlatpak(options.flatpak, options.localeBundle, options.debugBundle, projectPath, branch) + + return 0 if success else 1 + + +if __name__ == "__main__": + try: + sys.exit(main()) + except Error as e: + print("Error: %s" % e, file=sys.stderr) + sys.exit(1) diff --git a/third_party/ci-notary-service/signmacapp.py b/third_party/ci-notary-service/signmacapp.py new file mode 100644 index 0000000..45cd329 --- /dev/null +++ b/third_party/ci-notary-service/signmacapp.py @@ -0,0 +1,142 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: BSD-2-Clause +# +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker +# SPDX-FileCopyrightText: 2023 Julius Künzel + +import logging +import os +import sys +import tarfile +from pathlib import Path +from tempfile import TemporaryDirectory +from typing import Optional + +from sftpnotary import config, projects, util +from sftpnotary.exceptions import Error +from sftpnotary.macappsigner import SignMacAppJob + +log = logging.getLogger("signmacapp") + + +def parseCommandLine(): + import argparse + + parser = argparse.ArgumentParser(description="Sign macOS apps with signing service") + + # debug options + parser.add_argument("-v", "--verbose", action="count", default=0, help="increase the verbosity") + + parser.add_argument("--config") + + parser.add_argument("appfile", help="the .dmg file or .app (inside tar archive) to sign") + + options = parser.parse_args() + return options + + +def logTaskLog(logFile: Path): + log.info("Logs of remote signing:") + with open(logFile, "r", encoding="utf-8") as f: + for line in f: + log.info(line.rstrip()) + + +def signMacApp(app: Path, logFolder: Path, projectPath: Optional[str], branch: Optional[str]) -> bool: + # Look for project-specific entitlements file using CI_PROJECT_NAME + # For .app signing, logFolder is the original .app parent directory where entitlements were copied + entitlementsFile = None + projectName = os.environ.get("CI_PROJECT_NAME") + if projectName: + entitlementsPath = logFolder / f"{projectName}.entitlements" + if entitlementsPath.exists(): + entitlementsFile = entitlementsPath + log.info(f"Found entitlements file: {entitlementsFile.name} at {logFolder}") + else: + log.info(f"No entitlements file found at {entitlementsPath}") + else: + log.warning("CI_PROJECT_NAME not set, cannot look for entitlements file") + + with util.connectToSftpServer() as sftp: + job = SignMacAppJob( + sftp, + macAppFilePath=app, + entitlementsFilePath=entitlementsFile, + logFolder=logFolder, + token=os.environ.get("CI_JOB_TOKEN"), + projectPath=projectPath, + branch=branch, + ) + try: + job.start() + job.waitForCompletion() + except Exception as e: # or more specific exception + log.error("Error: SignMacAppJob failed", exc_info=e) + for logFile in job.logFiles: + if logFile.name == "task.log": + logTaskLog(logFile) + if not job.success: + log.error("Error: Signing macOS app failed") + return job.success + + +def main() -> int: + options = parseCommandLine() + config.loadConfig(options.config) + util.setUpClientLogging(log, options.verbose) + projectSettingsLocation = config.settings.get("General", "ProjectSettings", "macappsigner-projects.yaml") + util.loadProjectSettings( + projectSettingsLocation, + relativeTo=Path(options.config).absolute().parent, + ) + + # Ignore merge request pipelines + if os.environ.get("CI_PIPELINE_SOURCE") == "merge_request_event": + log.info("Merge request pipelines are not cleared for signing. Skipping.") + return 0 + + # Check if it makes sense to attempt signing the macOS file + projectPath = os.environ["CI_PROJECT_PATH"] + branch = os.environ["CI_COMMIT_REF_NAME"] + if not projects.settings.exists(projectPath, branch): + log.info( + f"""Branch '{branch}' of project '{projectPath}' is not cleared for signing. Skipping.\n +You can clear it by adding the branch to {projectSettingsLocation}""" + ) + return 0 + + appFilePath = Path(options.appfile) + + if appFilePath.suffix == ".app": + # Build a tarball since .app files are basically special folders + with TemporaryDirectory() as tempArchiveDir: + appArchivePath = Path(tempArchiveDir) / "shuttleArchive" + with tarfile.open(name=appArchivePath, mode="w") as archive: + archive.add(appFilePath, arcname=appFilePath.name, recursive=True) + + success = signMacApp(appArchivePath, appFilePath.parent, projectPath, branch) + + if success: + # signMacApp overwrites the archive with the unsigned content + # so we can just extract the archive at the same location again + util.extractTarArchive(appArchivePath, appFilePath.parent) + + else: + success = signMacApp(appFilePath, appFilePath.parent, projectPath, branch) + + if not success: + return 1 + + util.runCommand(["codesign", "--display", "--verbose", appFilePath], cwd=appFilePath.parent) + util.runCommand(["codesign", "--verify", "--strict", "--deep", appFilePath], cwd=appFilePath.parent) + + return 0 + + +if __name__ == "__main__": + try: + sys.exit(main()) + except Error as e: + print("Error: %s" % e, file=sys.stderr) + sys.exit(1) diff --git a/third_party/ci-notary-service/signwindowsbinaries.py b/third_party/ci-notary-service/signwindowsbinaries.py new file mode 100644 index 0000000..3cd1f99 --- /dev/null +++ b/third_party/ci-notary-service/signwindowsbinaries.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: BSD-2-Clause +# +# SPDX-FileCopyrightText: 2024 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + +import logging +import os +import sys +from pathlib import Path +from typing import List + +from sftpnotary import config, projects, util +from sftpnotary.exceptions import Error +from sftpnotary.windowsbinariessigner import SignWindowsBinariesJob + +log = logging.getLogger("signwindowsbinaries") + + +def parseCommandLine(): + import argparse + + parser = argparse.ArgumentParser(description="Sign Windows binaries with signing service") + + # debug options + parser.add_argument("-v", "--verbose", action="count", default=0, help="increase the verbosity") + + parser.add_argument("--config", required=True, help="the configuration to use; required") + + parser.add_argument( + "--log-folder", + dest="logFolder", + default=Path.cwd(), + type=Path, + help="the location where the log files should be saved; defaults to the current folder", + ) + + parser.add_argument( + "--files-from", dest="filesFrom", metavar="FILE", help="read list of binaries to sign from FILE" + ) + + parser.add_argument("files", nargs="*", metavar="FILE", help="the binaries to sign") + + options = parser.parse_args() + + if options.filesFrom is None and not options.files: + raise Error("No binaries to sign given.") + + if options.filesFrom is not None and options.files: + raise Error("Binaries to sign cannot be given on command line and via --files-from.") + + return options + + +def logTaskLog(logFile: Path): + log.info("Logs of remote signing:") + with open(logFile, "r", encoding="utf-8") as f: + for line in f: + log.info(line.rstrip()) + + +def signWindowsBinaries(binaries: List[Path], logFolder: Path, projectPath: str, branch: str) -> bool: + with util.connectToSftpServer() as sftp: + job = SignWindowsBinariesJob( + sftp, + filePaths=binaries, + logFolder=logFolder, + token=os.environ.get("CI_JOB_TOKEN"), + projectPath=projectPath, + branch=branch, + ) + try: + job.start() + job.waitForCompletion() + except Exception as e: # or more specific exception + log.error("Error: SignWindowsBinariesJob failed", exc_info=e) + for logFile in job.logFiles: + if logFile.name == "task.log": + logTaskLog(logFile) + if not job.success: + log.error("Error: Signing Windows binaries failed") + return job.success + + +def main() -> int: + options = parseCommandLine() + config.loadConfig(options.config) + util.setUpClientLogging(log, options.verbose) + projectSettingsLocation = config.settings.get("General", "ProjectSettings", "windowsbinariessigner-projects.yaml") + util.loadProjectSettings( + projectSettingsLocation, + relativeTo=Path(options.config).absolute().parent, + ) + + # Ignore merge request pipelines + if os.environ.get("CI_PIPELINE_SOURCE") == "merge_request_event": + log.info("Merge request pipelines are not cleared for signing. Skipping.") + return 0 + + # Check if it makes sense to attempt signing the files + projectPath = os.environ["CI_PROJECT_PATH"] + branch = os.environ["CI_COMMIT_REF_NAME"] + if not projects.settings.exists(projectPath, branch): + log.info( + f"""Branch '{branch}' of project '{projectPath}' is not cleared for signing. Skipping.\n +You can clear it by adding the branch to {projectSettingsLocation}""" + ) + return 0 + + if options.files: + binaries = [Path(s) for s in options.files] + else: + with open(options.filesFrom, encoding="utf-8") as f: + filenames = [line.strip() for line in f] + binaries = [Path(s) for s in filenames if s] + + success = signWindowsBinaries(binaries, options.logFolder.absolute(), projectPath, branch) + + return 0 if success else 1 + + +if __name__ == "__main__": + try: + sys.exit(main()) + except Error as e: + print("Error: %s" % e, file=sys.stderr) + sys.exit(1) diff --git a/third_party/ci-notary-service/tests/__init__.py b/third_party/ci-notary-service/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/third_party/ci-notary-service/tests/test_apkutils.py b/third_party/ci-notary-service/tests/test_apkutils.py new file mode 100644 index 0000000..e8d15c1 --- /dev/null +++ b/third_party/ci-notary-service/tests/test_apkutils.py @@ -0,0 +1,114 @@ +# SPDX-License-Identifier: BSD-2-Clause +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + +import pytest + +from sftpnotary import apkutils + + +class TestApkutils: + def test_filterFastlaneFileNames(self): + assert apkutils.filterFastlaneFileNames(["org.example.foo.yml"], "org.example.foo") == ["org.example.foo.yml"] + + # allowed images (only featureGraphic.png and icon.png) + assert apkutils.filterFastlaneFileNames( + ["org.example.foo/en-US/images/featureGraphic.png"], "org.example.foo" + ) == ["org.example.foo/en-US/images/featureGraphic.png"] + assert apkutils.filterFastlaneFileNames(["org.example.foo/en-US/images/icon.png"], "org.example.foo") == [ + "org.example.foo/en-US/images/icon.png" + ] + + # allowed phoneScreenshots (any *.png files) + assert apkutils.filterFastlaneFileNames( + ["org.example.foo/en-US/images/phoneScreenshots/foo.png"], "org.example.foo" + ) == ["org.example.foo/en-US/images/phoneScreenshots/foo.png"] + + # allowed text files (only full_description.txt, short_description.txt, and title.txt) + assert apkutils.filterFastlaneFileNames(["org.example.foo/en-US/full_description.txt"], "org.example.foo") == [ + "org.example.foo/en-US/full_description.txt" + ] + assert apkutils.filterFastlaneFileNames(["org.example.foo/en-US/short_description.txt"], "org.example.foo") == [ + "org.example.foo/en-US/short_description.txt" + ] + assert apkutils.filterFastlaneFileNames(["org.example.foo/en-US/title.txt"], "org.example.foo") == [ + "org.example.foo/en-US/title.txt" + ] + + # names with two letter language code (without country code) + assert apkutils.filterFastlaneFileNames(["org.example.foo/uk/images/icon.png"], "org.example.foo") == [ + "org.example.foo/uk/images/icon.png" + ] + assert apkutils.filterFastlaneFileNames( + ["org.example.foo/uk/images/phoneScreenshots/foo.png"], "org.example.foo" + ) == ["org.example.foo/uk/images/phoneScreenshots/foo.png"] + assert apkutils.filterFastlaneFileNames(["org.example.foo/uk/full_description.txt"], "org.example.foo") == [ + "org.example.foo/uk/full_description.txt" + ] + + def test_filterFastlaneFileNames_unexpected_names(self): + # the full file paths must match + assert apkutils.filterFastlaneFileNames(["org.example.foo.ymlx"], "org.example.foo") == [] + assert apkutils.filterFastlaneFileNames(["xorg.example.foo.yml"], "org.example.foo") == [] + assert apkutils.filterFastlaneFileNames(["org.example.foo/en-US/images/icon.pngx"], "org.example.foo") == [] + assert apkutils.filterFastlaneFileNames(["xorg.example.foo/en-US/images/icon.png"], "org.example.foo") == [] + assert ( + apkutils.filterFastlaneFileNames( + ["org.example.foo/en-US/images/phoneScreenshots/foo.pngx"], "org.example.foo" + ) + == [] + ) + assert ( + apkutils.filterFastlaneFileNames( + ["xorg.example.foo/en-US/images/phoneScreenshots/foo.png"], "org.example.foo" + ) + == [] + ) + assert apkutils.filterFastlaneFileNames(["org.example.foo/en-US/foo.txtx"], "org.example.foo") == [] + assert apkutils.filterFastlaneFileNames(["xorg.example.foo/en-US/foo.txt"], "org.example.foo") == [] + + # folder must match application ID + assert apkutils.filterFastlaneFileNames(["org.example.bar/en-US/images/icon.png"], "org.example.foo") == [] + assert ( + apkutils.filterFastlaneFileNames( + ["org.example.bar/en-US/images/phoneScreenshots/foo.png"], "org.example.foo" + ) + == [] + ) + assert apkutils.filterFastlaneFileNames(["org.example.bar/en-US/foo.txt"], "org.example.foo") == [] + + # invalid language/country codes + assert apkutils.filterFastlaneFileNames(["org.example.foo/en_US/images/icon.png"], "org.example.foo") == [] + assert ( + apkutils.filterFastlaneFileNames( + ["org.example.foo/en_US/images/phoneScreenshots/foo.png"], "org.example.foo" + ) + == [] + ) + assert apkutils.filterFastlaneFileNames(["org.example.foo/en_US/foo.txt"], "org.example.foo") == [] + + # disallowed file names + assert apkutils.filterFastlaneFileNames(["org.example.foo/en_US/images/foo.png"], "org.example.foo") == [] + assert apkutils.filterFastlaneFileNames(["org.example.foo/en_US/images/icon.exe"], "org.example.foo") == [] + assert ( + apkutils.filterFastlaneFileNames( + ["org.example.foo/en_US/images/phoneScreenshots/foo.exe"], "org.example.foo" + ) + == [] + ) + assert apkutils.filterFastlaneFileNames(["org.example.foo/en-US/foo.txt"], "org.example.foo") == [] + assert apkutils.filterFastlaneFileNames(["org.example.foo/en_US/title.py"], "org.example.foo") == [] + + def test_filterFastlaneFileNames_dangerous_names(self): + assert apkutils.filterFastlaneFileNames(["/etc/passwd"], "org.example.foo") == [] + assert apkutils.filterFastlaneFileNames(["../../etc/passwd"], "org.example.foo") == [] + assert apkutils.filterFastlaneFileNames(["foo/../../etc/passwd"], "org.example.foo") == [] + assert apkutils.filterFastlaneFileNames(["org.example.foo/bla..txt"], "org.example.foo") == [] + + def test_filterFastlaneFileNames_invalid_applicationId(self): + with pytest.raises(ValueError): + apkutils.filterFastlaneFileNames([], "") + with pytest.raises(ValueError): + apkutils.filterFastlaneFileNames([], "/org.example.foo") + with pytest.raises(ValueError): + apkutils.filterFastlaneFileNames([], "org/example.foo") diff --git a/third_party/ci-notary-service/tests/test_authentication.py b/third_party/ci-notary-service/tests/test_authentication.py new file mode 100644 index 0000000..7a1627f --- /dev/null +++ b/third_party/ci-notary-service/tests/test_authentication.py @@ -0,0 +1,243 @@ +# SPDX-License-Identifier: BSD-2-Clause +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + +from unittest.mock import ANY, create_autospec + +import pytest +import requests + +import sftpnotary.authentication +from sftpnotary import projects +from sftpnotary.authentication import AuthenticationFailed, GitLabJobTokenAuthentication +from sftpnotary.core import Request + + +@pytest.fixture(autouse=True) +def no_requests(monkeypatch): + """Remove requests.sessions.Session.request for all tests to prevent "requests" + from performing actual HTTP requests.""" + monkeypatch.delattr("requests.sessions.Session.request") + + +def monkeyPatchWithAutospec(monkeyPatch, obj, name): + mock = create_autospec(getattr(obj, name)) + monkeyPatch.setattr(obj, name, mock) + return mock + + +@pytest.fixture +def mock_requests_get(monkeypatch): + return monkeyPatchWithAutospec(monkeypatch, requests, "get") + + +@pytest.fixture +def mock_apiRequest(monkeypatch): + return monkeyPatchWithAutospec(monkeypatch, GitLabJobTokenAuthentication, "apiRequest") + + +@pytest.fixture +def mock_getJob(monkeypatch): + return monkeyPatchWithAutospec(monkeypatch, GitLabJobTokenAuthentication, "getJob") + + +@pytest.fixture +def mock_getProject(monkeypatch): + return monkeyPatchWithAutospec(monkeypatch, GitLabJobTokenAuthentication, "getProject") + + +@pytest.fixture +def mock_projects_settings(monkeypatch): + mock = create_autospec(projects.ProjectSettings) + monkeypatch.setattr(sftpnotary.authentication.projects, "settings", mock) + return mock + + +class MockResponse: + def __init__(self, status_code=200, headers=None, json=None): + self.status_code = status_code + self.ok = status_code < 400 + self.text = "" + self.headers = headers if headers is not None else {} + self._json = json + + def json(self): + if self._json == requests.JSONDecodeError: + raise requests.JSONDecodeError("", "", 0) + return self._json + + def raise_for_status(self): + if not self.ok: + raise requests.HTTPError(f"{self.status_code} HTTP Error", response=self) + + +class TestAuthentication: + def test_init(self): + auth = GitLabJobTokenAuthentication("https://gitlab.example.net/api/v4", userAgent="SFTPNotary Test") + + assert auth.apiV4Url == "https://gitlab.example.net/api/v4" + assert auth.userAgent == "SFTPNotary Test" + + def test_apiRequest(self, mock_requests_get): + mock_requests_get.return_value = MockResponse(json={"foo": "bar"}, headers={}) + + auth = GitLabJobTokenAuthentication("https://gitlab.example.net/api/v4") + r = auth.apiRequest("/path/") + + assert r == {"foo": "bar"} + assert mock_requests_get.call_count == 1 + assert mock_requests_get.call_args.args[0] == f"{auth.apiV4Url}/path/" + headers = mock_requests_get.call_args.kwargs.get("headers") + assert headers is not None, "headers not passed to request function" + assert headers == {} + timeout = mock_requests_get.call_args.kwargs.get("timeout") + assert timeout is not None, "timeout not passed to request function" + assert timeout == 5, "timeout doesn't default to 5" + + def test_apiRequest_with_keyword_arguments(self, mock_requests_get): + mock_requests_get.return_value = MockResponse(json={"foo": "bar"}, headers={}) + + auth = GitLabJobTokenAuthentication("https://gitlab.example.net/api/v4", userAgent="SFTPNotary Test") + auth.apiRequest("/path/", headers={"Authorization": "Bearer foo"}, timeout=42, keyword="value") + + headers = mock_requests_get.call_args.kwargs.get("headers") + assert headers.get("Authorization") == "Bearer foo" + assert headers.get("User-Agent") == auth.userAgent + timeout = mock_requests_get.call_args.kwargs.get("timeout") + assert timeout == 42 + keyword = mock_requests_get.call_args.kwargs.get("keyword") + assert keyword == "value", "keyword argument 'keyword' not passed as-is to request function" + + def test_apiRequest_failed_request(self, mock_requests_get): + mock_requests_get.return_value = MockResponse(status_code=400, json={}, headers={}) + + auth = GitLabJobTokenAuthentication("https://gitlab.example.net/api/v4") + with pytest.raises(requests.HTTPError, match="HTTP Error"): + auth.apiRequest("/path/") + + def test_apiRequest_invalid_response(self, mock_requests_get): + mock_requests_get.return_value = MockResponse(status_code=200, json=requests.JSONDecodeError, headers={}) + + auth = GitLabJobTokenAuthentication("https://gitlab.example.net/api/v4") + with pytest.raises(requests.JSONDecodeError): + auth.apiRequest("/path/") + + def test_getJob(self, mock_apiRequest): + mock_apiRequest.return_value = {"foo": "bar"} + + auth = GitLabJobTokenAuthentication("https://gitlab.example.net/api/v4") + job = auth.getJob("job-token") + + assert job == {"foo": "bar"} + mock_apiRequest.assert_called_once_with(auth, "/job", headers=ANY) + headers = mock_apiRequest.call_args.kwargs.get("headers") + assert headers.get("Authorization") == "Bearer job-token" + + def test_getJob_failed_request(self, mock_apiRequest): + mock_apiRequest.side_effect = requests.RequestException + + auth = GitLabJobTokenAuthentication("https://gitlab.example.net/api/v4") + job = auth.getJob("job-token") + + assert job is None + + def test_getProject(self, mock_apiRequest): + mock_apiRequest.return_value = {"foo": "bar"} + + auth = GitLabJobTokenAuthentication("https://gitlab.example.net/api/v4") + project = auth.getProject(42) + + assert project == {"foo": "bar"} + mock_apiRequest.assert_called_once_with(auth, "/projects/42") + + def test_getProject_failed_request(self, mock_apiRequest): + mock_apiRequest.side_effect = requests.RequestException + + auth = GitLabJobTokenAuthentication("https://gitlab.example.net/api/v4") + project = auth.getProject(42) + + assert project is None + + def test_authenticate(self, mock_getJob, mock_getProject, mock_projects_settings): + mock_getJob.return_value = {"pipeline": {"project_id": 42, "source": "push"}, "ref": "branchA"} + mock_getProject.return_value = {"path_with_namespace": "namespaceA/projectA"} + mock_projects_settings.exists.return_value = True + + auth = GitLabJobTokenAuthentication("https://gitlab.example.net/api/v4") + auth.authenticate(request=Request(token="job-token", branch="branchA", projectPath="namespaceA/projectA")) + + mock_getJob.assert_called_once_with(auth, "job-token") + mock_getProject.assert_called_once_with(auth, 42) + mock_projects_settings.exists.assert_called_once_with("namespaceA/projectA", "branchA") + + def test_authenticate_no_job(self, mock_getJob): + mock_getJob.return_value = None + + auth = GitLabJobTokenAuthentication("https://gitlab.example.net/api/v4") + with pytest.raises(AuthenticationFailed, match="Failed to retrieve job"): + auth.authenticate(request=Request(token="job-token", branch="branchA", projectPath="namespaceA/projectA")) + + def test_authenticate_job_without_project_id(self, mock_getJob): + mock_getJob.return_value = {"ref": "branchA"} + + auth = GitLabJobTokenAuthentication("https://gitlab.example.net/api/v4") + with pytest.raises(AuthenticationFailed, match="pipeline.project_id"): + auth.authenticate(request=Request(token="job-token", branch="branchA", projectPath="namespaceA/projectA")) + + def test_authenticate_no_project(self, mock_getJob, mock_getProject): + mock_getJob.return_value = {"pipeline": {"project_id": 42, "source": "push"}, "ref": "branchA"} + mock_getProject.return_value = None + + auth = GitLabJobTokenAuthentication("https://gitlab.example.net/api/v4") + with pytest.raises(AuthenticationFailed, match="Failed to retrieve project"): + auth.authenticate(request=Request(token="job-token", branch="branchA", projectPath="namespaceA/projectA")) + + def test_authenticate_job_without_ref(self, mock_getJob, mock_getProject): + mock_getJob.return_value = {"pipeline": {"project_id": 42, "source": "push"}} + mock_getProject.return_value = {} + + auth = GitLabJobTokenAuthentication("https://gitlab.example.net/api/v4") + with pytest.raises(AuthenticationFailed, match="does not match the job's branch"): + auth.authenticate(request=Request(token="job-token", branch="branchA", projectPath="namespaceA/projectA")) + + def test_authenticate_job_with_wrong_branch(self, mock_getJob, mock_getProject): + mock_getJob.return_value = {"pipeline": {"project_id": 42, "source": "push"}, "ref": "wrongBranch"} + mock_getProject.return_value = {} + + auth = GitLabJobTokenAuthentication("https://gitlab.example.net/api/v4") + with pytest.raises(AuthenticationFailed, match="does not match the job's branch"): + auth.authenticate(request=Request(token="job-token", branch="branchA", projectPath="namespaceA/projectA")) + + def test_authenticate_merge_request_job(self, mock_getJob, mock_getProject, mock_projects_settings): + mock_getJob.return_value = {"pipeline": {"project_id": 42, "source": "merge_request_event"}, "ref": "branchA"} + mock_getProject.return_value = {"path_with_namespace": "namespaceA/projectA"} + mock_projects_settings.exists.return_value = True + + auth = GitLabJobTokenAuthentication("https://gitlab.example.net/api/v4") + with pytest.raises(AuthenticationFailed, match="Merge requests are not cleared for this request"): + auth.authenticate(request=Request(token="job-token", branch="branchA", projectPath="namespaceA/projectA")) + + def test_authenticate_project_without_path(self, mock_getJob, mock_getProject): + mock_getJob.return_value = {"pipeline": {"project_id": 42, "source": "push"}, "ref": "branchA"} + mock_getProject.return_value = {} + + auth = GitLabJobTokenAuthentication("https://gitlab.example.net/api/v4") + with pytest.raises(AuthenticationFailed, match="does not match the job's project path"): + auth.authenticate(request=Request(token="job-token", branch="branchA", projectPath="namespaceA/projectA")) + + def test_authenticate_project_with_wrong_path(self, mock_getJob, mock_getProject): + mock_getJob.return_value = {"pipeline": {"project_id": 42, "source": "push"}, "ref": "branchA"} + mock_getProject.return_value = {"path_with_namespace": "wrong/path"} + + auth = GitLabJobTokenAuthentication("https://gitlab.example.net/api/v4") + with pytest.raises(AuthenticationFailed, match="does not match the job's project path"): + auth.authenticate(request=Request(token="job-token", branch="branchA", projectPath="namespaceA/projectA")) + + def test_authenticate_disallowed_project_branch(self, mock_getJob, mock_getProject, mock_projects_settings): + mock_getJob.return_value = {"pipeline": {"project_id": 42, "source": "push"}, "ref": "branchA"} + mock_getProject.return_value = {"path_with_namespace": "namespaceA/projectA"} + mock_projects_settings.exists.return_value = False + + auth = GitLabJobTokenAuthentication("https://gitlab.example.net/api/v4") + with pytest.raises(AuthenticationFailed, match="not cleared"): + auth.authenticate(request=Request(token="job-token", branch="branchA", projectPath="namespaceA/projectA")) diff --git a/third_party/ci-notary-service/tests/test_flatpaksigner.py b/third_party/ci-notary-service/tests/test_flatpaksigner.py new file mode 100644 index 0000000..d15229d --- /dev/null +++ b/third_party/ci-notary-service/tests/test_flatpaksigner.py @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: BSD-2-Clause +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + +import re + +import pytest + +from sftpnotary import flatpaksigner + +goodBundleHeader = ( + b"flatpak\0\x42\x00\x89\xe5\x00\x75\x08\x00ref\0\0\0\0\0app/org.example.abcde/x86_64/master\0\x00\x73\x04\x00" +) +goodBundleHeaderBigEndian = ( + b"flatpak\0\x42\x00\x89\xe5\x00\x75\x08\x00ref\0\0\0\0\0app/org.example.abcde/x86_64/master\0\x00\x73\x04\x00" +) + +truncatedBundleHeader = b"flatpak\0\x01\x00\x89\xe5\x00\x75\x08\x00" +invalidBundleHeader1 = ( + b"flaptak\0\x01\x00\x89\xe5\x00\x75\x08\x00ref\0\0\0\0\0app/org.example.abcde/x86_64/master\0\x00\x73\x04\x00" +) +invalidBundleHeader2 = ( + b"flatpak\0\x01\x00\x98\xe5\x00\x75\x08\x00ref\0\0\0\0\0app/org.example.abcde/x86_64/master\0\x00\x73\x04\x00" +) +noRefInBundleHeader = ( + b"flatpak\0\x01\x00\x89\xe5\x00\x75\x08\x00fer\0\0\0\0\0app/org.example.abcde/x86_64/master\0\x00\x73\x04\x00" +) +noEndOfRefBundleHeader = b"flatpak\0\x42\x00\x89\xe5\x00\x75\x08\x00ref\0\0\0\0\0app/org.example.abcde/x86_64/master" + + +class TestFlatpakSigner: + def test_getRefFromFlatpakBundleHeader(self): + ref = flatpaksigner.getRefFromFlatpakBundleHeader(goodBundleHeader) + assert ref == "app/org.example.abcde/x86_64/master" + ref = flatpaksigner.getRefFromFlatpakBundleHeader(goodBundleHeaderBigEndian) + assert ref == "app/org.example.abcde/x86_64/master" + + def test_getRefFromFlatpakBundleHeader_errors(self): + with pytest.raises(Exception, match=re.escape("Truncated or invalid Flatpak bundle (smaller than 32 bytes)")): + flatpaksigner.getRefFromFlatpakBundleHeader(truncatedBundleHeader) + with pytest.raises(Exception, match=re.escape("Invalid Flatpak bundle header (doesn't start with 'flatpak')")): + flatpaksigner.getRefFromFlatpakBundleHeader(invalidBundleHeader1) + with pytest.raises(Exception, match=re.escape("Invalid Flatpak bundle header (wrong magic number)")): + flatpaksigner.getRefFromFlatpakBundleHeader(invalidBundleHeader2) + with pytest.raises(Exception, match=re.escape("Start of 'ref' entry not found")): + flatpaksigner.getRefFromFlatpakBundleHeader(noRefInBundleHeader) + with pytest.raises(Exception, match=re.escape("End of 'ref' value not found")): + flatpaksigner.getRefFromFlatpakBundleHeader(noEndOfRefBundleHeader) diff --git a/third_party/ci-notary-service/tests/test_projects.py b/third_party/ci-notary-service/tests/test_projects.py new file mode 100644 index 0000000..12467bb --- /dev/null +++ b/third_party/ci-notary-service/tests/test_projects.py @@ -0,0 +1,207 @@ +# SPDX-License-Identifier: BSD-2-Clause +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + +import pytest + +from sftpnotary import projects + + +class TestProjects: + def test_load_branch_settings(self): + settings = """ + namespace/project: + branches: + branchname: + keyA: valueA + keyB: valueB + """ + projects.readProjectSettings(settings) + assert projects.settings is not None + assert "namespace/project" in projects.settings._projects + p = projects.settings._projects["namespace/project"] + assert "branchname" in p + b = p["branchname"] + assert len(b) == 2 + assert b.get("keyA") == "valueA" + assert b.get("keyB") == "valueB" + + def test_load_project_and_branch_settings(self): + settings = """ + namespace/project: + keyA: valueAP + keyC: valueC + branches: + branchA: + keyA: valueA + keyB: valueB + branchB: + """ + projects.readProjectSettings(settings) + assert projects.settings is not None + assert "namespace/project" in projects.settings._projects + p = projects.settings._projects["namespace/project"] + assert len(p) == 2 + branchA = p["branchA"] + assert len(branchA) == 3 + assert branchA.get("keyA") == "valueA" + assert branchA.get("keyB") == "valueB" + assert branchA.get("keyC") == "valueC" + branchB = p["branchB"] + assert len(branchB) == 2 + assert branchB.get("keyA") == "valueAP" + assert branchB.get("keyC") == "valueC" + + def test_load_default_settings(self): + settings = """ + defaults: + keyA: defaultA + keyC: defaultC + branches: + - branchname + + namespace/project: + """ + projects.readProjectSettings(settings) + assert projects.settings is not None + assert "namespace/project" in projects.settings._projects + p = projects.settings._projects["namespace/project"] + assert "branchname" in p + b = p["branchname"] + assert len(b) == 2 + assert b.get("keyA") == "defaultA" + assert b.get("keyC") == "defaultC" + + def test_load_settings(self): + settings = """ + defaults: + keyA: defaultA + keyC: defaultC + keyD: defaultD + branches: + - defaultBranch + + namespace/project: + keyA: projectA + keyB: projectB + branches: + branchA: + keyA: valueA + defaultBranch: + keyC: valueC + """ + projects.readProjectSettings(settings) + assert projects.settings is not None + assert "namespace/project" in projects.settings._projects + p = projects.settings._projects["namespace/project"] + assert len(p) == 2 + assert "branchA" in p + branchA = p["branchA"] + assert len(branchA) == 4 + assert branchA.get("keyA") == "valueA" + assert branchA.get("keyB") == "projectB" + assert branchA.get("keyC") == "defaultC" + assert branchA.get("keyD") == "defaultD" + assert "defaultBranch" in p + defaultBranch = p["defaultBranch"] + assert len(defaultBranch) == 4 + assert defaultBranch.get("keyA") == "projectA" + assert defaultBranch.get("keyB") == "projectB" + assert defaultBranch.get("keyC") == "valueC" + assert defaultBranch.get("keyD") == "defaultD" + + def test_branches_looking_like_int_float_bool_etc(self): + settings = """ + namespace/projectA: + branches: + 42: + 2.0: + true: + """ + projects.readProjectSettings(settings) + assert projects.settings is not None + assert "namespace/projectA" in projects.settings._projects + p = projects.settings._projects["namespace/projectA"] + assert len(p) == 3 + assert "42" in p + assert "2.0" in p + assert "true" in p + + def test_exists(self): + settings = """ + defaults: + branches: + - defaultBranch + + namespace/project: + branches: + branchA: + """ + projects.readProjectSettings(settings) + assert projects.settings.exists("namespace/project") + assert not projects.settings.exists("namespace/other-project") + + assert projects.settings.exists("namespace/project", "branchA") + assert projects.settings.exists("namespace/project", "defaultBranch") + assert not projects.settings.exists("namespace/project", "otherBranch") + + def test_get(self): + settings = """ + defaults: + keyA: defaultA + keyC: defaultC + branches: + - defaultBranch + + namespace/project: + keyA: projectA + keyB: projectB + branches: + branchA: + keyA: valueA + """ + projects.readProjectSettings(settings) + assert projects.settings.get("namespace/project", "branchA", "keyA") == "valueA" + assert projects.settings.get("namespace/project", "branchA", "keyB") == "projectB" + assert projects.settings.get("namespace/project", "branchA", "keyC") == "defaultC" + assert projects.settings.get("namespace/project", "defaultBranch", "keyA") == "projectA" + assert projects.settings.get("namespace/project", "defaultBranch", "keyB") == "projectB" + assert projects.settings.get("namespace/project", "defaultBranch", "keyC") == "defaultC" + + with pytest.raises(projects.Error, match=r"Unknown project .*"): + projects.settings.get("namespace/other-project", "defaultBranch", "keyA") + with pytest.raises(projects.Error, match=r"Unknown branch .*"): + projects.settings.get("namespace/project", "otherBranch", "keyA") + assert projects.settings.get("namespace/project", "branchA", "unknownKey") is None + assert projects.settings.get("namespace/project", "branchA", "unknownKey", ["foo"]) == ["foo"] + + def test_getBool(self): + settings = """ + namespace/project: + branches: + branchA: + boolTrue: tRuE + bool1: 1 + boolYes: YeS + boolOn: oN + boolFalse: fAlsE + bool0: 0 + boolNo: nO + boolOff: oFF + boolInvalid: invalid + """ + projects.readProjectSettings(settings) + assert projects.settings.getBool("namespace/project", "branchA", "boolTrue", False) is True + assert projects.settings.getBool("namespace/project", "branchA", "bool1", False) is True + assert projects.settings.getBool("namespace/project", "branchA", "boolYes", False) is True + assert projects.settings.getBool("namespace/project", "branchA", "boolOn", False) is True + assert projects.settings.getBool("namespace/project", "branchA", "boolFalse", True) is False + assert projects.settings.getBool("namespace/project", "branchA", "bool0", True) is False + assert projects.settings.getBool("namespace/project", "branchA", "boolNo", True) is False + assert projects.settings.getBool("namespace/project", "branchA", "boolOff", True) is False + + assert projects.settings.getBool("namespace/project", "branchA", "boolNoSet", True) is True + assert projects.settings.getBool("namespace/project", "branchA", "boolNoSet", False) is False + + with pytest.raises(ValueError, match=r"Not a boolean: .*"): + projects.settings.getBool("namespace/project", "branchA", "boolInvalid", True) diff --git a/third_party/ci-notary-service/tests/test_requests.py b/third_party/ci-notary-service/tests/test_requests.py new file mode 100644 index 0000000..d4b5abc --- /dev/null +++ b/third_party/ci-notary-service/tests/test_requests.py @@ -0,0 +1,26 @@ +# SPDX-License-Identifier: BSD-2-Clause +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + +import pytest + +from sftpnotary.core import SingleFileRequest +from sftpnotary.exceptions import InvalidFileName + + +class TestRequests: + def test_SingleFileRequest_validation(self): + validFileName = SingleFileRequest(fileName="foo.apk") + validFileName.validate() + + missingFileName = SingleFileRequest() + with pytest.raises(InvalidFileName): + missingFileName.validate() + + emptyFileName = SingleFileRequest(fileName="") + with pytest.raises(InvalidFileName): + emptyFileName.validate() + + invalidFileName = SingleFileRequest(fileName="../../etc/passwd") + with pytest.raises(InvalidFileName): + invalidFileName.validate() diff --git a/third_party/ci-notary-service/tests/test_sftp.py b/third_party/ci-notary-service/tests/test_sftp.py new file mode 100644 index 0000000..66332a5 --- /dev/null +++ b/third_party/ci-notary-service/tests/test_sftp.py @@ -0,0 +1,337 @@ +# SPDX-License-Identifier: BSD-2-Clause +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + +import stat +import time +from unittest.mock import create_autospec, Mock + +import paramiko +import pytest + +import sftpnotary.sftp +from sftpnotary.sftp import SFTPClient, SFTPError + + +@pytest.fixture(autouse=True) +def mock_paramiko(monkeypatch): + monkeypatch.setattr(sftpnotary.sftp, "SSHClient", create_autospec(paramiko.SSHClient)) + monkeypatch.setattr(sftpnotary.sftp.RSAKey, "from_private_key_file", Mock(return_value="-----RSA Key")) + monkeypatch.setattr(sftpnotary.sftp.RSAKey, "from_private_key", Mock(side_effect=lambda x: x.read())) + + +def createSFTPAttributes(**kwargs): + attrs = paramiko.SFTPAttributes() + attrs.st_mode = 0 + for k, v in kwargs.items(): + setattr(attrs, k, v) + return attrs + + +class TestSFTP: + def test_connect_and_cleanup(self): + with SFTPClient() as sftp: + sftp.connect("localhost", "base/path", knownHostsFile="/knownHostsFile", port=-1, username="username") + internalSshClient = sftp._sshClient + internalSftpClient = sftp._sftpClient + assert internalSshClient is not None + assert internalSftpClient is not None + internalSshClient.load_system_host_keys.assert_called_once_with("/knownHostsFile") + internalSshClient.set_missing_host_key_policy.assert_not_called() + internalSshClient.connect.assert_called_once_with("localhost", port=-1, username="username") + internalSftpClient.chdir.assert_called_once_with("base/path") + + internalSftpClient.close.assert_called_once() + assert sftp._sftpClient is None + internalSshClient.close.assert_called_once() + assert sftp._sshClient is None + + def test_connect_accepts_missing_host_keys_if_known_host_file_not_given(self): + with SFTPClient() as sftp: + sftp.connect("localhost", "base/path") + internalSshClient = sftp._sshClient + internalSshClient.set_missing_host_key_policy.assert_called_once() + assert isinstance( + internalSshClient.set_missing_host_key_policy.call_args.args[0], paramiko.client.AutoAddPolicy + ) + + def test_connect_with_rsa_key_file(self): + with SFTPClient() as sftp: + sftp.connect("localhost", "base/path", rsaKeyFile="/rsaKey") + internalSshClient = sftp._sshClient + internalSshClient.connect.assert_called_once_with("localhost", pkey="-----RSA Key", allow_agent=False) + + def test_connect_with_rsa_key_from_environment_variable(self, monkeypatch): + monkeypatch.setenv("RSA_KEY", "-----RSA Key from env. var.") + with SFTPClient() as sftp: + sftp.connect("localhost", "base/path", rsaKeyFile="env:RSA_KEY") + internalSshClient = sftp._sshClient + internalSshClient.connect.assert_called_once_with( + "localhost", pkey="-----RSA Key from env. var.", allow_agent=False + ) + + def test_connect_with_rsa_key_file_from_environment_variable(self, monkeypatch): + monkeypatch.setenv("RSA_KEY", "/rsaKeyPath") + with SFTPClient() as sftp: + sftp.connect("localhost", "base/path", rsaKeyFile="env:RSA_KEY") + internalSshClient = sftp._sshClient + internalSshClient.connect.assert_called_once_with("localhost", pkey="-----RSA Key", allow_agent=False) + + def test_reconnect(self): + with SFTPClient() as sftp: + sftp.connect( + "localhost", + "base/path", + knownHostsFile="/knownHostsFile", + rsaKeyFile="/rsaKey", + port=-1, + username="username", + ) + oldSshClient = sftp._sshClient + oldSshClient.reset_mock() + oldSftpClient = sftp._sftpClient + oldSftpClient.reset_mock() + + sftp.reconnect() + + oldSftpClient.close.assert_called_once() + oldSshClient.close.assert_called_once() + newSshClient = sftp._sshClient + newSftpClient = sftp._sftpClient + newSshClient.connect.assert_called_once_with( + "localhost", port=-1, username="username", pkey="-----RSA Key", allow_agent=False + ) + newSftpClient.chdir.assert_called_once_with("base/path") + + def test_reconnect_retries_multiple_times(self, monkeypatch): + with SFTPClient() as sftp: + sftp.connect("localhost", "base/path") + + monkeypatch.setattr(sftpnotary.sftp, "SSHClient", Mock(side_effect=sftpnotary.sftp.SSHException)) + monkeypatch.setattr(time, "sleep", Mock()) + + with pytest.raises(SFTPError): + sftp.reconnect(maxTries=10) + + assert sftpnotary.sftp.SSHClient.call_count == 10 + assert time.sleep.call_args_list == [ + ((1.0,),), + ((2.0,),), + ((4.0,),), + ((8.0,),), + ((16.0,),), + ((32.0,),), + ((60,),), + ((60,),), + ((60,),), + ] + + def test_download(self): + with SFTPClient() as sftp: + sftp.connect("localhost", "base/path") + internalSftpClient = sftp._sftpClient + + sftp.download("remote/path", "local/path") + + internalSftpClient.get.assert_called_once() + assert internalSftpClient.get.call_args.args[0] == "remote/path" + assert internalSftpClient.get.call_args.args[1] == "local/path" + + def test_download_fails(self, monkeypatch): + with SFTPClient() as sftp: + sftp.connect("localhost", "base/path") + internalSftpClient = sftp._sftpClient + + monkeypatch.setattr(internalSftpClient, "get", Mock(side_effect=Exception)) + monkeypatch.setattr(sftpnotary.sftp.Path, "unlink", Mock()) + with pytest.raises(SFTPError): + sftp.download("remote/path", "local/path") + + sftpnotary.sftp.Path.unlink.assert_called_once_with(missing_ok=True) + + def test_downloadBytes(self, monkeypatch): + with SFTPClient() as sftp: + sftp.connect("localhost", "base/path") + internalSftpClient = sftp._sftpClient + + def getfo_mock(_, fl, **__): + fl.write(b"BYTES") + + monkeypatch.setattr(internalSftpClient, "getfo", Mock(side_effect=getfo_mock)) + result = sftp.downloadBytes("remote/path") + + assert result == b"BYTES" + internalSftpClient.getfo.assert_called_once() + assert internalSftpClient.getfo.call_args.args[0] == "remote/path" + + def test_downloadBytes_fails(self, monkeypatch): + with SFTPClient() as sftp: + sftp.connect("localhost", "base/path") + internalSftpClient = sftp._sftpClient + + monkeypatch.setattr(internalSftpClient, "getfo", Mock(side_effect=Exception)) + with pytest.raises(SFTPError): + sftp.downloadBytes("remote/path") + + def test_upload(self): + with SFTPClient() as sftp: + sftp.connect("localhost", "base/path") + internalSftpClient = sftp._sftpClient + + sftp.upload("local/path", "remote/path") + + internalSftpClient.put.assert_called_once() + assert internalSftpClient.put.call_args.args[0] == "local/path" + assert internalSftpClient.put.call_args.args[1] == "remote/path" + + def test_upload_retried_up_to_3_times_on_EOFError(self, monkeypatch): + with SFTPClient() as sftp: + sftp.connect("localhost", "base/path") + internalSftpClient = sftp._sftpClient + + monkeypatch.setattr(sftp, "reconnect", Mock()) + monkeypatch.setattr(internalSftpClient, "put", Mock(side_effect=(EOFError, None))) + sftp.upload("local/path", "remote/path") + assert sftp.reconnect.called + assert internalSftpClient.put.call_count == 2 + + sftp.reconnect.reset_mock() + internalSftpClient.put.reset_mock() + internalSftpClient.put.side_effect = (EOFError, EOFError, None) + sftp.upload("local/path", "remote/path") + assert internalSftpClient.put.call_count == 3 + + sftp.reconnect.reset_mock() + internalSftpClient.put.reset_mock() + internalSftpClient.put.side_effect = EOFError + with pytest.raises(SFTPError): + sftp.upload("local/path", "remote/path") + assert internalSftpClient.put.call_count == 3 + + def test_upload_not_retried_on_other_errors(self, monkeypatch): + with SFTPClient() as sftp: + sftp.connect("localhost", "base/path") + internalSftpClient = sftp._sftpClient + + monkeypatch.setattr(sftp, "reconnect", Mock()) + monkeypatch.setattr(internalSftpClient, "put", Mock(side_effect=Exception)) + with pytest.raises(SFTPError): + sftp.upload("local/path", "remote/path") + assert not sftp.reconnect.called + assert internalSftpClient.put.call_count == 1 + + def test_uploadBytes(self): + with SFTPClient() as sftp: + sftp.connect("localhost", "base/path") + internalSftpClient = sftp._sftpClient + + sftp.uploadBytes(b"BYTES", "remote/path") + + internalSftpClient.putfo.assert_called_once() + assert internalSftpClient.putfo.call_args.args[1] == "remote/path" + + def test_uploadBytes_retried_up_to_3_times_on_EOFError(self, monkeypatch): + with SFTPClient() as sftp: + sftp.connect("localhost", "base/path") + internalSftpClient = sftp._sftpClient + + monkeypatch.setattr(sftp, "reconnect", Mock()) + monkeypatch.setattr(internalSftpClient, "putfo", Mock(side_effect=(EOFError, None))) + sftp.uploadBytes(b"BYTES", "remote/path") + assert sftp.reconnect.called + assert internalSftpClient.putfo.call_count == 2 + + sftp.reconnect.reset_mock() + internalSftpClient.putfo.reset_mock() + internalSftpClient.putfo.side_effect = (EOFError, EOFError, None) + sftp.uploadBytes(b"BYTES", "remote/path") + assert internalSftpClient.putfo.call_count == 3 + + sftp.reconnect.reset_mock() + internalSftpClient.putfo.reset_mock() + internalSftpClient.putfo.side_effect = EOFError + with pytest.raises(SFTPError): + sftp.uploadBytes(b"BYTES", "remote/path") + assert internalSftpClient.putfo.call_count == 3 + + def test_uploadBytes_not_retried_on_other_errors(self, monkeypatch): + with SFTPClient() as sftp: + sftp.connect("localhost", "base/path") + internalSftpClient = sftp._sftpClient + + monkeypatch.setattr(sftp, "reconnect", Mock()) + monkeypatch.setattr(internalSftpClient, "putfo", Mock(side_effect=Exception)) + with pytest.raises(SFTPError): + sftp.uploadBytes(b"BYTES", "remote/path") + assert not sftp.reconnect.called + assert internalSftpClient.putfo.call_count == 1 + + def test_recursiveRemoveDirectory(self, monkeypatch): + with SFTPClient() as sftp: + sftp.connect("localhost", "base/path") + internalSftpClient = sftp._sftpClient + + def listdir_attr_mock(path): + if str(path) == "folder": + return [ + createSFTPAttributes(filename="file1"), + createSFTPAttributes(filename="file2"), + createSFTPAttributes(filename="subfolder1", st_mode=stat.S_IFDIR), + ] + elif str(path) == "folder/subfolder1": + return [ + createSFTPAttributes(filename="file1.1"), + createSFTPAttributes(filename="file1.2"), + ] + raise Exception(f"Called with unexpected path {path}") + + monkeypatch.setattr(internalSftpClient, "listdir_attr", Mock(side_effect=listdir_attr_mock)) + monkeypatch.setattr(internalSftpClient, "remove", Mock()) + monkeypatch.setattr(internalSftpClient, "rmdir", Mock()) + + sftp.recursiveRemoveDirectory("folder") + + assert internalSftpClient.remove.call_count == 4 + assert internalSftpClient.remove.call_args_list == [ + (("folder/file1",),), + (("folder/file2",),), + (("folder/subfolder1/file1.1",),), + (("folder/subfolder1/file1.2",),), + ] + assert internalSftpClient.rmdir.call_count == 2 + assert internalSftpClient.rmdir.call_args_list == [ + (("folder/subfolder1",),), + (("folder",),), + ] + + def test_forwarded_functions(self, monkeypatch): + with SFTPClient() as sftp: + sftp.connect("localhost", "base/path") + internalSftpClient = sftp._sftpClient + + monkeypatch.setattr(internalSftpClient, "listdir", Mock(return_value="listdir")) + assert sftp.listdir("remote/path") == "listdir" + + monkeypatch.setattr(internalSftpClient, "listdir_attr", Mock(return_value="listdir_attr")) + assert sftp.listdir_attr("remote/path") == "listdir_attr" + + monkeypatch.setattr(internalSftpClient, "listdir_iter", Mock(return_value="listdir_iter")) + assert sftp.listdir_iter("remote/path") == "listdir_iter" + + monkeypatch.setattr(internalSftpClient, "lstat", Mock(return_value="lstat")) + assert sftp.lstat("remote/path") == "lstat" + + monkeypatch.setattr(internalSftpClient, "mkdir", Mock(return_value="mkdir")) + assert sftp.mkdir("remote/path") == "mkdir" + + monkeypatch.setattr(internalSftpClient, "posix_rename", Mock(return_value="posix_rename")) + assert sftp.posix_rename("remote/oldpath", "remote/newpath") == "posix_rename" + + monkeypatch.setattr(internalSftpClient, "remove", Mock(return_value="remove")) + assert sftp.remove("remote/path") == "remove" + + monkeypatch.setattr(internalSftpClient, "rmdir", Mock(return_value="rmdir")) + assert sftp.rmdir("remote/path") == "rmdir" + + monkeypatch.setattr(internalSftpClient, "stat", Mock(return_value="stat")) + assert sftp.stat("remote/path") == "stat" diff --git a/third_party/ci-notary-service/tests/test_util.py b/third_party/ci-notary-service/tests/test_util.py new file mode 100644 index 0000000..3ce31aa --- /dev/null +++ b/third_party/ci-notary-service/tests/test_util.py @@ -0,0 +1,55 @@ +# SPDX-License-Identifier: BSD-2-Clause +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + +import pytest + +from sftpnotary import util +from sftpnotary.exceptions import Error, InvalidFileName + + +class TestUtil: + def test_collectArgumentsUpToSize(self): + assert list(util.collectArgumentsUpToSize(["1.exe"], 42)) == [["1.exe"]] + assert list(util.collectArgumentsUpToSize(["1.exe"], 5)) == [["1.exe"]] + with pytest.raises(Error): + list(util.collectArgumentsUpToSize(["1.exe"], 4)) + + assert list(util.collectArgumentsUpToSize(["1.exe", "11.exe"], 42)) == [["1.exe", "11.exe"]] + assert list(util.collectArgumentsUpToSize(["1.exe", "11.exe"], 6)) == [["1.exe"], ["11.exe"]] + with pytest.raises(Error): + list(util.collectArgumentsUpToSize(["1.exe", "11.exe"], 5)) + + assert list(util.collectArgumentsUpToSize(["1.exe", "2.exe", "3.exe"], 11)) == [["1.exe", "2.exe"], ["3.exe"]] + assert list(util.collectArgumentsUpToSize(["1.exe", "2.exe", "3.exe"], 10)) == [["1.exe"], ["2.exe"], ["3.exe"]] + + def test_validateFileName(self): + util.validateFileName("foo.apk") + + with pytest.raises(InvalidFileName): + util.validateFileName(None) + with pytest.raises(InvalidFileName): + util.validateFileName("") + with pytest.raises(InvalidFileName): + util.validateFileName("../../etc/passwd") + + util.validateFileName("foo bar.apk") + util.validateFileName("foo\tbar.apk") + util.validateFileName("föö.apk") + + def test_validateFileName_strict(self): + util.validateFileName("foo-arm64-v8a.apk", strict=True) + + with pytest.raises(InvalidFileName): + util.validateFileName(None, strict=True) + with pytest.raises(InvalidFileName): + util.validateFileName("", strict=True) + with pytest.raises(InvalidFileName): + util.validateFileName("../../etc/passwd", strict=True) + + with pytest.raises(InvalidFileName): + util.validateFileName("foo bar.apk", strict=True) + with pytest.raises(InvalidFileName): + util.validateFileName("foo\tbar.apk", strict=True) + with pytest.raises(InvalidFileName): + util.validateFileName("föö.apk", strict=True) diff --git a/third_party/ci-notary-service/tox.ini b/third_party/ci-notary-service/tox.ini new file mode 100644 index 0000000..707f12c --- /dev/null +++ b/third_party/ci-notary-service/tox.ini @@ -0,0 +1,84 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2023 KDE e.V. + +[tox] +minversion = 4.1.3 +envlist = py{310,311},coverage,format,lint,security,sort-imports,static-type-checker,yamllint + +[testenv] +description = installs the module and runs the tests for this Python version +skip_install = True +deps = pytest +commands = + pip install -e . + pytest --junitxml=junit-{envname}.xml --junit-prefix={envname} tests {posargs} + +[testenv:coverage] +description = runs the tests with coverage +skip_install = True +deps = + -r{toxinidir}/requirements.txt + coverage[toml] + pytest +commands = + coverage erase + coverage run --parallel -m pytest --junitxml=junit-{envname}.xml --junit-prefix={envname} tests + coverage combine + coverage xml + coverage report + +[testenv:check-format] +description = runs black --check +skip_install = true +deps = black==23.11.0 +commands = black --check . + +[testenv:format] +description = runs black +skip_install = true +deps = black==23.11.0 +commands = black . + +[testenv:lint] +description = runs flake8 +skip_install = true +deps = flake8==6.1.0 +commands = flake8 . + +[testenv:security] +description = runs bandit +skip_install = true +deps = bandit[toml]==1.8.6 +commands = bandit -c pyproject.toml -r . + +[testenv:check-imports] +description = runs isort --check +skip_install = true +deps = isort==5.12.0 +commands = isort --check . + +[testenv:sort-imports] +description = runs isort +skip_install = true +deps = isort==5.12.0 +commands = isort . + +[testenv:static-type-checker] +description = runs mypy +skip_install = true +deps = + mypy==1.7.0 + types-paramiko + types-PyYAML + types-requests + azure-storage-blob + markdownify + pkginfo + git+https://invent.kde.org/kloecker/microstore.git +commands = mypy . + +[testenv:yamllint] +description = runs yamllint +skip_install = true +deps = yamllint==1.33.0 +commands = yamllint . diff --git a/third_party/ci-notary-service/websitepublisher.py b/third_party/ci-notary-service/websitepublisher.py new file mode 100644 index 0000000..b98b035 --- /dev/null +++ b/third_party/ci-notary-service/websitepublisher.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: BSD-2-Clause +# +# SPDX-FileCopyrightText: 2023 KDE e.V. +# SPDX-FileCopyrightText: 2023 Ben Cooksley +# SPDX-FileContributor: Ingo Klöcker + +import sys + +from sftpnotary import authentication, config, util +from sftpnotary.exceptions import Error +from sftpnotary.websitepublisher import PublishWebsiteWorker + + +def parseCommandLine(): + import argparse + + parser = argparse.ArgumentParser(description="Worker for publishing files to a remote server") + + # debug options + parser.add_argument("-v", "--verbose", action="count", default=0, help="increase the verbosity") + + parser.add_argument("--id", dest="workerId", help="Unique, alpha-numeric identifier of this service worker") + + parser.add_argument("--config") + + options = parser.parse_args() + return options + + +def setUpAuthentication(): + auth = authentication.GitLabJobTokenAuthentication( + apiV4Url=config.settings.get("Authentication", "GitLabAPIv4Url", ""), userAgent="org.kde.websitepublisher" + ) + authentication.setAuthentication(auth) + + +def startWorker(workerId: str): + with util.connectToSftpServer() as sftp: + worker = PublishWebsiteWorker(workerId, sftp) + worker.start() + + +def main(): + options = parseCommandLine() + config.loadConfig(options.config) + util.setUpServiceLogging("websitepublisher", options.verbose) + util.loadProjectSettings(config.settings.get("General", "ProjectSettings")) + if config.settings.getboolean("Authentication", "Enabled", False): + setUpAuthentication() + + startWorker(options.workerId) + + return 0 + + +if __name__ == "__main__": + try: + sys.exit(main()) + except Error as e: + print("Error: %s" % e, file=sys.stderr) + sys.exit(1) diff --git a/third_party/ci-notary-service/windowsbinariessigner.py b/third_party/ci-notary-service/windowsbinariessigner.py new file mode 100644 index 0000000..688aaed --- /dev/null +++ b/third_party/ci-notary-service/windowsbinariessigner.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: BSD-2-Clause +# +# SPDX-FileCopyrightText: 2024 KDE e.V. +# SPDX-FileContributor: Ingo Klöcker + +import sys + +from sftpnotary import authentication, config, util +from sftpnotary.exceptions import Error +from sftpnotary.windowsbinariessigner import SignWindowsBinariesWorker + + +def parseCommandLine(): + import argparse + + parser = argparse.ArgumentParser(description="Worker for signing Windows binaries") + + # debug options + parser.add_argument("-v", "--verbose", action="count", default=0, help="increase the verbosity") + + parser.add_argument("--id", dest="workerId", help="Unique, alpha-numeric identifier of this service worker") + + parser.add_argument("--config") + + options = parser.parse_args() + return options + + +def setUpAuthentication(): + auth = authentication.GitLabJobTokenAuthentication( + apiV4Url=config.settings.get("Authentication", "GitLabAPIv4Url", ""), userAgent="org.kde.windowsbinariessigner" + ) + authentication.setAuthentication(auth) + + +def startWorker(workerId: str): + with util.connectToSftpServer() as sftp: + worker = SignWindowsBinariesWorker(workerId, sftp) + worker.start() + + +def main(): + options = parseCommandLine() + config.loadConfig(options.config) + util.setUpServiceLogging("windowsbinariessigner", options.verbose) + util.loadProjectSettings(config.settings.get("General", "ProjectSettings")) + if config.settings.getboolean("Authentication", "Enabled", False): + setUpAuthentication() + + startWorker(options.workerId) + + return 0 + + +if __name__ == "__main__": + try: + sys.exit(main()) + except Error as e: + print("Error: %s" % e, file=sys.stderr) + sys.exit(1) diff --git a/third_party/enote-sdk/README.md b/third_party/enote-sdk/README.md new file mode 100644 index 0000000..faec664 --- /dev/null +++ b/third_party/enote-sdk/README.md @@ -0,0 +1,548 @@ +## Version + +2.0 + +## INTRODUCTION + +This document is provided by MobiScribe. The SDK Library uses the JAVA language +design, which contains two classes.jar and javalib.jar JAVA Library. + +Developers can use this SDK to customize MobiScribe like: + +1. Refresh mode of the eInk panel +1. nDraw for handwriting speed-up +1. 2-Step-Suspend for power saving on the reading apps +1. Adb tool setup for Netronix devices + +## Development REQUIREMENTS + +# Operate System: + +- Windows 7 64-bit above version. +- Mac OS X +- Ubuntu 14.05 64-bit version + +# Java Environment: + +- Java Runtime Environment (JRE 1.8.0) +- Java Development Kit (JDK 8) + +# Android Environment: + +- Android SDK 4.4 (API level 19) +- Android Studio 2.1.3 above version + +# IMPLEMENTATION + +There are 2 main libraries for E-ink Refresh and Handwriting , customer +can include these libraries to make the performance better + +## E-ink Refresh Library + +Import view class : + +``` +import android.view.View ; +``` + +# Summary + +| Return | Parameter | +| ------ | ---------------------------------------------------------------------------------------------------------------------------- | +| void | invalidate( Rect region , int updateMode );
. Rect region : set invalidate area
. int updateMode : EINK update mode | +| void | void invalidate( int updateMode );
. int updateMode : EINK update mode | + +# Example Code for Full Refresh Display: + +``` +invalidate( UPDATE_MODE_FULL_GC16 ); +``` + +**EINK update mode (1/3)** + +``` +import android.view.View ; +public static final int UPDATE_MODE_FULL_GC16 = + View. EINK_WAVEFORM_MODE_GC16 + | View. EINK_UPDATE_MODE_FULL ; +public static final int UPDATE_MODE_PARTIAL_DU = + View. EINK_WAVEFORM_MODE_DU + | View. EINK_UPDATE_MODE_PARTIAL ; +``` + +**EINK Mode (2/3)** + +``` +public static final int UPDATE_MODE_PARTIAL_A2 = + View. EINK_WAVEFORM_MODE_A2 + | View. EINK_UPDATE_MODE_PARTIAL ; +public static final int UPDATE_MODE_PARTIAL_GC4 = + View. EINK_WAVEFORM_MODE_GC4 + | View. EINK_UPDATE_MODE_PARTIAL ; +public static final int UPDATE_MODE_PARTIAL_DU_WITH_DITHER = + View. EINK_WAVEFORM_MODE_DU + | View. EINK_UPDATE_MODE_PARTIAL + | View. EINK_DITHER_MODE_DITHER ; +public static final int UPDATE_MODE_PARTIAL_A2_WITH_DITHER = + View. EINK_WAVEFORM_MODE_A2 + | View. EINK_UPDATE_MODE_PARTIAL + | View. EINK_DITHER_MODE_DITHER ; +public static final int UPDATE_MODE_PARTIAL_GC4_WITH_DITHER = + View. EINK_WAVEFORM_MODE_GC4 + | View. EINK_UPDATE_MODE_PARTIAL + | View. EINK_DITHER_MODE_DITHER ; +public static final int UPDATE_MODE_PARTIAL_DU_WITH_MONO = + View. EINK_WAVEFORM_MODE_DU + | View. EINK_UPDATE_MODE_PARTIAL + | View. EINK_DITHER_MODE_DITHER + | View. EINK_MONOCHROME_MODE_MONOCHROME ; +``` + +**EINK Mode (3/3)** + +``` +public static final int UPDATE_MODE_PARTIAL_A2_WITH_MONO = + View. EINK_WAVEFORM_MODE_A2 + | View. EINK_UPDATE_MODE_PARTIAL + | View. EINK_DITHER_MODE_DITHER + | View. EINK_MONOCHROME_MODE_MONOCHROME ; +public static final int UPDATE_MODE_PARTIAL_GC4_WITH_MONO = + View. EINK_WAVEFORM_MODE_GC4 + | View. EINK_UPDATE_MODE_PARTIAL + | View. EINK_DITHER_MODE_DITHER + | View. EINK_MONOCHROME_MODE_MONOCHROME ; +public static final int UPDATE_MODE_PARTIAL_GC16 = + View. EINK_WAVEFORM_MODE_GC16 + | View. EINK_UPDATE_MODE_PARTIAL ; +public static final int UPDATE_MODE_PARTIAL_AUTO = + View. EINK_WAVEFORM_MODE_AUTO + | View. EINK_UPDATE_MODE_PARTIAL ; +public static final int UPDATE_MODE_FULL_A2 = + View. EINK_WAVEFORM_MODE_A2 + | View. EINK_UPDATE_MODE_FULL + | View. EINK_MONOCHROME_MODE_MONOCHROME ; +public static final int UPDATE_MODE_FULL_DU = + View. EINK_WAVEFORM_MODE_DU + | View. EINK_UPDATE_MODE_FULL + | View. EINK_MONOCHROME_MODE_MONOCHROME ; +public static final int MODE_APPNDRAWSTROKESYNC = 0x01000000; +``` + +## Handwriting Library + +``` +Import nDrawHelper class : +import ntx.draw.nDrawHelper; +``` + +# Summary + +| Return | Parameter | +| ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| void | NDrawInit();
no parameter; initialize nDraw | +| void | NDrawSetDrawRegion(int[] packet);
int [] packet { left, top, right, bottom} : set draw region | +| void | NDrawSwitch( boolean b )
boolean b = true : nDrawHelper enable
boolean b = false : nDrawHelper disable | +| void | NDrawSetInputOffset( int pen_offset_x , int pen_offset_y )
int pen_offset_x : set pen offset x-axis coordinate
int pen_offset_y : set pen offset y-axis coordinate | +| void | NDrawSetPenType( int penType)
int penType: set pen type | +| void | NDrawSetStrokeWidth( int lineWidth )
int lineWidth : set line width or pen thickness | +| void | NDrawSetPaintColor( int color )
int color : set paint color | +| void | NDrawSetUpdateMode(int refresh_mode)
int refresh_mode: set update mode of writing | +| void | NDrawSetMaxStrokeWidthWhenUsingPressure(int max_pressure )
int max_pressure: set maximum pen thickness when using pressure | +| void | NDrawSaveSignature()
no parameter; take screenshots of writing area and entire screen | +| void | NDrawSetInputRotation(int mCurrentRotation );
int mCurrentRotation: set orientation of writing | +| void | NDrawDropFrames(long nanosecond )
long nanosecond : set time of don't update screen | + +**Example Code for Initializing nDraw:** + +``` +@Override +protected void onCreate(Bundle savedInstanceState) { + super .onCreate(savedInstanceState); + nDrawHelper. NDrawInit (); +} +``` + +| Return | Parameter | +| ------ | ------------------------------------------------ | +| void | NDrawInit();
no parameter; initialize nDraw | + +**Example Code for Setting Draw Region** + +``` +int Ndraw_region_left = 0 ; +int Ndraw_region_top = getRelativeTop(NtxView. this ); +int Ndraw_region_right = Ndraw_region_left + w; +int Ndraw_region_bottom = Ndraw_region_top + h; +int [] packet1 = {Ndraw_region_left, Ndraw_region_top, Ndraw_region_right, +Ndraw_region_bottom}; +nDrawHelper.NDrawSetDrawRegion(packet1); +private int getRelativeTop(View myView ) { + if ( myView .getParent() == myView .getRootView()) + return myView .getTop(); + else + return myView .getTop() + getRelativeTop((View) myView .getParent()); +} +``` + +| Return | Parameter | +| ------ | ------------------------------------------------------------------------------------------------ | +| void | NDrawSetDrawRegion(int[] packet);
int [] packet { left, top, right, bottom} : set draw region | + +**Example Code for Setting Multi Draw Region** + +``` +int Ndraw_region_left = 0 ; +int Ndraw_region_top = getRelativeTop(NtxView. this ); +int Ndraw_region_right = Ndraw_region_left + w/ 3 ; +int Ndraw_region_bottom = Ndraw_region_top + h/ 3 ; +int Ndraw_region_left_2 = (w * 2 )/ 3 ; +int Ndraw_region_top_2 = getRelativeTop(NtxView. this ); +int Ndraw_region_right_2 = w; +int Ndraw_region_bottom_2 = Ndraw_region_top_2 + h/ 3 ; +int Ndraw_region_left_3 = w/ 3 ; +int Ndraw_region_top_3 = getRelativeTop(NtxView. this ) + h/ 3 ; +int Ndraw_region_right_3 = Ndraw_region_left_3 + w/ 3 ; +int Ndraw_region_bottom_3 = Ndraw_region_top_3 + h/ 3 ; +int [] multi_active_region = {Ndraw_region_left, Ndraw_region_top, Ndraw_region_right, +Ndraw_region_bottom, +Ndraw_region_left_2, Ndraw_region_top_2, Ndraw_region_right_2, +Ndraw_region_bottom_2, +Ndraw_region_left_3, Ndraw_region_top_3, Ndraw_region_right_3, +Ndraw_region_bottom_3}; +nDrawHelper. NDrawSetDrawRegion (multi_active_region); +private int getRelativeTop(View myView ) { + if ( myView .getParent() == myView .getRootView()) + return myView .getTop(); + else + return myView .getTop() + getRelativeTop((View) myView .getParent()); +} +``` + +| Return | Parameter | +| ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | +| void | NDrawSetDrawRegion(int[] packet);
int [] packet { left1, top1, right1, bottom1, left2, top2, right2, bottom2, left3, | +| top3, right3, bottom3} : set multi draw region | + +**Example Code for switch Hand Writing mode and pen offset :** + +``` +// Set nDraw enable +nDrawHelper.NDrawSwitch( true ); +// Set the pen offset, nDraw and Canvas offset must be the same. +public void setInputOffset(int offset_x, int offset_y){ +nDrawHelper.NDrawSetInputOffset(offset_x, offset_y); +intCanvasOffsetX=offset_x; +intCanvasOffsetY=offset_y; +} +// Sync the pen stroke of the canvas to the framebuffer instantly when pen up +int mode = MODE_APPNDRAWSTROKESYNC | UPDATE_MODE_FULL_GC16 ; +invalidate(mode); +``` + +| Return | Parameter | +| ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| void | NDrawSwitch( boolean b )
boolean b = true : nDrawHelper enable
boolean b = false : nDrawHelper disable | +| void | NDrawSetInputOffset( int pen_offset_x , int pen_offset_y )
int pen_offset_x : set nDraw pen offset x-axis coordinate
int pen_offset_y : set nDraw pen offset y-axis coordinate | + +**Example Code for Setting Pen Type:** + +``` +nDrawHelper. NDrawSetPenType ( 0 ); //Pencil +nDrawHelper. NDrawSetPenType ( 1 ); //Fountain Pen +nDrawHelper. NDrawSetPenType ( 2 ); //Chinese Brush +``` + +| Return | Parameter | +| ------------ | -------------------------------------------------------------------------------------------------------------- | +| void | NDrawSetPenType( int penType)
int penType: 0, 1, 2 set pen type as Pencil, Fountain Pen, and Chinese Brush | +| respectively | + +**Example Code for Setting nDraw Paint Stroke Width:** + +``` +nDraw and paint strokeWidth of the Canvas must be the same. +nDrawHelper.NDrawSetStrokeWidth(( int ) lineWidth ); +paint .setStrokeWidth(( float ) lineWidth ); +``` + +| Return | Parameter | +| ------ | -------------------------------------------------------------------------------- | +| void | NDrawSetStrokeWidth( int lineWidth )
int lineWidth : set nDraw pen thickness | + +**Example Code for Setting Pen Thickness with Pressure of Writing:** + +``` +//not using pressure, NOTSET=-1 +nDrawHelper.NDrawSetMaxStrokeWidthWhenUsingPressure( NOTSET ); +//using pressure +nDrawHelper.NDrawSetMaxStrokeWidthWhenUsingPressure( max_pressure ); +``` + +| Return | Parameter | +| ------ | ------------------------------------------------------------------------------------------------------------------------------- | +| void | NDrawSetMaxStrokeWidthWhenUsingPressure( int max_pressure )
int max_pressure : set maximum pen thickness when using pressure | + +**Example Code for Setting nDraw Paint Color:** + +``` +nDraw and paint color of the canvas must be the same. +nDrawHelper.NDrawSetPaintColor(Color. BLACK ); +paint .setColor(Color. BLACK ); +``` + +| Return | Parameter | +| ------ | ---------------------------------------------------------------------- | +| void | NDrawSetPaintColor( int color )
int color : set nDraw paint color | + +**Example Code for Changing Update Mode of Writing** + +``` +public static boolean isPenUpdateModeDU() { +return SystemProperties.get( "ro.product.hardwareType" , "" ).equals( "ED0Q00" ); +} +// update_mode initial +if (isPenUpdateModeDU()) { + setRefreshMode( UPDATE_MODE_PARTIAL_DU ); +} else { + setRefreshMode( UPDATE_MODE_PARTIAL_A2 ); +} +public void setRefreshMode( int refresh_mode) { + refreshMode = refresh_mode; + nDrawHelper.NDrawSetUpdateMode(refresh_mode); +} +``` + +| Return | Parameter | +| ------- | ------------------------------------------------------------------------------------- | +| boolean | isPenUpdateModeDU()
no parameter; it will return true if device is "ED0Q00" | +| void | setRefreshMode(int refresh_mode)
int refresh_mode: set update mode for writing | +| void | NDrawSetUpdateMode(int refresh_mode)
int refresh_mode: set update mode of writing | + +**Example Code for Setting Orientation of Writing Area** + +``` +private NtxView myNewView ; +myNewView .setCurrentRotation(getRequestedOrientation()); +… +public void setCurrentRotation( int mCurrent_Rotation) { +this . mCurrentRotation = mCurrent_Rotation; +nDrawHelper. NDrawSetInputRotation ( mCurrentRotation ); +} +``` + +| Return | Parameter | +| ------ | -------------------------------------------------------------------------------------------------------- | +| void | NDrawSetInputRotation(int mCurrentRotation );
int mCurrentRotation: set orientation of writing area | + +**Example Code for Taking Screenshots of Writing Area and Entire Screen** + +``` +nDrawHelper.NDrawSaveSignature(); +``` + +| Return | Parameter | +| ---------------------------------------- | --------------------------------------------------------------------------------------------------- | +| void | NDrawSaveSignature()
no parameter; take screenshots of writing area and entire screen, and save | +| them(.png) to root directory of SD-Card. | + +**Example Code for Setting Time Duration of Dropping Frames** + +``` +nDrawHelper.NDrawDropFrames(400000000); +``` + +| Return | Parameter | +| ------ | --------------------------------------------------------------------------------------------- | +| void | NDrawDropFrames( long nanosecond )
long nanosecond: set time duration of dropping frames. | + +# Appendix + +**Refresh Control Broadcast Receiver** +In order to improve EPD scrolling display performance, we have adopted some global eink +control strategies in framework. To ensure that your apps would not be influenced by those +strategies, you have to change eink control permission value, example code is as follows. + +**Example Code for Changing Eink Control Permission Value** + +``` +@Override +protected void onResume() { +super .onResume(); +changeEinkControlPermission( true );//not be influenced by strategies in framework +} +@Override +protected void onPause() { +super .onPause(); +changeEinkControlPermission( false );//be influenced by strategies in framework +} +private void changeEinkControlPermission( boolean isForNtxAppsOnly) { +Intent changePermissionIntent = new Intent( "ntx.eink_control.CHANGE_PERMISSION" ); +changePermissionIntent.putExtra( "isPermissionNtxApp" , isForNtxAppsOnly); +sendBroadcast(changePermissionIntent); +} +``` + +Using Intent( "ntx.eink_control. GLOBAL_REFRESH " ), we can switch to and keep one +refresh mode until we send broadcast to switch to another one. Example codes are as follows. + +**Example Code for Changing Global Refresh Mode to +UPDATE_MODE_GLOBAL_FULL_A2_WITH_DITHER** + +``` +Intent myIntent = new Intent( "ntx.eink_control. GLOBAL_REFRESH " ); +myIntent.putExtra( "updatemode" ,NtxView. UPDATE_MODE_GLOBAL_FULL_A2_WITH_DIT +HER ); +myIntent.putExtra( "commandFromNtxApp" , true ); +sendBroadcast(myIntent); +``` + +**Example Code for Changing Global Refresh Mode to +UPDATE_MODE_GLOBAL_RESET** + +``` +Intent myIntent = new Intent( "ntx.eink_control. GLOBAL_REFRESH " ); +myIntent.putExtra( "updatemode" ,NtxView. UPDATE_MODE_GLOBAL_RESET ); +myIntent.putExtra( "commandFromNtxApp" , true ); +sendBroadcast(myIntent); +Using Intent( "ntx.eink_control. QUICK_REFRESH " ), we can temporarily do some +refresh, especially Full Refresh, just one time and then restore refresh mode immediately. +``` + +**Example Code for Doing a Full Refresh** + +``` +Intent myIntent = new Intent( "ntx.eink_control. QUICK_REFRESH " ); +myIntent.putExtra( "updatemode" ,NtxView. UPDATE_MODE_FULL_GC16 ); +myIntent.putExtra( "commandFromNtxApp" , true ); +sendBroadcast(myIntent); +``` + +Sometimes we want to drop animation frames to decrease eink flash, example codes are as +follows. + +**Example Code for Setting Time Duration of Dropping Frames** + +``` +Intent myIntent = new Intent( "ntx.eink_control.DropFrames" ); +myIntent.putExtra( "period" , 1900000000L );//1.9 Seconds +myIntent.putExtra( "commandFromNtxApp" , true ); +sendBroadcast(myIntent); +Example Code for Resetting Time Duration of Dropping Frames +Intent myIntent = new Intent( "ntx.eink_control.DropFrames" ); +myIntent.putExtra( "period" , 0L );//0 Seconds +myIntent.putExtra( "commandFromNtxApp" , true ); +sendBroadcast(myIntent); +``` + +**2-Step-Suspend** + +This feature is a method for power saving on the MobiScribe products +with eInk panel. When this function is enabled, the system will keep +the current screen and enter suspend after the user has not acted for +a while. Please refer to the following sample code to control this +function. +NOTE : When the user has an action, the system will be woken up +from the suspend and it will take a very short time. It’s suitable for +reader apps to flip pages. There will be a delay in the first stroke if +using this feature in the handwriting apps. + +``` +/** +* Control the 2-Step-Suspend for MobiScribe eInk devices +* +* @param state +* 1 is enable. +* 0 is disable. +*/ +private void PowerEnhanceSet(int state ) { +try { +Settings.System.putInt(mContext.getContentResolver(), "power_enhance_enable", state ); +} catch (Exception e) { +e.printStackTrace(); +} +} +``` + +NOTE : Add the permission “WRITE_SETTINGS� in the AndroidManifest.xml + +20 + +# adb Setup + +1. USB Driver Installation for Windows 7
+ +- Download the driver from the Link , and install it. + +2. Download Android SDK platform-tools
+ +- To visit the Android Studio website , USER GUIDE -> Release + Note -> SDK Platform Tools , and to download the platform-tools + package. + +3. Add Android Vendor ID + +- Windows 7 64-bit above version: + - Make a “.android� directory at C:\Users\(user-name)\ + - Create a file “adb_usb.ini� in “.android� directory. Add the + content : 0x1f85, then save and close it. +- Ubuntu 14.05 64-bit version: + - Make a “.android� directory at /home/(user-name)/ + - Create a file “adb_usb.ini� in “.android� directory. Add the + content : 0x1f85, then save and close it. + +4. Execute adb server
+ Plug the usb link of your device to the computer. Extract the + download platform-tools package. Open the command line shell.
+ Execute the following commands : + +``` +adb kill-server +adb start-server +adb devices +``` + +Eink Features/Waveforms + +## Standard(4 bits) Waveform Modes + +| Mode | Description | +| --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| INIT (Global update WF) | Initialize is used to completely clear the display, if it's left in an unknown state (i.e. if the previous image has been lost by a reboot) | +| DU (Local update WF) | Direct update Non-flashing wave form that can be used to update. It can update any changed graytone pixel to black or white only. This waveform can be used for pen or other fast menu updates. It only updates changed pixels. | +| GC (Global update WF) | Grayscale Clear, 16 levels A "flashy" waveform used for 16 level grayscale images. This provides the best image appearance. All the pixels are updated or cleared. | +| A2 (Local update WF) | Animation, 2 Levels is a non-flashing waveform that can be used for fast updates and simple animation. This waveform support black & white updates only. Image quality and ghosting is reduced in exchange for the quicker response time. It only updates changed pixels and recommend a white image transition from 4bit to 1bit into A2 and 1bit to 4bit out of A2 mode | +| GL (Local update WF when white to white, Global update when 16 gray levels) | The GL waveform is used to update anti-aliased text with reduced flash. GL should be used only with Full Display Update (UPD_FULL), the entire display except pixels staying in white will update as the new image is written. The GL waveform has 16 unique gray levels. | + +## Regal (5 bits) Waveform Modes + +Standard WF mode included + +| Mode | Description | +| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| GLR* (Local update WF) | Grayscale Local, 16 Levels, Regals A variation of the GL low flash waveform with improved edge ghost performance. 16 Grayscale levels used for anti-aliased text update and other images with white background. This should be used with full display update. All pixels except pixels staying white will update. | +| GLD* (Local update WF) | Grayscale Local, 16 Levels A variation of the GL low flash waveform with improved edge and areal ghost performance. 16 grayscale levels used for anti-aliased text update and other images with white background. This should be used with full display update. All pixels except pixels staying white will update. | + +## UI Design with waveform mode + +| | Features | Example Use Cases | WF Mode | Comments | +| ---------------- | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Content Focused | Text Page Updates | - Clock/digit time - Calendar - Turning pages in a book or document | Regal, GL | - Quality content with reduced flashiness during page updates; - Primarily for white background - May need GC to update periodically | +| Content Focused | Pictures | - Launcher page turn - Gallery - Book covers - Screen savers - Illustrations - Home screens | GC | - When you want best image quality - More flashing but less ghosting | +| Content Focused | Entering a new book/application, natural user transitions | - After a submenu/book has been selected from a menu or going from a submenu/book to menu - Menu to submenu - Choosing between applications | GC | - Take advantage of natural breaks in the information flow to use GC to clear ghost buildup - When changing menus on screen | +| Informational | Icons flashing or updating | Battery charging, page loading, WiFi connection, download, etc | DU | - Use black and white icons to take advantage of faster update time with DU mode - Can be small in a title/header bar area or Large in middle of display | +| Informational | Overlaying content (pop-up menus, notifications, dialog boxes) | - Low battery warning - Confirming a user decision - Quick view | DU | For best quality, bring up dialog/pop-up with DU and erase dialog/pop-up with GC | +| Startup/shutdown | First time device is powered on, Loss of power, System freeze | When display is in unknown state | INIT | - Longest update time and restarts display - Not a DC balanced waveform so use sparingly | +| Startup/shutdown | Start up from known image | - Coming out of screen saver - Starting from known shut-down state | GC | Because image is known, do not need to use INIT | +| Startup/shutdown | Device shutdown; sleep mode | Power down with image on display | GC | Recommendation to go into a known state | + +| | Features | Example Use Cases | WF Mode | Comments | +| ----------- | :-----------------------------------------------: | ------------------------------------------------------------------------------ | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Interactive | Menu Selection (Response to user input) | Black/White Options: Radio buttons, underlining, Box outline, invert text etc. | DU | | +| Interactive | Menu Selection (Response to user input) | Grayscale Option: Highlight selection in gray | GC | Box Selection; could be more flashy | +| Interactive | Keyboard/Text Input | Search box entry password entry | DU | if anti-aliased text is desired, can play around with combined DU/GC update | +| Interactive | Keyboard response | Button Key acknowledgement | DU | Inversion of selected key Use inherent flashiness of GC to redisplay the button | +| Interactive | Browsing books, apps, or menu options (graphical) | Selection | GC | Recommend doing pipeline to show transitions | +| Interactive | Fast Page turn | Scanning through Books/Documents | A2 | Reduced Contrast - may be more ghostly; Need to start and end with white; GC should follow to display a quality image | +| Interactive | Fast Page turn | Scanning through Books/Documents | DU | Not as fast as A2 Better image quality | +| Interactive | Panning | Navigating zoomed text/images Navigating maps Camera view finder | A2 | Achieve grayscale through dithering | +| Interactive | Highlighting | Text highlighting | DU GC DU+GC | inversion of text with DU Grayscale highlighting with GC Combination of both: DU for fast initial user response , followed by GC to change to grayscale? | diff --git a/third_party/enote-sdk/Sample Code/Painter/app/app.iml b/third_party/enote-sdk/Sample Code/Painter/app/app.iml new file mode 100755 index 0000000..939b581 --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/app/app.iml @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/third_party/enote-sdk/Sample Code/Painter/app/build.gradle b/third_party/enote-sdk/Sample Code/Painter/app/build.gradle new file mode 100755 index 0000000..43603c3 --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/app/build.gradle @@ -0,0 +1,29 @@ +apply plugin: 'com.android.application' +android { + compileSdkVersion 15 + buildToolsVersion "23.0.2" + + defaultConfig { + applicationId "ntx.painter" + minSdkVersion 15 + targetSdkVersion 15 + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' + } + } + +} + +dependencies { +// provided files('src/main/libs/classes.jar') + compile files('src/main/libs/javalib.jar') + compile files('src/main/libs/ntx_android_bt_net_classes.jar') + compile files('src/main/libs/ntx_android_graphics_classes.jar') + compile files('src/main/libs/ntx_android_os_classes.jar') + compile files('src/main/libs/ntx_android_view_classes.jar') + +} \ No newline at end of file diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/AndroidManifest.xml b/third_party/enote-sdk/Sample Code/Painter/app/src/main/AndroidManifest.xml new file mode 100755 index 0000000..f6154e7 --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/app/src/main/AndroidManifest.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/java/ntx/note/asynctask/BitmapWorkerTask.java b/third_party/enote-sdk/Sample Code/Painter/app/src/main/java/ntx/note/asynctask/BitmapWorkerTask.java new file mode 100755 index 0000000..1e5adbe --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/app/src/main/java/ntx/note/asynctask/BitmapWorkerTask.java @@ -0,0 +1,65 @@ +package ntx.note.asynctask; + +import java.lang.ref.WeakReference; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.AsyncTask; +import android.widget.ImageView; + +public class BitmapWorkerTask extends AsyncTask { + private final WeakReference imageViewReference; + private int reqWidth = 0; + private int reqHeight = 0; + + public BitmapWorkerTask(ImageView imageView, int reqWidth, int reqHeight) { + // Use a WeakReference to ensure the ImageView can be garbage collected + imageViewReference = new WeakReference(imageView); + this.reqWidth = reqWidth; + this.reqHeight = reqHeight; + } + + @Override + protected Bitmap doInBackground(String... params) { + + if (!params[0].equals("")) { + return resizeBitmapFromFile(params[0], reqWidth, reqHeight); + } + return null; + } + + @Override + protected void onPostExecute(Bitmap bitmap) { + final ImageView imageView = imageViewReference.get(); + if (imageView != null && bitmap != null) { + imageView.setImageBitmap(bitmap); + } + } + + public Bitmap resizeBitmapFromFile(String path, int reqWidth, int reqHeight) { + // First decode with inJustDecodeBounds=true to check dimensions + final BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + BitmapFactory.decodeFile(path, options); + + // Calculate inSampleSize Raw height and width of image + final int height = options.outHeight; + final int width = options.outWidth; + options.inPreferredConfig = Bitmap.Config.RGB_565; + int inSampleSize = 1; + + if (height > reqHeight) { + inSampleSize = Math.round((float) height / (float) reqHeight); + } + + int expectedWidth = width / inSampleSize; + + if (expectedWidth > reqWidth) { + inSampleSize = Math.round((float) width / (float) reqWidth); + } + options.inSampleSize = inSampleSize; + options.inJustDecodeBounds = false; + + return BitmapFactory.decodeFile(path, options); + } +} diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/java/ntx/painter/ImagePickerActivity.java b/third_party/enote-sdk/Sample Code/Painter/app/src/main/java/ntx/painter/ImagePickerActivity.java new file mode 100755 index 0000000..4d224d3 --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/app/src/main/java/ntx/painter/ImagePickerActivity.java @@ -0,0 +1,315 @@ +package ntx.painter; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Intent; +import android.content.res.Configuration; +import android.net.Uri; +import android.os.AsyncTask.Status; +import android.os.Bundle; +import android.os.Environment; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.GridView; +import android.widget.ImageView; +import android.widget.SimpleAdapter; +import android.widget.TextView; +import android.widget.Toast; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import ntx.note.asynctask.BitmapWorkerTask; + +@SuppressLint("DefaultLocale") +public class ImagePickerActivity extends Activity implements OnItemClickListener { + private final static String TAG = "ImagePickerActivity"; + + public String[] searchImageType = new String[]{".png", ".jpg", ".jpeg", ".bmp"}; //auto list files + + private final static int NumPerPage_Portrait = 9; //this should be fit real status + private final static int NumPerPage_Landscape = 8; //this should be fit real status + + private final static int GridView_Landscape_height_6Inch = 830; + private final static int GridView_Landscape_height_13Inch = 930; + + private int numPerPage = 0; //this should be fit real status + + protected File sdcardDir, externalCardDir = null; + + private GridView fileGrid; + private SimpleAdapter simpleAdapter; + + private List resultPath = new ArrayList(); + private List> items = new ArrayList>(); + + private TextView txtv_pageinfo; + private ImageView imgv_pre_page, imgv_next_page; + private int totalPage, currentPage = 0; + public BitmapWorkerTask[] asyncTask = new BitmapWorkerTask[NumPerPage_Portrait]; + + public final String PATH_SDCARD = Environment.getExternalStorageDirectory().getPath(); + + @Override + public void onCreate(Bundle savedInstanceState) { + + super.onCreate(savedInstanceState); + setContentView(R.layout.image_picker); + + int display_mode = getResources().getConfiguration().orientation; + if (display_mode == Configuration.ORIENTATION_PORTRAIT) { + numPerPage = NumPerPage_Portrait; + } else { + numPerPage = NumPerPage_Landscape; + } + + sdcardDir = new File(PATH_SDCARD); + searchFiles(sdcardDir); + + Collections.sort(resultPath, new SortIgnoreCase()); + + totalPage = getTotalPage(); + if (currentPage == 0) + currentPage = 1; + + //add into items for showing + updateItems(); + + fileGrid = (GridView) findViewById(R.id.filepicker_file_grid); + + + if (display_mode == Configuration.ORIENTATION_PORTRAIT) { + + } else { + + ViewGroup.LayoutParams layoutParams = fileGrid.getLayoutParams(); + if (NtxView.isEinkHandWritingHardwareType() && NtxView.isEink6InchHardwareType()) { + layoutParams.height = GridView_Landscape_height_6Inch; + } else { + layoutParams.height = GridView_Landscape_height_13Inch; + } + + fileGrid.setLayoutParams(layoutParams); + } + + simpleAdapter = new SimpleAdapter(this, + items, R.layout.image_picker_item, new String[]{"image", "text"}, + new int[]{R.id.picker_image, R.id.picker_text}) { + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + + int mWidth = 205 * 2; + int mHeight = 150 * 2; + if (convertView == null) { + convertView = super.getView(position, convertView, parent); + } + + final TextView nameView = (TextView) convertView.findViewById(R.id.picker_text); + + final int indexNameS1 = items.get(position).get("image").toString().lastIndexOf('/') + 1; + final String filenameS1 = ((indexNameS1 > 0) ? items.get(position).get("image").toString().substring(indexNameS1).toLowerCase().intern() : ""); + nameView.setText(filenameS1); + + final ImageView coverView = (ImageView) convertView.findViewById(R.id.picker_image); + if (position > 0) { + coverView.setImageBitmap(null); + } + + if (asyncTask[position] != null && asyncTask[position].getStatus().equals(Status.RUNNING)) { + asyncTask[position].cancel(true); + } + + asyncTask[position] = new BitmapWorkerTask(coverView, mWidth, mHeight); + asyncTask[position].execute(items.get(position).get("image").toString()); + return convertView; + } + }; + fileGrid.setAdapter(simpleAdapter); + fileGrid.setOnItemClickListener(this); + + if (resultPath.isEmpty()) { + Toast.makeText(ImagePickerActivity.this, R.string.image_pick_no_image, Toast.LENGTH_LONG).show(); + } + + setTitle(R.string.image_pick_title); + + txtv_pageinfo = (TextView) findViewById(R.id.page_info); + imgv_pre_page = (ImageView) findViewById(R.id.imgb_pre_page); + imgv_next_page = (ImageView) findViewById(R.id.imgb_next_page); + + imgv_pre_page.setOnClickListener(instantKeyListener); + imgv_next_page.setOnClickListener(instantKeyListener); + + } + + private OnClickListener instantKeyListener = new OnClickListener() { + // TODO + @Override + public void onClick(final View v) { + switch (v.getId()) { + case R.id.imgb_pre_page: + currentPage--; + if (currentPage <= 0) + currentPage = totalPage; + + txtv_pageinfo.setText(currentPage + " of " + totalPage); + updateItems(); + simpleAdapter.notifyDataSetChanged(); + break; + case R.id.imgb_next_page: + currentPage++; + if (currentPage > totalPage) + currentPage = 1; + + txtv_pageinfo.setText(currentPage + " of " + totalPage); + updateItems(); + simpleAdapter.notifyDataSetChanged(); + break; + default: + finish(); + break; + } + } + }; + + @Override + public void onItemClick(AdapterView adapter, View view, int pos, long id) { + int realPos = 0; + + realPos = numPerPage * (currentPage - 1) + pos; + String path = resultPath.get(realPos); + final File f = new File(path); + + if (f.isFile()) + pickFile(f); + } + + + @Override + protected void onPause() { + super.onPause(); + changeEinkControlPermission(false); + } + + private void pickFile(File file) { + Intent intent = getIntent(); + intent.setData(Uri.fromFile(file)); + setResult(RESULT_OK, intent); + finish(); + } + + //scan all the specific type files. ex:*.note + public void searchFiles(File file) { + File[] the_Files = file.listFiles(); + + if (the_Files == null) + return; + + //search all dirs and files + for (File tempF : the_Files) { + if (tempF.isDirectory()) { + if (!tempF.isHidden()) + searchFiles(tempF); + } else { + try { + boolean isImage = false; + //compare file. if the key is matched, return value > -1. + for (String type : searchImageType) { + + final int index = tempF.getPath().lastIndexOf('.'); + final String myExtension = ((index > 0) ? tempF.getPath().substring(index).toLowerCase().intern() : ""); + + if (myExtension.equals(type) && tempF.getName().substring(0, 1).equals(".") == false) { + isImage = true; + break; + } + } + if (isImage) { + //add matched path into array + resultPath.add(tempF.getPath()); + } + } catch (Exception e) { + Toast.makeText(ImagePickerActivity.this, "error - searching image files.", Toast.LENGTH_LONG).show(); + } + } + } + + } + + @Override + protected void onResume() { + super.onResume(); + changeEinkControlPermission(true); + + // update page info + totalPage = getTotalPage(); + if (currentPage == 0) + currentPage = 1; + txtv_pageinfo.setText(currentPage + " of " + totalPage); + + if (totalPage == 1) { //only one page + txtv_pageinfo.setVisibility(View.INVISIBLE); + imgv_pre_page.setVisibility(View.INVISIBLE); + imgv_next_page.setVisibility(View.INVISIBLE); + } else { + txtv_pageinfo.setVisibility(View.VISIBLE); + imgv_pre_page.setVisibility(View.VISIBLE); + imgv_next_page.setVisibility(View.VISIBLE); + } + } + + private void changeEinkControlPermission(boolean isForNtxAppsOnly) { + Intent changePermissionIntent = new Intent("ntx.eink_control.CHANGE_PERMISSON"); + changePermissionIntent.putExtra("isPermissionNtxApp", isForNtxAppsOnly); + sendBroadcast(changePermissionIntent); + } + + // calculate total page + private int getTotalPage() { + int totalpage = resultPath.size() / (numPerPage); + + if (resultPath.size() % (numPerPage) != 0 | resultPath.size() / (numPerPage) == 0) + totalpage++; + return totalpage; + } + + // update items for showing + private void updateItems() { + if (items.size() != 0) + items.clear(); + + for (int i = numPerPage * (currentPage - 1); i < numPerPage * currentPage; i++) { + if (i >= resultPath.size()) + break; + + Map item = new HashMap(); + item.put("image", resultPath.get(i)); + items.add(item); + } + } + + public class SortIgnoreCase implements Comparator { + @Override + public int compare(Object o1, Object o2) { + String s1 = (String) o1; + String s2 = (String) o2; + + final int indexNameS1 = s1.lastIndexOf('/'); + final String filenameS1 = ((indexNameS1 > 1) ? s1.substring(indexNameS1).toLowerCase().intern() : ""); + + final int indexNameS2 = s2.lastIndexOf('/'); + final String filenameS2 = ((indexNameS2 > 1) ? s2.substring(indexNameS2).toLowerCase().intern() : ""); + + return filenameS1.toLowerCase().compareTo(filenameS2.toLowerCase()); + } + } +} \ No newline at end of file diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/java/ntx/painter/MainActivity.java b/third_party/enote-sdk/Sample Code/Painter/app/src/main/java/ntx/painter/MainActivity.java new file mode 100755 index 0000000..41df23f --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/app/src/main/java/ntx/painter/MainActivity.java @@ -0,0 +1,843 @@ + +package ntx.painter; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.net.Uri; +import android.os.Bundle; +import android.os.Environment; +import android.os.Handler; +import android.os.Message; +import android.os.SystemClock; +import android.provider.ContactsContract; +import android.provider.Settings; +import android.text.TextUtils; +import android.text.format.Time; +import android.util.DisplayMetrics; +import android.util.Log; +import android.view.Display; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.OrientationEventListener; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.EditText; +import android.widget.ImageButton; +import android.widget.LinearLayout; +import android.widget.Spinner; +import android.widget.TextView; +import android.widget.Toast; +import android.hardware.SensorManager; + +import junit.framework.Assert; + +import ntx.draw.nDrawHelper; +import ntx.painter.NtxView.PenType; + +import java.io.File; +import java.util.Timer; +import java.util.TimerTask; + +public class MainActivity extends Activity { + + private final static String TAG = "MainActivity"; + + private Context mContext; + private NtxView myNewView; + private LinearLayout mainLayout, painterViewLayout; + + Timer mTimer; + private long fixed_full_refresh_time = 3 * 60 * 1000; + + private String strSaveImgPath; + + private Handler mHandler = new Handler(); + + protected ReselectSpinner thicknessSpinner; + protected ReselectSpinner mPenTypeSpinner; + private ImageButton refreshAButton, refreshButton; + private ImageButton thicknessButton, calibrationButton, cleanButton, rotateButton, backgroundButton, saveButton, infoButton; + private ImageButton mPenTypeButton; + protected TextView txtvThicknessNum; + protected TextView mTxtPenStyle; + protected Spinner mHorizontalSpinner, mVerticalSpinner, refreshModeSpinner; + private boolean isRefreshModeSpinnerInitRun, isThicknessSpinnerInitRun, isPenTypeSpinnerInitRun; + + private Button backgroundBlackButton, backgroundWhiteButton; + private Button autoDrawButton; + private CheckBox chkbox_finger_touch; + Dialog mDialog; + + AlertDialog.Builder mBuilder; + AlertDialog dialog; + + private int calHorizontalPosition, calVerticalPosition; + + private int initHorizontalPosition, initVerticalPosition; + private int isSavedInteger=0; + + + static int pen_offset_x, pen_offset_y; + + + private int[] thicknessChoices; + private String[] mPentypeChoices; + + private boolean refresh_flag = false; + + private WindowManager mWindowManager; + private Display mDisplay; + + private int getNavigationBarHeight() { + Resources resources = mContext.getResources(); + int resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android"); + int height = resources.getDimensionPixelSize(resourceId); + + return height; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mContext = getApplicationContext(); + + setContentView(R.layout.main); + mainLayout = (LinearLayout) findViewById(R.id.main_layout); + + thicknessSpinner = (ReselectSpinner) findViewById(R.id.toolbox_thickness_spinner); + mPenTypeSpinner = (ReselectSpinner) findViewById(R.id.pen_type_spinner); + thicknessButton = (ImageButton) findViewById(R.id.toolbox_thickness_button); + mPenTypeButton = (ImageButton) findViewById(R.id.pen_type_button); + txtvThicknessNum = (TextView) findViewById(R.id.toolbox_thickness_number); + mTxtPenStyle = (TextView) findViewById(R.id.pen_type_string); + calibrationButton = (ImageButton) findViewById(R.id.toolbox_calibration); + + cleanButton = (ImageButton) findViewById(R.id.toolbox_clean); + rotateButton = (ImageButton) findViewById(R.id.toolbox_rotate); + refreshModeSpinner = (Spinner) findViewById(R.id.toolbox_refresh_mode_spinner); + backgroundButton = (ImageButton) findViewById(R.id.toolbox_background); + saveButton = (ImageButton) findViewById(R.id.toolbox_save); + infoButton = (ImageButton) findViewById(R.id.toolbox_info); + refreshAButton = (ImageButton) findViewById(R.id.toolbox_full_refreshA); + refreshButton = (ImageButton) findViewById(R.id.toolbox_full_refresh); + + backgroundWhiteButton = (Button) findViewById(R.id.btn_bg_white); + backgroundBlackButton = (Button) findViewById(R.id.btn_bg_black); + chkbox_finger_touch = (CheckBox) findViewById(R.id.chkbox_finger_touch); + autoDrawButton = (Button) findViewById(R.id.auto_draw); + + painterViewLayout = (LinearLayout) findViewById(R.id.painter_view); + + myNewView = new NtxView(this); + painterViewLayout.addView(myNewView); + + myNewView.getBottomHeight(getNavigationBarHeight()); + myNewView.setCurrentRotation(getRequestedOrientation()); + + thicknessButton.setOnClickListener(mOnClickListener); + mPenTypeButton.setOnClickListener(mOnClickListener); + calibrationButton.setOnClickListener(mOnClickListener); + cleanButton.setOnClickListener(mOnClickListener); + rotateButton.setOnClickListener(mOnClickListener); + backgroundButton.setOnClickListener(mOnClickListener); + saveButton.setOnClickListener(mOnClickListener); + infoButton.setOnClickListener(mOnClickListener); + refreshAButton.setOnClickListener(mOnClickListener); + refreshButton.setOnClickListener(mOnClickListener); + + thicknessChoices = getResources().getIntArray(R.array.dlg_thickness_values); + String[] thickness_spinner_string_table = new String[thicknessChoices.length]; + for (int i = 0; i < thicknessChoices.length; i++) { + if (i == thicknessChoices.length - 1) + thickness_spinner_string_table[i] = (String) "Pressure"; + else + thickness_spinner_string_table[i] = (String) String.valueOf(thicknessChoices[i]); + } + ArrayAdapter mAdapter = new ArrayAdapter( + mContext, + R.layout.toolbox_spinner_item, + thickness_spinner_string_table); + mAdapter.setDropDownViewResource(R.layout.toolbox_spinner_item); + thicknessSpinner.setAdapter(mAdapter); + isThicknessSpinnerInitRun = true; + thicknessSpinner.setOnItemSelectedListener(mOnItemSelectedListener); + setToolboxThicknessValue(myNewView.getPenThickness()); + + //pen type + mPentypeChoices = getResources().getStringArray(R.array.pen_type_values); + + mAdapter = new ArrayAdapter( + mContext, + R.layout.toolbox_spinner_item, + mPentypeChoices); + mAdapter.setDropDownViewResource(R.layout.toolbox_spinner_item); + mPenTypeSpinner.setAdapter(mAdapter); + isPenTypeSpinnerInitRun = true; + mPenTypeSpinner.setOnItemSelectedListener(mOnItemSelectedListener); + + String[] refresh_mode_spinner_string_table = getResources().getStringArray(R.array.toolbox_refresh_mode); + mAdapter = new ArrayAdapter( + mContext, + R.layout.toolbox_spinner_item, + refresh_mode_spinner_string_table); + mAdapter.setDropDownViewResource(R.layout.toolbox_spinner_item); + refreshModeSpinner.setAdapter(mAdapter); + isRefreshModeSpinnerInitRun = true; + refreshModeSpinner.setOnItemSelectedListener(mOnItemSelectedListener); + refreshModeSpinner.setOnTouchListener(mSpinnerOnTouchListener); + setToolBoxRefreshModeCurrentValue(); + + backgroundWhiteButton.setOnClickListener(mOnClickListener); + backgroundBlackButton.setOnClickListener(mOnClickListener); + autoDrawButton.setOnClickListener(mOnClickListener); + + chkbox_finger_touch.setOnClickListener(new CheckBox.OnClickListener() { + @Override + public void onClick(View v) { + myNewView.setFingerTouch(chkbox_finger_touch.isChecked()); + } + }); + + + refreshAButton.setOnTouchListener(new View.OnTouchListener(){ + @Override + public boolean onTouch(View v, MotionEvent event) { + if(event.getAction() == MotionEvent.ACTION_DOWN) + { + refreshAButton.setImageResource(R.color.black); + } + + return false; + } + }); + + + + mBuilder=new AlertDialog.Builder(MainActivity.this); + View mView = LayoutInflater.from(MainActivity.this).inflate(R.layout.dialog_calibration, null); + mBuilder.setTitle("Calibration"); + + mHorizontalSpinner = (Spinner) mView.findViewById(R.id.horizontal_offset_spinner); + mVerticalSpinner = (Spinner) mView.findViewById(R.id.vertical_offset_spinner); + + ArrayAdapter adapterHorizontal = new ArrayAdapter(MainActivity.this, + android.R.layout.simple_spinner_item, + getResources().getStringArray(R.array.horizontal_offset_list)); + ArrayAdapter adapterVertical = new ArrayAdapter(MainActivity.this, + android.R.layout.simple_spinner_item, + getResources().getStringArray(R.array.vertical_offset_list)); + + + adapterHorizontal.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + adapterVertical.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + + mHorizontalSpinner.setAdapter(adapterHorizontal); + mVerticalSpinner.setAdapter(adapterVertical); + + mHorizontalSpinner.setOnItemSelectedListener(mOnItemSelectedListener); + mVerticalSpinner.setOnItemSelectedListener(mOnItemSelectedListener); + + + + initHorizontalPosition=(adapterHorizontal.getCount()-1)/2; + initVerticalPosition=(adapterHorizontal.getCount()-1)/2; + + isSavedInteger=Settings.System.getInt(getContentResolver(),"isSavedInteger",999); + + if(isSavedInteger==1){ + + calHorizontalPosition=Settings.System.getInt(getContentResolver(),"calHorizontalPosition",0); + calVerticalPosition=Settings.System.getInt(getContentResolver(),"calVerticalPosition",0); + + + }else{ + + calHorizontalPosition=initHorizontalPosition; + calVerticalPosition=initVerticalPosition; + + } + + mHorizontalSpinner.setSelection(calHorizontalPosition); + mVerticalSpinner.setSelection(calVerticalPosition); + + + final int[] horizontal_offset_int_table=getResources().getIntArray(R.array.horizontal_offset); + final int[] vertical_offset_int_table=getResources().getIntArray(R.array.vertical_offset); + + + pen_offset_x=horizontal_offset_int_table[calHorizontalPosition]; + pen_offset_y=vertical_offset_int_table[calVerticalPosition]; + + + myNewView.setInputOffset(pen_offset_x, pen_offset_y); + + + mBuilder.setPositiveButton("OK", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + + + + calHorizontalPosition=mHorizontalSpinner.getSelectedItemPosition(); + calVerticalPosition=mVerticalSpinner.getSelectedItemPosition(); + + pen_offset_x=horizontal_offset_int_table[calHorizontalPosition]; + pen_offset_y=vertical_offset_int_table[calVerticalPosition]; + + + myNewView.setInputOffset(pen_offset_x, pen_offset_y); + + + + Settings.System.putInt(getContentResolver(),"calHorizontalPosition", calHorizontalPosition); + Settings.System.putInt(getContentResolver(),"calVerticalPosition", calVerticalPosition); + Settings.System.putInt(getContentResolver(),"isSavedInteger",1); + + + dialogInterface.dismiss(); + + + } + }); + + + mBuilder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + + + + mHorizontalSpinner.setSelection(calHorizontalPosition); + mVerticalSpinner.setSelection(calVerticalPosition); + dialogInterface.dismiss(); + + + + + } + }); + + + + + mBuilder.setView(mView); + + dialog = mBuilder.create(); + dialog.setCancelable(false); + + mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); + mDisplay = mWindowManager.getDefaultDisplay(); + + nDrawHelper.NDrawInit(this); + + + } + + @Override + public void onBackPressed() { + super.onBackPressed(); + changeEinkControlPermission(false); + Log.d(TAG,"onBackPressed"); + nDrawHelper.NDrawSkia2FBUnInit(); + //myNewView.onBackPressed(); + int pid = android.os.Process.myPid(); + android.os.Process.killProcess(pid); + } + + @Override + protected void onResume() { + super.onResume(); + changeEinkControlPermission(true); + myNewView.onResume(); + + mTimer = new Timer(); + mTimer.schedule(new TimerTask() { + @Override + public void run() { + while (!myNewView.getFullRefreshable()) { + SystemClock.sleep(1000); + } + //RefreshHandler.sendEmptyMessage(1);//Bugfix: show white region when resume from suspend + } + }, 0, fixed_full_refresh_time); + PowerEnhanceSet(1); + + + + if (refresh_flag){ + + changeToA2DitheringMode(); + + mHandler.postDelayed(runInvalidate,2000); + + }else{ + + changeToGlobalReset(); + + } + + + } + + private void changeEinkControlPermission(boolean isForNtxAppsOnly) { + Intent changePermissionIntent = new Intent("ntx.eink_control.CHANGE_PERMISSON"); + changePermissionIntent.putExtra("isPermissionNtxApp", isForNtxAppsOnly); + sendBroadcast(changePermissionIntent); + } + + private Handler RefreshHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case 1: + if (myNewView.isEinkHardwareType()) + myNewView.fullRefresh(mainLayout); + else + mainLayout.invalidate(); + break; + } + } + }; + + private Spinner.OnTouchListener mSpinnerOnTouchListener = new Spinner.OnTouchListener() { + @Override + public boolean onTouch(View view, MotionEvent motionEvent) { + if (motionEvent.getAction() == MotionEvent.ACTION_UP) { + nDrawHelper.NDrawSwitch(false); + } + + return false; + } + }; + + private Button.OnClickListener mOnClickListener = new Button.OnClickListener() { + @Override + public void onClick(View v) { + Log.d(TAG, "onClick"); + nDrawHelper.NDrawSwitch(false); + switch (v.getId()) { + case R.id.toolbox_thickness_button: + //trigger thickness spinner + ((ReselectSpinner) findViewById(R.id.toolbox_thickness_spinner)).performClick(); + break; + case R.id.pen_type_button: + //trigger thickness spinner + ((ReselectSpinner) findViewById(R.id.pen_type_spinner)).performClick(); + break; + case R.id.toolbox_calibration: + + + dialog.show(); + + break; + case R.id.toolbox_clean: + myNewView.clear(); + break; + case R.id.toolbox_rotate: + // set Landscape/ Portrait + startRotate(); + + break; + case R.id.toolbox_background: + + AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this); + builder.setMessage(getString(R.string.wait)); + mDialog = builder.create(); + mDialog.show(); + + new Thread(new Runnable() { + @Override + public void run() { + Intent intent = new Intent(MainActivity.this, ImagePickerActivity.class); + startActivityForResult(intent, REQUEST_CODE_PICK_IMAGE); + } + }).start(); + break; + case R.id.toolbox_save: + Time now = new Time(); + now.setToNow(); + strSaveImgPath = Environment.getExternalStorageDirectory().getPath() + "/painter" + now.format("_%Y%m%d-%H%M%S.png"); + if (myNewView.FileOutput(strSaveImgPath) == 0) { + mDialog = createDialog( + MainActivity.this, + String.format(getString(R.string.toolbox_save_msg_success), strSaveImgPath), + new View.OnClickListener() { + @Override + public void onClick(View v) { + mDialog.dismiss(); + } + }); + mDialog.show(); + } else { + mDialog = createDialog( + MainActivity.this, + String.format(getString(R.string.toolbox_save_msg_fail), strSaveImgPath), + new View.OnClickListener() { + @Override + public void onClick(View v) { + mDialog.dismiss(); + } + }); + mDialog.show(); + } + break; + case R.id.toolbox_info: + mDialog = createDialog( + MainActivity.this, + getString(R.string.msg_info), + new View.OnClickListener() { + @Override + public void onClick(View v) { + mDialog.dismiss(); + } + }); + mDialog.show(); + break; + case R.id.btn_bg_white: + myNewView.setCanvasStyle(1); + myNewView.setBackgroundPath(""); + myNewView.clear(); + break; + case R.id.btn_bg_black: + myNewView.setCanvasStyle(2); + myNewView.setBackgroundPath(""); + myNewView.clear(); + break; + case R.id.toolbox_full_refreshA: + // refreshButton.setImageResource(R.drawable.ic_menu_reset); + if (refresh_flag == false){ + + refresh_flag = true; + + }else if (refresh_flag == true){ + + refresh_flag = false; + } + + + + if (refresh_flag){ + + refreshAButton.setImageResource(R.drawable.ic_menu_admode); + + changeToA2DitheringMode(); + + myNewView.invalidate(); + + }else{ + + refreshAButton.setImageResource(R.drawable.ic_menu_reset); + + changeToGlobalReset(); + + myNewView.invalidate(); + + } + + + break; + + case R.id.toolbox_full_refresh: + + myNewView.invalidate(); + + Intent ac = new Intent("ntx.eink_control.QUICK_REFRESH"); + ac.putExtra("updatemode",NtxView.UPDATE_MODE_FULL_GC16); + ac.putExtra("commandFromNtxApp", true); + sendBroadcast(ac); + + + break; + + + default: + break; + } + } + }; + + + public void changeToA2DitheringMode(){ + + doDuRefresh(); + + Intent a = new Intent("ntx.eink_control.GLOBAL_REFRESH"); + a.putExtra("updatemode",NtxView.UPDATE_MODE_GLOBAL_FULL_A2_WITH_DITHER); + a.putExtra("commandFromNtxApp", true); + sendBroadcast(a); + + } + + private void doDuRefresh(){ + + Intent quickDuRefreshIntent = new Intent("ntx.eink_control.QUICK_REFRESH"); + quickDuRefreshIntent.putExtra("updatemode",NtxView.UPDATE_MODE_FULL_DU_WITH_DITHER); + quickDuRefreshIntent.putExtra("commandFromNtxApp", true); + sendBroadcast(quickDuRefreshIntent); + + } + + + public void changeToGlobalReset(){ + + Intent al = new Intent("ntx.eink_control.GLOBAL_REFRESH"); + al.putExtra("updatemode",NtxView.UPDATE_MODE_GLOBAL_RESET); + al.putExtra("commandFromNtxApp", true); + sendBroadcast(al); + + } + + + + + public static Dialog createDialog(Context context, String msg, View.OnClickListener callbackOk) { + Dialog dialog = new Dialog(context, R.style.dialog_custom); + dialog.setCancelable(false); + dialog.setContentView(R.layout.dialog_custom); + + DisplayMetrics dm = context.getResources().getDisplayMetrics(); + int vWidth = dm.widthPixels; + int vHeight = dm.heightPixels; + LinearLayout ll = (LinearLayout) dialog.findViewById(R.id.lldialog); + ll.getLayoutParams().width = (int) (vWidth * 0.5); + Window dialogWindow = dialog.getWindow(); + WindowManager.LayoutParams lp = dialogWindow.getAttributes(); + dialogWindow.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL); + lp.y = (int) (vWidth * 0.4); + + Button btnOk = (Button) dialog.findViewById(R.id.dialog_button_ok); + btnOk.setOnClickListener(callbackOk); + TextView txtMessage = (TextView) dialog.findViewById(R.id.message); + txtMessage.setText(msg); + return dialog; + } + + private AdapterView.OnItemSelectedListener mOnItemSelectedListener = new AdapterView.OnItemSelectedListener() { + + @Override + public void onItemSelected(AdapterView parent, View item, int position, long id) { + if (parent.getId() == R.id.toolbox_thickness_spinner) { + if (isThicknessSpinnerInitRun) { + isThicknessSpinnerInitRun = false; + return; + } + if (position == thicknessChoices.length - 1) { + myNewView.setPenThicknessWithPressure(true); + setToolboxThicknessValue(); + } else { + int thickness = thicknessChoices[position]; + //save current setting to the customized + thicknessChoices[thicknessChoices.length - 1] = thickness; + if (thickness == myNewView.getPenThickness() && (!myNewView.getPenThicknessWithPressure())) + return; + myNewView.setPenThickness(thickness); + setToolboxThicknessValue(thickness); + } + } else if (parent.getId() == R.id.toolbox_refresh_mode_spinner) { + if (isRefreshModeSpinnerInitRun) { + isRefreshModeSpinnerInitRun = false; + return; + } + int refresh_mode_selected = NtxView.refresh_mode_table[position]; + if (refresh_mode_selected == myNewView.getRefreshMode()) return; + myNewView.setRefreshMode(refresh_mode_selected); + } else if (parent.getId() == R.id.pen_type_spinner) { + if (isPenTypeSpinnerInitRun) { + isPenTypeSpinnerInitRun = false; + return; + } + + int pen_type_selected = NtxView.pen_type_table[position]; + if (pen_type_selected == myNewView.getPenType()) return; + myNewView.setPenType(pen_type_selected); + updateIcon(); + } + } + + @Override + public void onNothingSelected(AdapterView arg0) { + } + + }; + + private void updateIcon() { + //Log.d(TAG, "updateIcon:" + mPentypeChoices[myNewView.getPenType()]); + if ( myNewView.getPenType() == NtxView.PenType.PENCIL.ordinal() ) { + mPenTypeButton.setImageResource(R.drawable.writing_pen_pencil); + + } else if (myNewView.getPenType() == PenType.PEN.ordinal()) { + mPenTypeButton.setImageResource(R.drawable.writing_pen_pen); + + } else if (myNewView.getPenType() == PenType.CHINESE_BRUSH.ordinal()) { + mPenTypeButton.setImageResource(R.drawable.writing_pen_brush); + } + } + + @Override + protected void onPause() { + super.onPause(); + changeEinkControlPermission(false); + myNewView.onPause(); + mTimer.cancel(); + PowerEnhanceSet(0); + + + changeToGlobalReset(); + + + } + + private void startRotate() { + if(getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT){ + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); + } else if(getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE){ + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT); + } else if(getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT){ + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE); + } else if(getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE){ + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + } else{ + //default + // setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + } + myNewView.setCurrentRotation(getRequestedOrientation()); + myNewView.setBackgroundPath(""); + + + } + + public void setToolBoxRefreshModeCurrentValue() { + mHandler.removeCallbacks(runbSetRefreshMode); + mHandler.postDelayed(runbSetRefreshMode, 500); + } + + private Runnable runbSetRefreshMode = new Runnable() { + @Override + public void run() { + setRefreshModeValue(myNewView.getRefreshMode()); + } + }; + + + private Runnable runInvalidate = new Runnable() { + @Override + public void run() { + + + myNewView.invalidate(); + + } + }; + + + + public void setRefreshModeValue(int refresh_mode) { + for (int i = 0; i < NtxView.refresh_mode_table.length; i++) { + if (refresh_mode == NtxView.refresh_mode_table[i]) { + refreshModeSpinner.setSelection(i); + } + } + } + + public void setToolboxThicknessValue() { + setToolboxThicknessValue(0); + } + + public void setToolboxThicknessValue(int thickness) { + for (int i = 0; i < thicknessChoices.length; i++) { + if (thickness == thicknessChoices[i]) { + thicknessSpinner.setSelection(i); + break; + } + } + + if (myNewView.getPenThicknessWithPressure()) { + thicknessButton.setImageResource(R.drawable.ic_menu_thickness_pressure); + txtvThicknessNum.setText("P"); + return; + } + + //update thickness button + if ((thickness >= 9) && (thickness <= 14)) { + thicknessButton.setImageResource(R.drawable.ic_menu_thickness_medium); + } else if (thickness >= 15) { + thicknessButton.setImageResource(R.drawable.ic_menu_thickness_large); + } else { + thicknessButton.setImageResource(R.drawable.ic_menu_thickness_small); + } + + //update thickness number + setThicknessNumText(String.valueOf(thickness)); + + //sync to customized thickness + thicknessChoices[thicknessChoices.length - 1] = thickness; + + } + + public void setThicknessNumText(String mString) { + txtvThicknessNum.setText(mString); + } + + private final static int REQUEST_CODE_PICK_IMAGE = 1; + + @Override + protected void onActivityResult(int requestCode, int resultCode, + Intent intent) { + super.onActivityResult(requestCode, resultCode, intent); + + if (mDialog.isShowing()) + mDialog.dismiss(); + + switch (requestCode) { + case REQUEST_CODE_PICK_IMAGE: + if (resultCode != RESULT_OK) + break; + Uri selectedImage = intent.getData(); + if (selectedImage != null) { + File mFile = new File(selectedImage.getPath()); + myNewView.setBackgroundPath(mFile.getPath()); + } + break; + default: + Assert.fail("Unknown request code"); + } + } + + + /** + * Control the 2-Step-Suspend for Netronix eInk devices + * + * @param state + * 1 is enable. + * 0 is disable. + */ + private void PowerEnhanceSet(int state) { + Log.d(TAG, "PowerEnhanceSet = " + state); + try { + Settings.System.putInt(mContext.getContentResolver(), "power_enhance_enable", state); + } catch (Exception e) { + e.printStackTrace(); + Log.d(TAG, "set POWER_ENHANCE_ENABLE error!!"); + } + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + Log.d(TAG, "Rotation = " + mDisplay.getRotation()); + } + +} \ No newline at end of file diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/java/ntx/painter/NtxView.java b/third_party/enote-sdk/Sample Code/Painter/app/src/main/java/ntx/painter/NtxView.java new file mode 100755 index 0000000..01c3158 --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/app/src/main/java/ntx/painter/NtxView.java @@ -0,0 +1,962 @@ +package ntx.painter; + +import android.content.Context; +import android.content.pm.ActivityInfo; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.Rect; +import android.graphics.drawable.BitmapDrawable; +import android.os.Debug; +import android.os.Handler; +import android.os.SystemProperties; +import android.util.AttributeSet; +import android.util.Log; +import android.view.KeyCharacterMap; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.View; +import android.widget.Toast; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; + +import ntx.draw.nDrawHelper; + +public class NtxView extends View { + + private final static String TAG = "NtxView"; + + private Bitmap mBitmap; + private Canvas mCanvas; + + private Paint mPaint; + private Path mPath; + + private Rect mCurrentUpdateEndPointRegion; + private Rect mCurrentUpdateRect; + + boolean mStartFlag = false; + boolean mFirstPointFlag = true; + boolean mFinishUpdateFlag = false; + boolean isFingerTouch = false; + + private int mCurX = -1; + private int mCurY = -1; + private int mOldX = -1; + private int mOldY = -1; + private int mCurWidth; + + private int intCanvasHeight = 0; + private int intCanvasWidth = 0; + + private int fLinewidth = 6; + private int refreshMode; + private int mPenType = PenType.PENCIL.ordinal(); + private int max_pressure = CHINESE_BRUSH_STROKEWIDTH; + private String strBackgroundPath = ""; + + private static final int CHINESE_BRUSH_STROKEWIDTH = 100; + + private boolean isFullRefreshable = true; + private boolean isEnablePenPressure = false; + + private Object mDrawLock; + public final int NOTSET = -1; + + boolean isEraser = false; + private ArrayList tPath; + private Rect mCurrDrawRect; + private Paint mCurrDrawPaint; + + public static int mCurrentRotation; + public static int mNavigationBarHeight; + + static private int intCanvasOffsetX; + static private int intCanvasOffsetY; + static private boolean isOutSide = false; + + public static final int UPDATE_MODE_PARTIAL_DU = + android.view.View.EINK_WAVEFORM_MODE_DU + | android.view.View.EINK_UPDATE_MODE_PARTIAL; + + public static final int UPDATE_MODE_PARTIAL_DU_WITH_DITHER = + android.view.View.EINK_WAVEFORM_MODE_DU + | android.view.View.EINK_UPDATE_MODE_PARTIAL + | android.view.View.EINK_DITHER_MODE_DITHER; + + public static final int UPDATE_MODE_PARTIAL_DU_WITH_MONO = + android.view.View.EINK_WAVEFORM_MODE_DU + | android.view.View.EINK_UPDATE_MODE_PARTIAL + | android.view.View.EINK_DITHER_MODE_DITHER + | android.view.View.EINK_MONOCHROME_MODE_MONOCHROME; + + public static final int UPDATE_MODE_PARTIAL_A2 = + android.view.View.EINK_WAVEFORM_MODE_A2 + | android.view.View.EINK_UPDATE_MODE_PARTIAL; + + public static final int UPDATE_MODE_PARTIAL_A2_WITH_DITHER = + android.view.View.EINK_WAVEFORM_MODE_A2 + | android.view.View.EINK_UPDATE_MODE_PARTIAL + | android.view.View.EINK_DITHER_MODE_DITHER; + + public static final int UPDATE_MODE_PARTIAL_A2_WITH_MONO = + android.view.View.EINK_WAVEFORM_MODE_A2 + | android.view.View.EINK_UPDATE_MODE_PARTIAL + | android.view.View.EINK_DITHER_MODE_DITHER + | android.view.View.EINK_MONOCHROME_MODE_MONOCHROME; + + public static final int UPDATE_MODE_PARTIAL_GC4 = + android.view.View.EINK_WAVEFORM_MODE_GC4 + | android.view.View.EINK_UPDATE_MODE_PARTIAL; + + public static final int UPDATE_MODE_PARTIAL_GC4_WITH_DITHER = + android.view.View.EINK_WAVEFORM_MODE_GC4 + | android.view.View.EINK_UPDATE_MODE_PARTIAL + | android.view.View.EINK_DITHER_MODE_DITHER; + + public static final int UPDATE_MODE_PARTIAL_GC4_WITH_MONO = + android.view.View.EINK_WAVEFORM_MODE_GC4 + | android.view.View.EINK_UPDATE_MODE_PARTIAL + | android.view.View.EINK_DITHER_MODE_DITHER + | android.view.View.EINK_MONOCHROME_MODE_MONOCHROME; + + public static final int UPDATE_MODE_FULL_GC16 = + android.view.View.EINK_WAVEFORM_MODE_GC16 + | android.view.View.EINK_UPDATE_MODE_FULL; + + public static final int UPDATE_MODE_PARTIAL_GC16 = + android.view.View.EINK_WAVEFORM_MODE_GC16 + | android.view.View.EINK_UPDATE_MODE_PARTIAL; + + public static final int UPDATE_MODE_PARTIAL_AUTO = + android.view.View.EINK_WAVEFORM_MODE_AUTO + | android.view.View.EINK_UPDATE_MODE_PARTIAL; + + public static final int UPDATE_MODE_FULL_A2 = + android.view.View.EINK_WAVEFORM_MODE_A2 + | android.view.View.EINK_UPDATE_MODE_FULL + | android.view.View.EINK_MONOCHROME_MODE_MONOCHROME; + + public static final int UPDATE_MODE_FULL_DU = + android.view.View.EINK_WAVEFORM_MODE_DU + | android.view.View.EINK_UPDATE_MODE_FULL + | android.view.View.EINK_MONOCHROME_MODE_MONOCHROME; + + public static final int UPDATE_MODE_FULL_DU_WITH_DITHER = + android.view.View.EINK_WAVEFORM_MODE_DU + | android.view.View.EINK_UPDATE_MODE_FULL + | android.view.View.EINK_DITHER_MODE_DITHER; + + public static final int EINK_STATIC_MODE_SET = 0x10000000; + public static final int EINK_STATIC_MODE_CLEAR = 0x20000000; + public static final int UPDATE_MODE_GLOBAL_PARTIAL_A2_WITH_DITHER = + android.view.View.EINK_AUTO_MODE_REGIONAL + | android.view.View.EINK_WAIT_MODE_NOWAIT + | android.view.View.EINK_UPDATE_MODE_PARTIAL + | android.view.View.EINK_WAVEFORM_MODE_A2 + | android.view.View.EINK_DITHER_MODE_DITHER + | EINK_STATIC_MODE_SET; + public static final int UPDATE_MODE_GLOBAL_RESET = EINK_STATIC_MODE_CLEAR; + + public static final int UPDATE_MODE_GLOBAL_FULL_GC16 = + android.view.View.EINK_UPDATE_MODE_FULL + | android.view.View.EINK_WAVEFORM_MODE_GC16 + | EINK_STATIC_MODE_SET; + + public static final int UPDATE_MODE_GLOBAL_FULL_A2_WITH_DITHER = + android.view.View.EINK_AUTO_MODE_REGIONAL + | android.view.View.EINK_WAIT_MODE_WAIT + | android.view.View.EINK_UPDATE_MODE_FULL + | android.view.View.EINK_WAVEFORM_MODE_A2 + | android.view.View.EINK_DITHER_MODE_DITHER + | EINK_STATIC_MODE_SET; + + public static final int MODE_APPNDRAWSTROKESYNC = 0x01000000; + + public static int[] refresh_mode_table = { + UPDATE_MODE_PARTIAL_DU, + UPDATE_MODE_PARTIAL_DU_WITH_DITHER, + UPDATE_MODE_PARTIAL_DU_WITH_MONO, + UPDATE_MODE_PARTIAL_A2, + UPDATE_MODE_PARTIAL_A2_WITH_DITHER, + UPDATE_MODE_PARTIAL_A2_WITH_MONO, + UPDATE_MODE_PARTIAL_GC4, + UPDATE_MODE_PARTIAL_GC4_WITH_DITHER, + UPDATE_MODE_PARTIAL_GC4_WITH_MONO + }; + + public enum PenType { + PENCIL, + PEN, + CHINESE_BRUSH, + } + + public static int[] pen_type_table = { + PenType.PENCIL.ordinal(), + PenType.PEN.ordinal(), + PenType.CHINESE_BRUSH.ordinal(), + }; + + public static boolean isEinkHardwareType() { + return SystemProperties.get("ro.product.hardwareType", "").equals("E60Q20") + || SystemProperties.get("ro.product.hardwareType", "").equals("E60Q30") + || SystemProperties.get("ro.product.hardwareType", "").equals("E60Q50") + || SystemProperties.get("ro.product.hardwareType", "").equals("E60Q60") + || SystemProperties.get("ro.product.hardwareType", "").equals("ED0Q00") + || SystemProperties.get("ro.product.hardwareType", "").equals("E60QD0") + || SystemProperties.get("ro.product.hardwareType", "").equals("E70Q30") + || SystemProperties.get("ro.product.hardwareType", "").equals("EA0Q00") + || SystemProperties.get("ro.product.hardwareType", "").equals("E60QR2"); + } + + public static boolean isEinkHandWritingHardwareType() { + return SystemProperties.get("ro.product.hardwareType", "").equals("E60Q60") + || SystemProperties.get("ro.product.hardwareType", "").equals("ED0Q00") + || SystemProperties.get("ro.product.hardwareType", "").equals("E70Q30") + || SystemProperties.get("ro.product.hardwareType", "").equals("EA0Q00") + || SystemProperties.get("ro.product.hardwareType", "").equals("E60QR2"); + } + + public static boolean isEink6InchHardwareType() { + return SystemProperties.get("ro.product.hardwareType", "").equals("E60Q60") + || SystemProperties.get("ro.product.hardwareType", "").equals("E60QR2") + || SystemProperties.get("ro.product.hardwareType", "").equals("EA0Q00"); + } + + public static boolean isPenUpdateModeDU() { + return SystemProperties.get("ro.product.hardwareType", "").equals("ED0Q00"); + } + + public void setCurrentRotation(int mCurrent_Rotation) { + + this.mCurrentRotation = mCurrent_Rotation; + nDrawHelper.NDrawSetInputRotation(mCurrentRotation); + + + } + + public NtxView(Context context) { + this(context, null); + } + + public NtxView(Context context, AttributeSet attrs) { + this(context, attrs, android.R.attr.textViewStyle); + } + + public NtxView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(); + } + + public void init() { + + mPaint = new Paint(); + mPaint.setAntiAlias(false); + mPaint.setStyle(Paint.Style.STROKE); + mPaint.setColor(Color.BLACK); + mPaint.setStrokeJoin(Paint.Join.ROUND); + mPaint.setStrokeCap(Paint.Cap.ROUND); + + mPath = new Path(); + tPath = new ArrayList(); + + mCurrentUpdateEndPointRegion = new Rect(0, 0, 0, 0); + mCurrentUpdateRect = new Rect(NOTSET, NOTSET, NOTSET, NOTSET); + + mCurrDrawPaint = new Paint(); + mCurrDrawPaint.setAntiAlias(false); + mCurrDrawPaint.setStyle(Paint.Style.STROKE); + mCurrDrawPaint.setColor(Color.BLACK); + mCurrDrawPaint.setStrokeJoin(Paint.Join.ROUND); + mCurrDrawPaint.setStrokeCap(Paint.Cap.ROUND); + + mFirstPointFlag = true; + + mDrawLock = new Object(); + + // update_mode initial + if (isPenUpdateModeDU()) { + setRefreshMode(UPDATE_MODE_PARTIAL_DU); + } else { + setRefreshMode(UPDATE_MODE_PARTIAL_A2); + } + setPenThickness(fLinewidth); + } + + private int getRelativeTop(View myView) { + if (myView.getParent() == myView.getRootView()) + return myView.getTop(); + else + return myView.getTop() + getRelativeTop((View) myView.getParent()); + } + + public void getBottomHeight(int mNavigationBar_Height) { + + this.mNavigationBarHeight = mNavigationBar_Height; + + } + + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + //Log.d(TAG, "onSizeChanged w h oldw oldh = " + "( " + w + ", " + h + ", " + oldw + ", " + oldh + ")"); + int curW = 0; + int curH = 0; + + if (curW < w) + curW = w; + if (curH < h) + curH = h; + + intCanvasHeight = curH; + intCanvasWidth = curW; + + Canvas newCanvas = new Canvas(); + Bitmap newBitmap = Bitmap.createBitmap(curW, curH, Bitmap.Config.ARGB_8888); + newCanvas.setBitmap(newBitmap); + newCanvas.drawColor(Color.WHITE); + if (mBitmap != null) { + newCanvas.drawBitmap(mBitmap, 0, 0, null); + } + mBitmap = newBitmap; + mCanvas = newCanvas; + + synchronized (mDrawLock) { + mDrawLock.notifyAll(); + } + + int Ndraw_region_left = 0; + int Ndraw_region_top = getRelativeTop(NtxView.this); + int Ndraw_region_right = Ndraw_region_left + w; + int Ndraw_region_bottom = Ndraw_region_top + h; + int[] packet1 = {Ndraw_region_left, Ndraw_region_top, Ndraw_region_right, Ndraw_region_bottom}; + + //Log.d(TAG, "packet1: " + Arrays.toString(packet1)); + //nDrawHelper.NDrawInit(); + nDrawHelper.NDrawSetDrawRegion(packet1); + + //test_setNDrawMultiActiveRegion(w, h); + + } + + private void test_NDrawDropFrames() { + nDrawHelper.NDrawDropFrames(400000000); //400 ms + } + + @Override + protected void onDraw(Canvas canvas) { + canvas.drawBitmap(mBitmap, 0, 0, null); + } + + /** + * Return a String describing the calling method and location at a particular stack depth. + * + * @param callStack the Thread stack + * @param depth the depth of stack to return information for. + * @return the String describing the caller at that depth. + */ + private static String getCaller(StackTraceElement callStack[], int depth) { + // callStack[4] is the caller of the method that called getCallers() + if (4 + depth >= callStack.length) { + return ""; + } + StackTraceElement caller = callStack[4 + depth]; + return caller.getClassName() + "." + caller.getMethodName() + ":" + caller.getLineNumber(); + } + + /** + * Return a string consisting of methods and locations at multiple call stack levels. + * + * @param depth the number of levels to return, starting with the immediate caller. + * @return a string describing the call stack. + * {@hide} + */ + public static String getCallers(final int depth) { + final StackTraceElement[] callStack = Thread.currentThread().getStackTrace(); + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < depth; i++) { + sb.append(getCaller(callStack, i)).append(" "); + } + return sb.toString(); + } + + /** + * Return a string consisting of methods and locations at multiple call stack levels. + * + * @param depth the number of levels to return, starting with the immediate caller. + * @return a string describing the call stack. + * {@hide} + */ + public static String getCallers(final int start, int depth) { + final StackTraceElement[] callStack = Thread.currentThread().getStackTrace(); + StringBuffer sb = new StringBuffer(); + depth += start; + for (int i = start; i < depth; i++) { + sb.append(getCaller(callStack, i)).append(" "); + } + return sb.toString(); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + processOnTouchEventNtx(event); + return true; + } + + @Override + public boolean onHoverEvent(MotionEvent event) { + + super.onHoverEvent(event); + if (event.getAction() == MotionEvent.ACTION_HOVER_EXIT) { + mHandler.removeCallbacks(runPostInvalidate); + mHandler.postDelayed(runPostInvalidate, 3000); + } else if (event.getAction() == MotionEvent.ACTION_HOVER_ENTER) { + mHandler.removeCallbacks(runPostInvalidate); + nDrawHelper.NDrawSwitch(true); + } + + return true; + } + + boolean processOnTouchEventNtx(MotionEvent event) { + // Check Finger Touch or Pen + switch (getToolType(event)) { + case MotionEvent.TOOL_TYPE_STYLUS: // set Pan touch + if (isFingerTouch) return true; + + break; + case MotionEvent.TOOL_TYPE_FINGER: // set Hand touch + if (false == isFingerTouch) return true; + + break; + + } + + if (event.getAction() == MotionEvent.ACTION_DOWN) { + + // Check Pen ERASER and HIGHLIGHT button pressed + if ((event.getButtonState() & MotionEvent.BUTTON_SECONDARY) > 0 ? true : false) { // NTX Eraser + isEraser = true; + nDrawHelper.NDrawSwitch(false); + } else if ((event.getButtonState() & MotionEvent.BUTTON_TERTIARY) > 0 ? true : false) { // Lin Eraser + isEraser = true; + nDrawHelper.NDrawSwitch(false); + } else if ((event.getToolType(0) == MotionEvent.TOOL_TYPE_ERASER)) { + isEraser = true; + nDrawHelper.NDrawSwitch(false); + } else { + isEraser = false; + nDrawHelper.NDrawSwitch(true); + + //nDrawHelper.NDrawSetInputOffset(intCanvasOffsetX,intCanvasOffsetY); + + } + + nDrawHelper.NDrawSetStrokeWidth(fLinewidth); + + startUpdating(); + } + + int historySize = event.getHistorySize(); + for (int i = 0; i < historySize; i++) { + drawPointNtx(event.getHistoricalX(i) + intCanvasOffsetX, + event.getHistoricalY(i) + intCanvasOffsetY + 1, + event.getHistoricalPressure(i), + event.getHistoricalSize(i)); + } + + drawPointNtx(event.getX() + intCanvasOffsetX, + event.getY() + intCanvasOffsetY + 1, + event.getPressure(), + event.getSize()); + + if (event.getAction() == MotionEvent.ACTION_UP) { + stopUpdating(); + //nDrawHelper.NDrawSwitch(false); + } else if (event.getAction() == MotionEvent.ACTION_MOVE) { + if (isEraser) + eraseDraw(); + } + + return true; + } + + void startUpdating() { + setFullRefreshable(false); + mHandler.removeCallbacks(runPostInvalidate); + mStartFlag = true; + mCurrDrawRect = new Rect(0, 0, 0, 0); + + } + + void stopUpdating() { + setFullRefreshable(true); + mStartFlag = false; + + mFirstPointFlag = true; + synchronized (mDrawLock) { + mCurrentUpdateRect.set(NOTSET, NOTSET, NOTSET, NOTSET); + } + int mode = MODE_APPNDRAWSTROKESYNC | android.view.View.EINK_WAVEFORM_MODE_GC16; + Log.d(TAG, "app invalidate() " + Integer.toHexString(mode)); + invalidate(mode); + } + + private void drawPointNtx(float x, float y, float pressure, float size) { + + int x_int = 0; + int y_int = 0; + + x_int = (int) x; + y_int = (int) y; + + currDrawRectMove((int) x, (int) y); + + if (mCurX != x_int || mCurY != y_int) { + if (mFinishUpdateFlag) { + mFinishUpdateFlag = false; + } + /*if (isEnablePenPressure) { + mPaint.setStrokeWidth(((float) max_pressure) * pressure); + //nDrawHelper.NDrawSetStrokeWidth((int) (((float) max_pressure) * pressure)); + }*/ + updatePenStroke(pressure); + mCurX = x_int; + mCurY = y_int; + if (mCurY > intCanvasHeight) { + mCurY = intCanvasHeight; + } + if (mCurY < 0) { + mCurY = 0; + isOutSide = true; + return; + } + if (isOutSide == true) { + isOutSide = false; + stopUpdating(); + } + if (mCurX > intCanvasWidth) { + mCurX = intCanvasWidth; + } + if (mCurX < 0) { + mCurX = 0; + } + if (isEnablePenPressure) { + mCurWidth = (int) ((((float) max_pressure) * pressure) / 2.0f); + } else { + mCurWidth = getPenThickness() / 2; + } + if (mCurWidth < 1) { + mCurWidth = 1; + } + + if (mCanvas != null) { + int newleft = mCurX - mCurWidth; + int newtop = mCurY - mCurWidth; + int newright = mCurX + mCurWidth; + int newbottom = mCurY + mCurWidth; + synchronized (mDrawLock) { + if (mFirstPointFlag) { + mFirstPointFlag = false; + mCurrentUpdateRect.set(newleft, newtop, newright, newbottom); + } else { + mCurrentUpdateRect.union(newleft, newtop, newright, newbottom); + + if (false == isEraser) { + mCanvas.drawLine((float) mOldX, (float) mOldY, (float) mCurX, (float) mCurY, mPaint); + + + if (getPenType() == PenType.PEN.ordinal()){ + tPath.add(new TouchPath( (int)(fLinewidth * pressure), mPaint.getColor(), mOldX, mOldY, mCurX, mCurY, mCurrDrawRect)); + + }else if (getPenType() == PenType.CHINESE_BRUSH.ordinal()) { + tPath.add(new TouchPath((int)(float)(max_pressure * Math.pow(pressure,3)), mPaint.getColor(), mOldX, mOldY, mCurX, mCurY, mCurrDrawRect)); + + }else{ + // PenType.PENCIL.ordinal() + tPath.add(new TouchPath(fLinewidth, mPaint.getColor(), mOldX, mOldY, mCurX, mCurY, mCurrDrawRect)); + + } + } + } + mOldX = mCurX; + mOldY = mCurY; + mCurrentUpdateEndPointRegion.set(newleft, newtop, newright, newbottom); + } + } + } + } + + private Handler mHandler = new Handler(); + + public synchronized void clear() { + if (mCanvas != null) { + tPath.clear(); + + mPath.reset(); + drawBackground(); + mHandler.removeCallbacks(runClear); + mHandler.postDelayed(runClear, 1000); + } + } + + private Runnable runPostInvalidate = new Runnable() { + @Override + public void run() { + postInvalidate(); + } + }; + + private Runnable runClear = new Runnable() { + @Override + public void run() { + + mFirstPointFlag = true; + fullRefresh(NtxView.this); + } + }; + + public int FileOutput(String output_path) { + + Bitmap bmpBackground = null; + + if (strBackgroundPath.equals("")) { + if (mBitmap == null) + return -1; // retrun -1 ==> fail; return 0 ==> success; + + bmpBackground = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), Bitmap.Config.ARGB_8888); + } else { + bmpBackground = Bitmap.createScaledBitmap(BitmapFactory.decodeFile(strBackgroundPath), mBitmap.getWidth(), + mBitmap.getHeight(), true); + } + + if (mBitmap != null) { + // Create new canvas to merge paint and background + bmpBackground = combineBitmap(bmpBackground, mBitmap); + } + + try { + FileOutputStream fos = new FileOutputStream(output_path); + bmpBackground.compress(Bitmap.CompressFormat.PNG, 100, fos); + fos.close(); + return 0; + } catch (IOException e) { + e.printStackTrace(); + return -1; + } + + } + + /** + * @param background + * @param foreground + * @return Bitmap + */ + public static Bitmap combineBitmap(Bitmap background, Bitmap foreground) { + if (background == null) { + return null; + } + int bgWidth = background.getWidth(); + int bgHeight = background.getHeight(); + int fgWidth = foreground.getWidth(); + int fgHeight = foreground.getHeight(); + Bitmap newmap = Bitmap.createBitmap(bgWidth, bgHeight, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(newmap); + canvas.drawBitmap(background, 0, 0, null); + canvas.drawBitmap(foreground, (bgWidth - fgWidth) / 2, + (bgHeight - fgHeight) / 2, null); + canvas.save(Canvas.ALL_SAVE_FLAG); + canvas.restore(); + return newmap; + } + + public int getPenThickness() { + return fLinewidth; + } + + public void setPenThickness(int i) { + fLinewidth = i; + mPaint.setStrokeWidth(fLinewidth); + nDrawHelper.NDrawSetMaxStrokeWidthWhenUsingPressure(NOTSET); + nDrawHelper.NDrawSetStrokeWidth(fLinewidth); + isEnablePenPressure = false; + return; + } + + private void updatePenStroke( float pressure ) { + + if ( mPenType == PenType.PENCIL.ordinal() ) { + mPaint.setStrokeWidth(fLinewidth); + nDrawHelper.NDrawSetMaxStrokeWidthWhenUsingPressure(NOTSET); + nDrawHelper.NDrawSetStrokeWidth(fLinewidth); + } else if ( mPenType == PenType.PEN.ordinal() ) { + isEnablePenPressure = true; + mPaint.setStrokeWidth(fLinewidth * pressure); + nDrawHelper.NDrawSetMaxStrokeWidthWhenUsingPressure(fLinewidth); + + } else if ( mPenType == PenType.CHINESE_BRUSH.ordinal() ) { + isEnablePenPressure = true; + mPaint.setStrokeWidth((float)(max_pressure * Math.pow(pressure,3))); + nDrawHelper.NDrawSetMaxStrokeWidthWhenUsingPressure(max_pressure); + + } + } + + + + public boolean getPenThicknessWithPressure() { + return isEnablePenPressure; + } + + public void setPenThicknessWithPressure(boolean enable_pen_pressure) { + nDrawHelper.NDrawSetMaxStrokeWidthWhenUsingPressure(max_pressure); + isEnablePenPressure = enable_pen_pressure; + return; + } + + public void setFullRefreshable(boolean fullRefreshable) { + isFullRefreshable = fullRefreshable; + } + + public boolean getFullRefreshable() { + return isFullRefreshable; + } + + public void setFingerTouch(boolean checked) { + isFingerTouch = checked; + } + + private int intCanvasStyle = 1; + + public void setCanvasStyle(int i) { + if (i == 1) { + intCanvasStyle = 1; + mPaint.setColor(Color.BLACK); + mCanvas.drawColor(Color.WHITE); + nDrawHelper.NDrawSetPaintColor(Color.BLACK); + } else if (i == 2) { + intCanvasStyle = 2; + mPaint.setColor(Color.WHITE); + mCanvas.drawColor(Color.BLACK); + nDrawHelper.NDrawSetPaintColor(Color.WHITE); + } + mPaint.setXfermode(null); + setPenThickness(fLinewidth); + } + + public void setRefreshMode(int refresh_mode) { + refreshMode = refresh_mode; + nDrawHelper.NDrawSetUpdateMode(refresh_mode); + } + + public int getRefreshMode() { + return refreshMode; + } + + public void setPenType(int type) { + mPenType = type; + nDrawHelper.NDrawSetPenType(type); + } + + public int getPenType() { + //Log.d(TAG, "getPenType: " + mPenType); + return mPenType; + } + + public void setBackgroundPath(String background_path) { + strBackgroundPath = background_path; + + if (new File(background_path).exists()) { + tPath.clear(); + drawBackground(); + invalidate(); + } + } + + public void onPause() { + nDrawHelper.NDrawSwitch(false); + } + + public void onResume() { + nDrawHelper.NDrawSwitch(true); + } + + public void drawBackground() { + if (intCanvasStyle == 1) { + mBitmap.eraseColor(Color.WHITE); + } else if (intCanvasStyle == 2) { + mBitmap.eraseColor(Color.BLACK); + } + + if (new File(strBackgroundPath).exists()) { + mBitmap.eraseColor(Color.TRANSPARENT); + setBackgroundDrawable(new BitmapDrawable(strBackgroundPath)); + } + } + + private int getToolType(MotionEvent event) { + return hasToolStylus(event) ? MotionEvent.TOOL_TYPE_STYLUS : event.getToolType(event.getActionIndex()); + } + + private boolean hasToolStylus(MotionEvent event) { + for (int i = 0; i < event.getPointerCount(); i++) { + if (event.getToolType(i) == MotionEvent.TOOL_TYPE_STYLUS) { + return true; + } + } + return false; + } + + private void eraseDraw() { + if (isEraser && tPath.size() > 0 && isRectEmpty(mCurrDrawRect)) { + TouchPath tp; + boolean eraseStatus = false; + for (int i2 = 0; i2 < 2; i2++) { + for (int i1 = tPath.size() - 1; i1 >= 0; i1--) { + tp = (TouchPath) tPath.get(i1); + Rect rect = tp.mRect; + if (isRectEmpty(rect) && Rect.intersects(mCurrDrawRect, rect)) { + if (i2 == 1) { + tPath.remove(tp); + } else { + eraseRect(rect); + } + eraseStatus = true; + } + } + if (!eraseStatus) { + break; + } + } + if (eraseStatus) { + int currStrokeWidth = fLinewidth; + int currColor = mPaint.getColor(); + drawBackground(); + + Iterator it = tPath.iterator(); + while (it.hasNext()) { + tp = (TouchPath) it.next(); + mCurrDrawPaint.setStrokeWidth((float) tp.mStrokeWidth); + mCurrDrawPaint.setColor(tp.mColor); + nDrawHelper.NDrawSetStrokeWidth(tp.mStrokeWidth); + nDrawHelper.NDrawSetPaintColor(tp.mColor); + mCanvas.drawLine((float) tp.mOldX, (float) tp.mOldY, (float) tp.mCurX, (float) tp.mCurY, mCurrDrawPaint); + } + nDrawHelper.NDrawSetStrokeWidth(currStrokeWidth); + nDrawHelper.NDrawSetPaintColor(currColor); + + mCurrDrawPaint.setStrokeWidth((float) currStrokeWidth); + mCurrDrawPaint.setColor(currColor); + invalidate(); + } + } + } + + private boolean isRectEmpty(Rect rect) { + if ((rect.right - rect.left) + 1 <= 0 || (rect.bottom - rect.top) + 1 <= 0) { + return false; + } + return true; + } + + private void eraseRect(Rect rect) { + if (mCurrDrawRect.left > rect.left) { + mCurrDrawRect.left = rect.left; + } + if (mCurrDrawRect.top > rect.top) { + mCurrDrawRect.top = rect.top; + } + if (mCurrDrawRect.right < rect.right) { + mCurrDrawRect.right = rect.right; + } + if (mCurrDrawRect.bottom < rect.bottom) { + mCurrDrawRect.bottom = rect.bottom; + } + } + + private void currDrawRectMove(int mCurX, int mCurY) { + if (mCurrDrawRect.left == 0 || mCurrDrawRect.left > mCurX) { + mCurrDrawRect.left = mCurX; + } + if (mCurrDrawRect.top == 0 || mCurrDrawRect.top > mCurY) { + mCurrDrawRect.top = mCurY; + } + if (mCurrDrawRect.right == 0 || mCurrDrawRect.right < mCurX) { + mCurrDrawRect.right = mCurX; + } + if (mCurrDrawRect.bottom == 0 || mCurrDrawRect.bottom < mCurY) { + mCurrDrawRect.bottom = mCurY; + } + } + + public void fullRefresh(View view) { + view.invalidate(UPDATE_MODE_FULL_GC16); + } + + + public void setInputOffset(int offset_x, int offset_y) { + + nDrawHelper.NDrawSetInputOffset(offset_x, offset_y); + intCanvasOffsetX = offset_x; + intCanvasOffsetY = offset_y; + + } + + + class TouchPath { + public int mColor; + public int mCurX; + public int mCurY; + public int mOldX; + public int mOldY; + public Rect mRect; + public int mStrokeWidth; + + public TouchPath(int strokeWidth, int currColor, int currOldX, int currOldY, int currCurX, int currCurY, Rect currmRect) { + this.mStrokeWidth = strokeWidth; + this.mColor = currColor; + this.mRect = currmRect; + this.mOldX = currOldX; + this.mOldY = currOldY; + this.mCurX = currCurX; + this.mCurY = currCurY; + } + } + + public void test_setNDrawMultiActiveRegion(int w, int h) { + int Ndraw_region_left = 0; + int Ndraw_region_top = getRelativeTop(NtxView.this); + int Ndraw_region_right = Ndraw_region_left + w/3; + int Ndraw_region_bottom = Ndraw_region_top + h/3; + + int Ndraw_region_left_2 = (w * 2)/3 ; + int Ndraw_region_top_2 = getRelativeTop(NtxView.this); + int Ndraw_region_right_2 = w; + int Ndraw_region_bottom_2 = Ndraw_region_top_2 + h/3; + + int Ndraw_region_left_3 = w/3 ; + int Ndraw_region_top_3 = getRelativeTop(NtxView.this) + h/3; + int Ndraw_region_right_3 = Ndraw_region_left_3 + w/3; + int Ndraw_region_bottom_3 = Ndraw_region_top_3 + h/3; + + + int[] multi_active_region = {Ndraw_region_left, Ndraw_region_top, Ndraw_region_right, Ndraw_region_bottom, + Ndraw_region_left_2, Ndraw_region_top_2, Ndraw_region_right_2, Ndraw_region_bottom_2, + Ndraw_region_left_3, Ndraw_region_top_3, Ndraw_region_right_3, Ndraw_region_bottom_3}; + + + + Log.d(TAG, "multi_active_region: " + Arrays.toString(multi_active_region)); + //nDrawHelper.NDrawInit(multi_active_region); + nDrawHelper.NDrawSetDrawRegion(multi_active_region); + + } +} diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/java/ntx/painter/ReselectSpinner.java b/third_party/enote-sdk/Sample Code/Painter/app/src/main/java/ntx/painter/ReselectSpinner.java new file mode 100755 index 0000000..253ace5 --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/app/src/main/java/ntx/painter/ReselectSpinner.java @@ -0,0 +1,39 @@ +package ntx.painter; + +import android.content.Context; +import android.util.AttributeSet; +import android.widget.Spinner; + +public class ReselectSpinner extends Spinner{ + + public ReselectSpinner(Context context) + { super(context); } + + public ReselectSpinner(Context context, AttributeSet attrs) + { super(context, attrs); } + + public ReselectSpinner(Context context, AttributeSet attrs, int defStyle) + { super(context, attrs, defStyle); } + + @Override public void + setSelection(int position, boolean animate) + { + boolean sameSelected = position == getSelectedItemPosition(); + super.setSelection(position, animate); + if (sameSelected) { + // Spinner does not call the OnItemSelectedListener if the same item is selected, so do it manually now + getOnItemSelectedListener().onItemSelected(this, getSelectedView(), position, getSelectedItemId()); + } + } + + @Override public void + setSelection(int position) + { + boolean sameSelected = position == getSelectedItemPosition(); + super.setSelection(position); + if (sameSelected) { + // Spinner does not call the OnItemSelectedListener if the same item is selected, so do it manually now + getOnItemSelectedListener().onItemSelected(this, getSelectedView(), position, getSelectedItemId()); + } + } +} diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/libs/javalib.jar b/third_party/enote-sdk/Sample Code/Painter/app/src/main/libs/javalib.jar new file mode 100755 index 0000000..229904c Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/libs/javalib.jar differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/libs/ntx_android_bt_net_classes.jar b/third_party/enote-sdk/Sample Code/Painter/app/src/main/libs/ntx_android_bt_net_classes.jar new file mode 100755 index 0000000..12f74a6 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/libs/ntx_android_bt_net_classes.jar differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/libs/ntx_android_graphics_classes.jar b/third_party/enote-sdk/Sample Code/Painter/app/src/main/libs/ntx_android_graphics_classes.jar new file mode 100755 index 0000000..f600157 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/libs/ntx_android_graphics_classes.jar differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/libs/ntx_android_os_classes.jar b/third_party/enote-sdk/Sample Code/Painter/app/src/main/libs/ntx_android_os_classes.jar new file mode 100755 index 0000000..3454feb Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/libs/ntx_android_os_classes.jar differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/libs/ntx_android_view_classes.jar b/third_party/enote-sdk/Sample Code/Painter/app/src/main/libs/ntx_android_view_classes.jar new file mode 100755 index 0000000..992a852 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/libs/ntx_android_view_classes.jar differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-hdpi/icon.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-hdpi/icon.png new file mode 100755 index 0000000..edb127f Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-hdpi/icon.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-ldpi/icon.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-ldpi/icon.png new file mode 100755 index 0000000..edb127f Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-ldpi/icon.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-mdpi/icon.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-mdpi/icon.png new file mode 100755 index 0000000..edb127f Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-mdpi/icon.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-nodpi/bg_launcher_note.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-nodpi/bg_launcher_note.png new file mode 100755 index 0000000..33c0a97 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-nodpi/bg_launcher_note.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_admode.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_admode.png new file mode 100755 index 0000000..812caec Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_admode.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_background.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_background.png new file mode 100755 index 0000000..7807343 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_background.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_background_active.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_background_active.png new file mode 100755 index 0000000..9252d9e Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_background_active.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_background_pressed.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_background_pressed.png new file mode 100755 index 0000000..8772259 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_background_pressed.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_cal.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_cal.png new file mode 100755 index 0000000..4527442 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_cal.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_cal_active.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_cal_active.png new file mode 100755 index 0000000..056e384 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_cal_active.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_cal_pressed.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_cal_pressed.png new file mode 100755 index 0000000..056e384 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_cal_pressed.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_clean.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_clean.png new file mode 100755 index 0000000..d33b261 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_clean.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_clean_active.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_clean_active.png new file mode 100755 index 0000000..7393ca2 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_clean_active.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_clean_disabled.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_clean_disabled.png new file mode 100755 index 0000000..4de9325 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_clean_disabled.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_clean_pressed.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_clean_pressed.png new file mode 100755 index 0000000..7393ca2 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_clean_pressed.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_full_refresh.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_full_refresh.png new file mode 100755 index 0000000..5133b61 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_full_refresh.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_full_refresh_active.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_full_refresh_active.png new file mode 100755 index 0000000..3c301bd Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_full_refresh_active.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_full_refresh_pressed.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_full_refresh_pressed.png new file mode 100755 index 0000000..3c301bd Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_full_refresh_pressed.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_info.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_info.png new file mode 100755 index 0000000..f6eccb3 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_info.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_info_active.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_info_active.png new file mode 100755 index 0000000..924e2e2 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_info_active.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_info_pressed.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_info_pressed.png new file mode 100755 index 0000000..924e2e2 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_info_pressed.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_reset.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_reset.png new file mode 100755 index 0000000..67f14ef Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_reset.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_rotate.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_rotate.png new file mode 100755 index 0000000..62f4256 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_rotate.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_rotate_active.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_rotate_active.png new file mode 100755 index 0000000..2097651 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_rotate_active.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_rotate_pressed.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_rotate_pressed.png new file mode 100755 index 0000000..2097651 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_rotate_pressed.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_save.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_save.png new file mode 100755 index 0000000..0bcc2d5 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_save.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_save_active.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_save_active.png new file mode 100755 index 0000000..ba48fb0 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_save_active.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_save_disabled.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_save_disabled.png new file mode 100755 index 0000000..88cedbf Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_save_disabled.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_save_pressed.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_save_pressed.png new file mode 100755 index 0000000..ba48fb0 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_save_pressed.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_thickness.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_thickness.png new file mode 100755 index 0000000..1c6175a Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_thickness.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_thickness_active.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_thickness_active.png new file mode 100755 index 0000000..791ae31 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_thickness_active.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_thickness_large.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_thickness_large.png new file mode 100755 index 0000000..8fe5099 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_thickness_large.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_thickness_medium.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_thickness_medium.png new file mode 100755 index 0000000..4f94876 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_thickness_medium.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_thickness_pressed.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_thickness_pressed.png new file mode 100755 index 0000000..791ae31 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_thickness_pressed.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_thickness_pressure.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_thickness_pressure.png new file mode 100755 index 0000000..78dab06 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_thickness_pressure.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_thickness_small.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_thickness_small.png new file mode 100755 index 0000000..d72de11 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ic_menu_thickness_small.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ntx_custom_checkbox_checked.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ntx_custom_checkbox_checked.png new file mode 100755 index 0000000..168e06a Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ntx_custom_checkbox_checked.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ntx_custom_checkbox_unchecked.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ntx_custom_checkbox_unchecked.png new file mode 100755 index 0000000..f6d6568 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/ntx_custom_checkbox_unchecked.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/page_left.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/page_left.png new file mode 100755 index 0000000..ad4beda Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/page_left.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/page_left_pressed.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/page_left_pressed.png new file mode 100755 index 0000000..fc04dfc Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/page_left_pressed.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/page_right.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/page_right.png new file mode 100755 index 0000000..454297e Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/page_right.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/page_right_pressed.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/page_right_pressed.png new file mode 100755 index 0000000..743c3a4 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/page_right_pressed.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/writing_pen_brush.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/writing_pen_brush.png new file mode 100755 index 0000000..058ace6 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/writing_pen_brush.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/writing_pen_pen.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/writing_pen_pen.png new file mode 100755 index 0000000..2a68ee9 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/writing_pen_pen.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/writing_pen_pencil.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/writing_pen_pencil.png new file mode 100755 index 0000000..34eb989 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable-xhdpi/writing_pen_pencil.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/background.9.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/background.9.png new file mode 100755 index 0000000..2400eec Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/background.9.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/bg.xml b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/bg.xml new file mode 100755 index 0000000..932876a --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/bg.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/bg_default.xml b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/bg_default.xml new file mode 100755 index 0000000..691082b --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/bg_default.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/bg_pressed.xml b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/bg_pressed.xml new file mode 100755 index 0000000..516fb24 --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/bg_pressed.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/bg_selected.xml b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/bg_selected.xml new file mode 100755 index 0000000..516fb24 --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/bg_selected.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/bg_white.xml b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/bg_white.xml new file mode 100755 index 0000000..3fdc617 --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/bg_white.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/button_background.9.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/button_background.9.png new file mode 100755 index 0000000..049b451 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/button_background.9.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/button_background_active.9.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/button_background_active.9.png new file mode 100755 index 0000000..d6b1214 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/button_background_active.9.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/button_background_inactive.9.png b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/button_background_inactive.9.png new file mode 100755 index 0000000..11909f3 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/button_background_inactive.9.png differ diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/imgb_next_page.xml b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/imgb_next_page.xml new file mode 100755 index 0000000..49b5a82 --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/imgb_next_page.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/imgb_pre_page.xml b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/imgb_pre_page.xml new file mode 100755 index 0000000..e25f1a6 --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/imgb_pre_page.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/ntx_custom_checkbox.xml b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/ntx_custom_checkbox.xml new file mode 100755 index 0000000..9d515ea --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/ntx_custom_checkbox.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/painter_button_background.xml b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/painter_button_background.xml new file mode 100755 index 0000000..22439cf --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/painter_button_background.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/toolbox_background.xml b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/toolbox_background.xml new file mode 100755 index 0000000..495190a --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/toolbox_background.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/toolbox_calibration.xml b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/toolbox_calibration.xml new file mode 100755 index 0000000..0c37ab5 --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/toolbox_calibration.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/toolbox_clean.xml b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/toolbox_clean.xml new file mode 100755 index 0000000..873c920 --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/toolbox_clean.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/toolbox_full_refresh.xml b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/toolbox_full_refresh.xml new file mode 100755 index 0000000..54e0bb2 --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/toolbox_full_refresh.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/toolbox_info.xml b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/toolbox_info.xml new file mode 100755 index 0000000..95ddd58 --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/toolbox_info.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/toolbox_rotate.xml b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/toolbox_rotate.xml new file mode 100755 index 0000000..ef1b0c4 --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/toolbox_rotate.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/toolbox_save.xml b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/toolbox_save.xml new file mode 100755 index 0000000..f91ba9b --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/toolbox_save.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/toolbox_thickness.xml b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/toolbox_thickness.xml new file mode 100755 index 0000000..eb27347 --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/drawable/toolbox_thickness.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/layout/dialog_calibration.xml b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/layout/dialog_calibration.xml new file mode 100755 index 0000000..623e88b --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/layout/dialog_calibration.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/layout/dialog_custom.xml b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/layout/dialog_custom.xml new file mode 100755 index 0000000..e940421 --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/layout/dialog_custom.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/layout/main_dialog.xml b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/layout/main_dialog.xml new file mode 100755 index 0000000..68018a4 --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/layout/main_dialog.xml @@ -0,0 +1,25 @@ + + + + + + \ No newline at end of file diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/layout/seekbar_dialog.xml b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/layout/seekbar_dialog.xml new file mode 100755 index 0000000..4e6e9fb --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/layout/seekbar_dialog.xml @@ -0,0 +1,25 @@ + + + + + + \ No newline at end of file diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/layout/seekbar_dialog_2.xml b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/layout/seekbar_dialog_2.xml new file mode 100755 index 0000000..9f3b607 --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/layout/seekbar_dialog_2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + \ No newline at end of file diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/layout/toolbox_spinner_item.xml b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/layout/toolbox_spinner_item.xml new file mode 100755 index 0000000..67fbfa8 --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/layout/toolbox_spinner_item.xml @@ -0,0 +1,12 @@ + + diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/values/backg.xml b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/values/backg.xml new file mode 100755 index 0000000..b2a05a1 --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/values/backg.xml @@ -0,0 +1,15 @@ + + + + +WHITE +RED +GREEN +BLUE +YELLOW +BLACK +GRAY +MAGENTA +CYAN + + diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/values/colors.xml b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/values/colors.xml new file mode 100755 index 0000000..d9d250a --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/values/colors.xml @@ -0,0 +1,22 @@ + + + #000000 + #FFFFFF + #000000 + #111111 + #222222 + #333333 + #444444 + #555555 + #666666 + #777777 + #888888 + #999999 + #AAAAAA + #BBBBBB + #CCCCCC + #DDDDDD + #EEEEEE + #FFFFFF + #00000000 + \ No newline at end of file diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/values/filepicker_colors.xml b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/values/filepicker_colors.xml new file mode 100755 index 0000000..b96dbe3 --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/values/filepicker_colors.xml @@ -0,0 +1,12 @@ + + + + #FFFFFF + #000000 + #464646 + #767676 + #969696 + #DDDDDD + #333333 + #ff0091dc + \ No newline at end of file diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/values/image_picker_lengths.xml b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/values/image_picker_lengths.xml new file mode 100755 index 0000000..cdfd039 --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/values/image_picker_lengths.xml @@ -0,0 +1,7 @@ + + + 300dp + 128dp + 56dp + + \ No newline at end of file diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/values/single_choice_dialogs.xml b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/values/single_choice_dialogs.xml new file mode 100755 index 0000000..2f96d6e --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/values/single_choice_dialogs.xml @@ -0,0 +1,15 @@ + + + + + 1 + 3 + 6 + 9 + 12 + 15 + 350 + 99999 + + + \ No newline at end of file diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/values/strings.xml b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/values/strings.xml new file mode 100755 index 0000000..2cbbbac --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/values/strings.xml @@ -0,0 +1,73 @@ + + + SAVE FILE + nPainter + LOAD FILE + Finger touch + + This example is used to demonstrate E-ink refresh mode and digitizer \n\n + on the Netronix EPD devices. + Pick image + No image is found! + Saving to %1$s is successful ! + Saving to %1$s failed ! + Please wait... + + + + Left 20 + Left 16 + Left 12 + Left 8 + Left 4 + Zero + Right 4 + Right 8 + Right 12 + Right 16 + Right 20 + + + + -20 + -16 + -12 + -8 + -4 + 0 + 4 + 8 + 12 + 16 + 20 + + + + Up 20 + Up 16 + Up 12 + Up 8 + Up 4 + Zero + Down 4 + Down 8 + Down 12 + Down 16 + Down 20 + + + + -20 + -16 + -12 + -8 + -4 + 0 + 4 + 8 + 12 + 16 + 20 + + + diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/values/styles.xml b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/values/styles.xml new file mode 100755 index 0000000..0ee30e0 --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/values/styles.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/values/toolbox.xml b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/values/toolbox.xml new file mode 100755 index 0000000..99cddfa --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/values/toolbox.xml @@ -0,0 +1,16 @@ + + + + + PARTIAL_DU + PARTIAL_DU_WITH_DITHER + PARTIAL_DU_WITH_MONO + PARTIAL_A2 + PARTIAL_A2_WITH_DITHER + PARTIAL_A2_WITH_MONO + PARTIAL_GC4 + PARTIAL_GC4_WITH_DITHER + PARTIAL_GC4_WITH_MONO + + + diff --git a/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/values/total_pen_style.xml b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/values/total_pen_style.xml new file mode 100755 index 0000000..b7c3acd --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/app/src/main/res/values/total_pen_style.xml @@ -0,0 +1,8 @@ + + + + Pencil + Pen + Ch-Brush + + \ No newline at end of file diff --git a/third_party/enote-sdk/Sample Code/Painter/build.gradle b/third_party/enote-sdk/Sample Code/Painter/build.gradle new file mode 100755 index 0000000..ed022bd --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/build.gradle @@ -0,0 +1,25 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:2.2.3' + } +} + +allprojects { + repositories { + jcenter() + } + + gradle.projectsEvaluated { + tasks.withType(JavaCompile) { +// options.compilerArgs.add('-Xbootclasspath/p:app/src/main/libs/classes.jar') + options.compilerArgs.add('-Xbootclasspath/p:app/src/main/libs/ntx_android_bt_net_classes.jar') + options.compilerArgs.add('-Xbootclasspath/p:app/src/main/libs/ntx_android_graphics_classes.jar') + options.compilerArgs.add('-Xbootclasspath/p:app/src/main/libs/ntx_android_os_classes.jar') + options.compilerArgs.add('-Xbootclasspath/p:app/src/main/libs/ntx_android_view_classes.jar') + } + } +} diff --git a/third_party/enote-sdk/Sample Code/Painter/gradle/wrapper/gradle-wrapper.jar b/third_party/enote-sdk/Sample Code/Painter/gradle/wrapper/gradle-wrapper.jar new file mode 100755 index 0000000..13372ae Binary files /dev/null and b/third_party/enote-sdk/Sample Code/Painter/gradle/wrapper/gradle-wrapper.jar differ diff --git a/third_party/enote-sdk/Sample Code/Painter/gradle/wrapper/gradle-wrapper.properties b/third_party/enote-sdk/Sample Code/Painter/gradle/wrapper/gradle-wrapper.properties new file mode 100755 index 0000000..04e285f --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Mon Dec 28 10:00:20 PST 2015 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip diff --git a/third_party/enote-sdk/Sample Code/Painter/gradlew b/third_party/enote-sdk/Sample Code/Painter/gradlew new file mode 100755 index 0000000..9d82f78 --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/gradlew @@ -0,0 +1,160 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/third_party/enote-sdk/Sample Code/Painter/gradlew.bat b/third_party/enote-sdk/Sample Code/Painter/gradlew.bat new file mode 100755 index 0000000..8a0b282 --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/gradlew.bat @@ -0,0 +1,90 @@ +@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 + +@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= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/third_party/enote-sdk/Sample Code/Painter/import-summary.txt b/third_party/enote-sdk/Sample Code/Painter/import-summary.txt new file mode 100755 index 0000000..faa532a --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/import-summary.txt @@ -0,0 +1,34 @@ +ECLIPSE ANDROID PROJECT IMPORT SUMMARY +====================================== + +Ignored Files: +-------------- +The following files were *not* copied into the new Gradle project; you +should evaluate whether these are still needed in your project and if +so manually move them: + +* classes-full-debug.jar + +Moved Files: +------------ +Android Gradle projects use a different directory structure than ADT +Eclipse projects. Here's how the projects were restructured: + +* AndroidManifest.xml => app/src/main/AndroidManifest.xml +* res/ => app/src/main/res/ +* src/ => app/src/main/java/ + +Next Steps: +----------- +You can now build the project. The Gradle project needs network +connectivity to download dependencies. + +Bugs: +----- +If for some reason your project does not build, and you determine that +it is due to a bug or limitation of the Eclipse to Gradle importer, +please file a bug at http://b.android.com with category +Component-Tools. + +(This import summary is for your information only, and can be deleted +after import once you are satisfied with the results.) diff --git a/third_party/enote-sdk/Sample Code/Painter/local.properties b/third_party/enote-sdk/Sample Code/Painter/local.properties new file mode 100755 index 0000000..87cd06d --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/local.properties @@ -0,0 +1,12 @@ +## This file is automatically generated by Android Studio. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must *NOT* be checked into Version Control Systems, +# as it contains information specific to your local configuration. +# +# Location of the SDK. This is only used by Gradle. +# For customization when using a Version Control System, please read the +# header note. +#Mon Jan 23 11:24:27 CST 2017 +ndk.dir=/home/terrylove/codebase/AndroidTool/android-sdk-linux/ndk-bundle +sdk.dir=/home/terrylove/codebase/AndroidTool/android-sdk-linux diff --git a/third_party/enote-sdk/Sample Code/Painter/ntx_Painter1.iml b/third_party/enote-sdk/Sample Code/Painter/ntx_Painter1.iml new file mode 100755 index 0000000..27da7ad --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/ntx_Painter1.iml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/third_party/enote-sdk/Sample Code/Painter/settings.gradle b/third_party/enote-sdk/Sample Code/Painter/settings.gradle new file mode 100755 index 0000000..e7b4def --- /dev/null +++ b/third_party/enote-sdk/Sample Code/Painter/settings.gradle @@ -0,0 +1 @@ +include ':app' diff --git a/third_party/enote-sdk/Sample Code/nRefresh/.classpath b/third_party/enote-sdk/Sample Code/nRefresh/.classpath new file mode 100755 index 0000000..f26c8fa --- /dev/null +++ b/third_party/enote-sdk/Sample Code/nRefresh/.classpath @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/third_party/enote-sdk/Sample Code/nRefresh/.project b/third_party/enote-sdk/Sample Code/nRefresh/.project new file mode 100755 index 0000000..27e0253 --- /dev/null +++ b/third_party/enote-sdk/Sample Code/nRefresh/.project @@ -0,0 +1,33 @@ + + + ntx_nRefresh + + + + + + com.android.ide.eclipse.adt.ResourceManagerBuilder + + + + + com.android.ide.eclipse.adt.PreCompilerBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + com.android.ide.eclipse.adt.ApkBuilder + + + + + + com.android.ide.eclipse.adt.AndroidNature + org.eclipse.jdt.core.javanature + + diff --git a/third_party/enote-sdk/Sample Code/nRefresh/AndroidManifest.xml b/third_party/enote-sdk/Sample Code/nRefresh/AndroidManifest.xml new file mode 100755 index 0000000..ecf49e3 --- /dev/null +++ b/third_party/enote-sdk/Sample Code/nRefresh/AndroidManifest.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/third_party/enote-sdk/Sample Code/nRefresh/ntx_android_bt_net_classes.jar b/third_party/enote-sdk/Sample Code/nRefresh/ntx_android_bt_net_classes.jar new file mode 100755 index 0000000..19b6be2 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/nRefresh/ntx_android_bt_net_classes.jar differ diff --git a/third_party/enote-sdk/Sample Code/nRefresh/ntx_android_graphics_classes.jar b/third_party/enote-sdk/Sample Code/nRefresh/ntx_android_graphics_classes.jar new file mode 100755 index 0000000..f600157 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/nRefresh/ntx_android_graphics_classes.jar differ diff --git a/third_party/enote-sdk/Sample Code/nRefresh/ntx_android_os_classes.jar b/third_party/enote-sdk/Sample Code/nRefresh/ntx_android_os_classes.jar new file mode 100755 index 0000000..3454feb Binary files /dev/null and b/third_party/enote-sdk/Sample Code/nRefresh/ntx_android_os_classes.jar differ diff --git a/third_party/enote-sdk/Sample Code/nRefresh/ntx_android_util_classes.jar b/third_party/enote-sdk/Sample Code/nRefresh/ntx_android_util_classes.jar new file mode 100755 index 0000000..7b175df Binary files /dev/null and b/third_party/enote-sdk/Sample Code/nRefresh/ntx_android_util_classes.jar differ diff --git a/third_party/enote-sdk/Sample Code/nRefresh/ntx_android_view_classes.jar b/third_party/enote-sdk/Sample Code/nRefresh/ntx_android_view_classes.jar new file mode 100755 index 0000000..992a852 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/nRefresh/ntx_android_view_classes.jar differ diff --git a/third_party/enote-sdk/Sample Code/nRefresh/project.properties b/third_party/enote-sdk/Sample Code/nRefresh/project.properties new file mode 100755 index 0000000..8105578 --- /dev/null +++ b/third_party/enote-sdk/Sample Code/nRefresh/project.properties @@ -0,0 +1,16 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt + +# Project target. +target=android-19 +apk-configurations= +dex.force.jumbo=true diff --git a/third_party/enote-sdk/Sample Code/nRefresh/res/drawable-hdpi/icon.png b/third_party/enote-sdk/Sample Code/nRefresh/res/drawable-hdpi/icon.png new file mode 100755 index 0000000..b250677 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/nRefresh/res/drawable-hdpi/icon.png differ diff --git a/third_party/enote-sdk/Sample Code/nRefresh/res/drawable-ldpi/icon.png b/third_party/enote-sdk/Sample Code/nRefresh/res/drawable-ldpi/icon.png new file mode 100755 index 0000000..b250677 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/nRefresh/res/drawable-ldpi/icon.png differ diff --git a/third_party/enote-sdk/Sample Code/nRefresh/res/drawable-mdpi/icon.png b/third_party/enote-sdk/Sample Code/nRefresh/res/drawable-mdpi/icon.png new file mode 100755 index 0000000..b250677 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/nRefresh/res/drawable-mdpi/icon.png differ diff --git a/third_party/enote-sdk/Sample Code/nRefresh/res/drawable-nodpi/a_001.png b/third_party/enote-sdk/Sample Code/nRefresh/res/drawable-nodpi/a_001.png new file mode 100755 index 0000000..2163c51 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/nRefresh/res/drawable-nodpi/a_001.png differ diff --git a/third_party/enote-sdk/Sample Code/nRefresh/res/drawable-nodpi/a_002.png b/third_party/enote-sdk/Sample Code/nRefresh/res/drawable-nodpi/a_002.png new file mode 100755 index 0000000..d2ec71c Binary files /dev/null and b/third_party/enote-sdk/Sample Code/nRefresh/res/drawable-nodpi/a_002.png differ diff --git a/third_party/enote-sdk/Sample Code/nRefresh/res/drawable-nodpi/a_003.png b/third_party/enote-sdk/Sample Code/nRefresh/res/drawable-nodpi/a_003.png new file mode 100755 index 0000000..80fed28 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/nRefresh/res/drawable-nodpi/a_003.png differ diff --git a/third_party/enote-sdk/Sample Code/nRefresh/res/drawable-nodpi/a_004.png b/third_party/enote-sdk/Sample Code/nRefresh/res/drawable-nodpi/a_004.png new file mode 100755 index 0000000..6ffb1a5 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/nRefresh/res/drawable-nodpi/a_004.png differ diff --git a/third_party/enote-sdk/Sample Code/nRefresh/res/drawable-nodpi/a_005.png b/third_party/enote-sdk/Sample Code/nRefresh/res/drawable-nodpi/a_005.png new file mode 100755 index 0000000..42cc207 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/nRefresh/res/drawable-nodpi/a_005.png differ diff --git a/third_party/enote-sdk/Sample Code/nRefresh/res/drawable-nodpi/a_006.png b/third_party/enote-sdk/Sample Code/nRefresh/res/drawable-nodpi/a_006.png new file mode 100755 index 0000000..8ae2438 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/nRefresh/res/drawable-nodpi/a_006.png differ diff --git a/third_party/enote-sdk/Sample Code/nRefresh/res/drawable-nodpi/a_007.png b/third_party/enote-sdk/Sample Code/nRefresh/res/drawable-nodpi/a_007.png new file mode 100755 index 0000000..d90db27 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/nRefresh/res/drawable-nodpi/a_007.png differ diff --git a/third_party/enote-sdk/Sample Code/nRefresh/res/drawable-nodpi/default_photo.png b/third_party/enote-sdk/Sample Code/nRefresh/res/drawable-nodpi/default_photo.png new file mode 100755 index 0000000..3fb5f77 Binary files /dev/null and b/third_party/enote-sdk/Sample Code/nRefresh/res/drawable-nodpi/default_photo.png differ diff --git a/third_party/enote-sdk/Sample Code/nRefresh/res/layout/main.xml b/third_party/enote-sdk/Sample Code/nRefresh/res/layout/main.xml new file mode 100755 index 0000000..a912d62 --- /dev/null +++ b/third_party/enote-sdk/Sample Code/nRefresh/res/layout/main.xml @@ -0,0 +1,156 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +