Split integrations and export into ext module

feat: move integrations from lib to ext
feat: move content export from lib to ext
feat: rename affected packages for separate module distribution
chore: update Gradle module wiring
chore: adjust JPMS descriptors and dependencies
docs: update module structure documentation
This commit is contained in:
2026-04-01 20:43:10 +02:00
parent 354e9dd9bc
commit d1bdf7d9df
30 changed files with 233 additions and 49 deletions

View File

@@ -9,6 +9,7 @@ dependencies {
implementation 'org.apache.commons:commons-text'
implementation 'commons-cli:commons-cli'
implementation project(':lib')
implementation project(':ext')
// might be removed if I move BC ops to the lib
testImplementation 'org.bouncycastle:bcpkix-jdk18on'
}

View File

@@ -51,8 +51,8 @@ import org.apache.commons.cli.OptionGroup;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import zeroecho.sdk.integrations.covert.jpeg.JpegExifEmbedder;
import zeroecho.sdk.integrations.covert.jpeg.Slot;
import zeroecho.ext.integrations.covert.jpeg.JpegExifEmbedder;
import zeroecho.ext.integrations.covert.jpeg.Slot;
/**
* Command-line extension of ZeroEcho for covert embedding and extraction of

32
ext/.classpath Normal file
View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="bin/main" path="src/main/java">
<attributes>
<attribute name="gradle_scope" value="main"/>
<attribute name="gradle_used_by_scope" value="main,test"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="bin/main" path="src/main/resources">
<attributes>
<attribute name="gradle_scope" value="main"/>
<attribute name="gradle_used_by_scope" value="main,test"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="bin/test" path="src/test/java">
<attributes>
<attribute name="gradle_scope" value="test"/>
<attribute name="gradle_used_by_scope" value="test"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="bin/test" path="src/test/resources">
<attributes>
<attribute name="gradle_scope" value="test"/>
<attribute name="gradle_used_by_scope" value="test"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-21/"/>
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
<classpathentry kind="output" path="bin/default"/>
</classpath>

23
ext/.project Normal file
View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>ext</name>
<comment>Project ext created by Buildship.</comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
</natures>
</projectDescription>

31
ext/LICENSE Normal file
View File

@@ -0,0 +1,31 @@
Copyright (C) 2026, Leo Galambos
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.
3. All advertising materials mentioning features or use of this software must
display the following acknowledgement:
This product includes software developed by the Egothor project.
4. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
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.

13
ext/build.gradle Normal file
View File

@@ -0,0 +1,13 @@
plugins {
id 'buildlogic.java-library-conventions'
id 'com.palantir.git-version'
}
group='org.egothor'
dependencies {
api 'org.bouncycastle:bcpkix-jdk18on'
implementation 'org.apache.commons:commons-imaging'
implementation project(':lib')
testImplementation 'org.egothor:conflux'
}

View File

@@ -31,7 +31,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
package zeroecho.sdk.content.export;
package zeroecho.ext.content.export;
import java.io.ByteArrayInputStream;
import java.io.IOException;

View File

@@ -31,7 +31,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
package zeroecho.sdk.content.export;
package zeroecho.ext.content.export;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;

View File

@@ -36,10 +36,10 @@
*
* <p>
* This package provides streaming utilities and exportable content
* implementations that render {@link zeroecho.sdk.content.api.DataContent} for
* implementations that render {@link zeroecho.ext.content.api.DataContent} for
* deployment to external platforms or for script-based transport. Exports can
* be produced as raw bytes or as platform-specific scripts according to
* {@link zeroecho.sdk.content.api.ExportableDataContent.ExportMode}.
* {@link zeroecho.ext.content.api.ExportableDataContent.ExportMode}.
* </p>
*
* <h2>Scope</h2>
@@ -60,15 +60,15 @@
* <li><i>Piwigo uploader</i> - an exportable content implementation
* (package-private) that can either upload an image directly to a Piwigo server
* or generate Bash/CMD scripts that reconstruct and upload the image. It is
* built on {@link zeroecho.sdk.content.api.AbstractExportableDataContent} and
* built on {@link zeroecho.ext.content.api.AbstractExportableDataContent} and
* honors
* {@link zeroecho.sdk.content.api.ExportableDataContent.ExportMode}.</li>
* {@link zeroecho.ext.content.api.ExportableDataContent.ExportMode}.</li>
* </ul>
*
* <h2>Typical usage</h2>
* <h3>Format a stream as Base64 command lines</h3> <pre>{@code
* java.io.InputStream source = ... raw bytes ...;
* java.io.InputStream encoded = new zeroecho.sdk.content.export.Base64Stream(
* java.io.InputStream encoded = new zeroecho.ext.content.export.Base64Stream(
* source,
* "echo ".getBytes(java.nio.charset.StandardCharsets.UTF_8),
* 76,
@@ -78,8 +78,8 @@
* }</pre>
*
* <h3>Render an exportable content in a chosen mode</h3> <pre>{@code
* zeroecho.sdk.content.api.ExportableDataContent content = ... some exportable content ...;
* content.setExportMode(zeroecho.sdk.content.api.ExportableDataContent.ExportMode.BASH_SCRIPT);
* zeroecho.ext.content.api.ExportableDataContent content = ... some exportable content ...;
* content.setExportMode(zeroecho.ext.content.api.ExportableDataContent.ExportMode.BASH_SCRIPT);
* try (java.io.InputStream script = content.getStream()) {
* script.transferTo(out);
* }
@@ -87,7 +87,7 @@
*
* <h2>Security notes</h2>
* <ul>
* <li>Prefer exporting {@link zeroecho.sdk.content.api.EncryptedContent} when
* <li>Prefer exporting {@link zeroecho.ext.content.api.EncryptedContent} when
* targeting untrusted destinations.</li>
* <li>Avoid embedding secrets in scripts; pass credentials via environment
* variables or secure stores when possible.</li>
@@ -98,8 +98,8 @@
* <h2>Extensibility</h2>
* <ul>
* <li>New deployers should extend
* {@link zeroecho.sdk.content.api.AbstractExportableDataContent} and select a
* default {@link zeroecho.sdk.content.api.ExportableDataContent.ExportMode}
* {@link zeroecho.ext.content.api.AbstractExportableDataContent} and select a
* default {@link zeroecho.ext.content.api.ExportableDataContent.ExportMode}
* appropriate for the platform.</li>
* <li>Utilities like {@link Base64Stream} can be reused to generate
* platform-friendly payloads without buffering whole files.</li>
@@ -107,4 +107,4 @@
*
* @since 1.0
*/
package zeroecho.sdk.content.export;
package zeroecho.ext.content.export;

View File

@@ -0,0 +1,89 @@
/*******************************************************************************
* Copyright (C) 2026, Leo Galambos
* 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.
*
* 3. All advertising materials mentioning features or use of this software must
* display the following acknowledgement:
* This product includes software developed by the Egothor project.
*
* 4. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* 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.
******************************************************************************/
/**
* Content abstractions and streaming payloads for the SDK.
*
* <p>
* This package defines the common content model used by the SDK and organizes
* concrete sources and exporters under dedicated subpackages. Content objects
* expose streaming access to bytes and can be chained into pipelines produced
* by builder APIs.
* </p>
*
* <h2>Subpackages</h2>
* <ul>
* <li>{@link zeroecho.ext.content.export} - export helpers and platform
* deployers, such as {@link zeroecho.ext.content.export.Base64Stream} and
* exportable content that targets external destinations (for example, gallery
* platforms) or script-based transports.</li>
* </ul>
*
* <h2>Responsibilities</h2>
* <ul>
* <li>Support exportable content that can render itself as raw bytes or
* platform-specific scripts via
* {@link zeroecho.sdk.content.api.ExportableDataContent}.</li>
* </ul>
*
* <h2>Typical usage</h2> <pre>{@code
* // Stream a DataContent instance to an OutputStream.
* zeroecho.sdk.content.api.DataContent content = ... obtained from a builder chain ...;
* try (java.io.InputStream in = content.getStream()) {
* in.transferTo(out);
* }
*
* // If exportable, render in an alternate mode (for example, a shell script).
* if (content instanceof zeroecho.sdk.content.api.ExportableDataContent exportable) {
* exportable.setExportMode(
* zeroecho.sdk.content.api.ExportableDataContent.ExportMode.BASH_SCRIPT);
* try (java.io.InputStream script = exportable.getStream()) {
* script.transferTo(out);
* }
* }
* }</pre>
*
* <h2>Extensibility</h2>
* <ul>
* <li>New exporters should extend
* {@link zeroecho.sdk.content.api.AbstractExportableDataContent} and honor the
* selected
* {@link zeroecho.sdk.content.api.ExportableDataContent.ExportMode}.</li>
* <li>The export area is intended to host deployers for additional public
* platforms and, where appropriate, steganographic carriers for concealed
* delivery of encrypted streams.</li>
* </ul>
*
* @since 1.0
*/
package zeroecho.ext.content;

View File

@@ -31,7 +31,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
package zeroecho.sdk.integrations.covert;
package zeroecho.ext.integrations.covert;
import java.util.ArrayDeque;
import java.util.Map;

View File

@@ -31,7 +31,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
package zeroecho.sdk.integrations.covert.jpeg;
package zeroecho.ext.integrations.covert.jpeg;
import java.io.IOException;
import java.io.InputStream;

View File

@@ -31,7 +31,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
package zeroecho.sdk.integrations.covert.jpeg;
package zeroecho.ext.integrations.covert.jpeg;
import java.util.HashMap;
import java.util.List;

View File

@@ -110,4 +110,4 @@
*
* @since 1.0
*/
package zeroecho.sdk.integrations.covert.jpeg;
package zeroecho.ext.integrations.covert.jpeg;

View File

@@ -54,8 +54,8 @@
*
* <h2>Typical usage</h2> <pre>{@code
* // Use the built-in English distribution to create a short cover text.
* zeroecho.sdk.integrations.covert.TextualCodec.Generator gen =
* zeroecho.sdk.integrations.covert.TextualCodec.Generator.EN;
* zeroecho.ext.integrations.covert.TextualCodec.Generator gen =
* zeroecho.ext.integrations.covert.TextualCodec.Generator.EN;
* String sample = gen.getText(256);
*
* // Or construct a custom distribution.
@@ -63,8 +63,8 @@
* java.util.Map.entry('e', 12.7), java.util.Map.entry('t', 9.1),
* java.util.Map.entry('a', 8.2), java.util.Map.entry(' ', 25.4)
* );
* zeroecho.sdk.integrations.covert.TextualCodec.Generator custom =
* new zeroecho.sdk.integrations.covert.TextualCodec.Generator(freq);
* zeroecho.ext.integrations.covert.TextualCodec.Generator custom =
* new zeroecho.ext.integrations.covert.TextualCodec.Generator(freq);
* String cover = custom.getText(128);
* }</pre>
*
@@ -78,4 +78,4 @@
*
* @since 1.0
*/
package zeroecho.sdk.integrations.covert;
package zeroecho.ext.integrations.covert;

View File

@@ -31,7 +31,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
package zeroecho.sdk.integrations.stegano;
package zeroecho.ext.integrations.stegano;
/**
* Enumeration of image formats supported for steganographic processing.

View File

@@ -31,7 +31,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
package zeroecho.sdk.integrations.stegano;
package zeroecho.ext.integrations.stegano;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;

View File

@@ -31,7 +31,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
package zeroecho.sdk.integrations.stegano;
package zeroecho.ext.integrations.stegano;
import java.io.IOException;
import java.io.InputStream;

View File

@@ -31,7 +31,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
package zeroecho.sdk.integrations.stegano;
package zeroecho.ext.integrations.stegano;
/**
* Metadata that describes a steganographic method.

View File

@@ -44,11 +44,11 @@
* <h2>Design principles</h2>
* <ul>
* <li>All algorithms implement the
* {@link zeroecho.sdk.integrations.stegano.SteganographyMethod} interface,
* {@link zeroecho.ext.integrations.stegano.SteganographyMethod} interface,
* which defines stream-oriented {@code embed} and {@code extract} operations
* and supplies a metadata descriptor.</li>
* <li>Supported carrier formats are represented by
* {@link zeroecho.sdk.integrations.stegano.ImageFormat}. Only lossless formats
* {@link zeroecho.ext.integrations.stegano.ImageFormat}. Only lossless formats
* are suitable for direct bit-level embedding, but some algorithms may also
* provide support for lossy domains such as JPEG with dedicated
* techniques.</li>
@@ -64,7 +64,7 @@
* the frequency domain (for example, DCT coefficients for JPEG) or more
* advanced hybrid techniques. New methods can be registered by implementing the
* {@code SteganographyMethod} interface and returning appropriate
* {@link zeroecho.sdk.integrations.stegano.StegoMetadata}.
* {@link zeroecho.ext.integrations.stegano.StegoMetadata}.
* </p>
*
* <h2>Typical workflow</h2> <pre>{@code
@@ -81,4 +81,4 @@
* }
* }</pre>
*/
package zeroecho.sdk.integrations.stegano;
package zeroecho.ext.integrations.stegano;

View File

@@ -31,7 +31,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
package zeroecho.sdk.content.export;
package zeroecho.ext.content.export;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

View File

@@ -31,7 +31,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
package zeroecho.sdk.integrations.covert;
package zeroecho.ext.integrations.covert;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

View File

@@ -31,7 +31,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
package zeroecho.sdk.integrations.covert.jpeg;
package zeroecho.ext.integrations.covert.jpeg;
import static org.junit.jupiter.api.Assertions.assertEquals;

View File

@@ -31,7 +31,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
package zeroecho.sdk.integrations.stegano;
package zeroecho.ext.integrations.stegano;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

View File

Before

Width:  |  Height:  |  Size: 230 KiB

After

Width:  |  Height:  |  Size: 230 KiB

View File

@@ -13,13 +13,6 @@
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="bin/test" path="src/test/resources">
<attributes>
<attribute name="gradle_scope" value="test"/>
<attribute name="gradle_used_by_scope" value="test"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="bin/main" path="src/main/resources">
<attributes>
<attribute name="gradle_scope" value="main"/>

View File

@@ -8,7 +8,6 @@ group='org.egothor'
dependencies {
api 'org.bouncycastle:bcpkix-jdk18on'
implementation 'org.egothor:conflux'
implementation 'org.apache.commons:commons-imaging'
}

View File

@@ -54,10 +54,6 @@
* {@link zeroecho.sdk.content.builtin.PlainString},
* {@link zeroecho.sdk.content.builtin.PlainFile}, and
* {@link zeroecho.sdk.content.builtin.SecretPassword}.</li>
* <li>{@link zeroecho.sdk.content.export} - export helpers and platform
* deployers, such as {@link zeroecho.sdk.content.export.Base64Stream} and
* exportable content that targets external destinations (for example, gallery
* platforms) or script-based transports.</li>
* </ul>
*
* <h2>Responsibilities</h2>

View File

@@ -19,6 +19,13 @@
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="bin/test" path="src/test/resources">
<attributes>
<attribute name="gradle_scope" value="test"/>
<attribute name="gradle_used_by_scope" value="test"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-21/"/>
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
<classpathentry kind="output" path="bin/default"/>

View File

@@ -11,4 +11,4 @@ plugins {
rootProject.name = 'ZeroEcho'
include('app', 'lib', 'pki', 'samples')
include('app', 'ext', 'lib', 'pki', 'samples')