From 4b6e811de521e4f9e959820ce6dc9c7c2283a212 Mon Sep 17 00:00:00 2001 From: DemchaAV Date: Sun, 5 Jul 2026 16:25:21 +0100 Subject: [PATCH 1/3] build: extract the semantic DOCX/PPTX backend into graph-compose-render-docx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split the POI-backed semantic office backend out of the engine jar so the lean core no longer carries Apache POI. - New standalone render-docx/ module (lockstep-versioned with the engine): moves DocxSemanticBackend and the PptxSemanticBackend stub into new format packages document.backend.semantic.docx / .pptx (the SPI — SemanticBackend, SemanticExportContext, SemanticExportManifest — stays in the core document.backend.semantic package; a split package is not allowed). poi-ooxml is a plain compile dependency here. - Root pom drops the poi-ooxml dependency. The DocumentSession export test that exercised both backends moves to render-docx as SessionSemanticExportTest (the engine test scope can no longer see the backends); its no-poi guard is dropped because POI is always present in this module. - aggregator adds the module; examples depend on graph-compose-render-docx (which brings POI transitively) and WordExportExample imports the new FQN. Reactor build green: render-docx compiles and its docx tests pass, while the root builds POI-free. --- aggregator/pom.xml | 1 + examples/pom.xml | 12 +- .../features/docx/WordExportExample.java | 2 +- pom.xml | 13 - render-docx/pom.xml | 228 ++++++++++++++++++ .../semantic/docx}/DocxSemanticBackend.java | 4 +- .../semantic/pptx}/PptxSemanticBackend.java | 5 +- .../semantic/docx}/DocxGeometryDropTest.java | 2 +- .../semantic/docx}/DocxListParityTest.java | 2 +- .../docx}/DocxSemanticBackendTest.java | 2 +- .../docx/SessionSemanticExportTest.java | 70 ++++++ .../document/api/DocumentSessionTest.java | 46 ---- 12 files changed, 316 insertions(+), 71 deletions(-) create mode 100644 render-docx/pom.xml rename {src/main/java/com/demcha/compose/document/backend/semantic => render-docx/src/main/java/com/demcha/compose/document/backend/semantic/docx}/DocxSemanticBackend.java (99%) rename {src/main/java/com/demcha/compose/document/backend/semantic => render-docx/src/main/java/com/demcha/compose/document/backend/semantic/pptx}/PptxSemanticBackend.java (87%) rename {src/test/java/com/demcha/compose/document/backend/semantic => render-docx/src/test/java/com/demcha/compose/document/backend/semantic/docx}/DocxGeometryDropTest.java (98%) rename {src/test/java/com/demcha/compose/document/backend/semantic => render-docx/src/test/java/com/demcha/compose/document/backend/semantic/docx}/DocxListParityTest.java (98%) rename {src/test/java/com/demcha/compose/document/backend/semantic => render-docx/src/test/java/com/demcha/compose/document/backend/semantic/docx}/DocxSemanticBackendTest.java (99%) create mode 100644 render-docx/src/test/java/com/demcha/compose/document/backend/semantic/docx/SessionSemanticExportTest.java diff --git a/aggregator/pom.xml b/aggregator/pom.xml index a8e19102a..2f5361242 100644 --- a/aggregator/pom.xml +++ b/aggregator/pom.xml @@ -60,6 +60,7 @@ .. ../fonts ../emoji + ../render-docx ../bundle ../examples ../benchmarks diff --git a/examples/pom.xml b/examples/pom.xml index 2c65ac5b1..c96aad7fe 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -67,13 +67,13 @@ ${graphcompose.emoji.version} - + - org.apache.poi - poi-ooxml - 5.5.1 + io.github.demchaav + graph-compose-render-docx + ${graphcompose.version} diff --git a/examples/src/main/java/com/demcha/examples/features/docx/WordExportExample.java b/examples/src/main/java/com/demcha/examples/features/docx/WordExportExample.java index e16da1429..86e9ff5cb 100644 --- a/examples/src/main/java/com/demcha/examples/features/docx/WordExportExample.java +++ b/examples/src/main/java/com/demcha/examples/features/docx/WordExportExample.java @@ -2,7 +2,7 @@ import com.demcha.compose.GraphCompose; import com.demcha.compose.document.api.DocumentSession; -import com.demcha.compose.document.backend.semantic.DocxSemanticBackend; +import com.demcha.compose.document.backend.semantic.docx.DocxSemanticBackend; import com.demcha.compose.document.chart.ChartData; import com.demcha.compose.document.chart.ChartSpec; import com.demcha.compose.document.image.DocumentImageData; diff --git a/pom.xml b/pom.xml index b6b2b5474..f73f309bd 100644 --- a/pom.xml +++ b/pom.xml @@ -182,19 +182,6 @@ ${flexmark.version} - - - org.apache.poi - poi-ooxml - ${poi.version} - true - - com.fasterxml.jackson.core jackson-annotations diff --git a/render-docx/pom.xml b/render-docx/pom.xml new file mode 100644 index 000000000..8b535b4a4 --- /dev/null +++ b/render-docx/pom.xml @@ -0,0 +1,228 @@ + + + 4.0.0 + + + io.github.demchaav + graph-compose-render-docx + 2.0.0-SNAPSHOT + + GraphCompose Render — DOCX + Semantic DOCX / PPTX export backend for GraphCompose, backed by Apache POI. + https://github.com/DemchaAV/GraphCompose + + + + MIT License + https://opensource.org/licenses/MIT + repo + + + + + + DemchaAV + Artem Demchyshyn + demchishynartem@gmail.com + https://github.com/DemchaAV + + Lead Developer + Architect + + UTC 0 + + + + + scm:git:https://github.com/DemchaAV/GraphCompose.git + scm:git:ssh://git@github.com/DemchaAV/GraphCompose.git + https://github.com/DemchaAV/GraphCompose/tree/main + + + + UTF-8 + 17 + + 5.5.1 + 6.1.1 + 3.27.7 + 1.5.37 + 1.0.0 + 1.0.0 + + 3.15.0 + 3.5.0 + 3.5.6 + 3.4.0 + 3.12.0 + 3.2.8 + 0.11.0 + + + true + + + + + io.github.demchaav + graph-compose + ${project.version} + + + org.apache.poi + poi-ooxml + ${poi.version} + + + + + org.junit.jupiter + junit-jupiter + ${junit.bom.version} + test + + + org.assertj + assertj-core + ${assertj.version} + test + + + ch.qos.logback + logback-classic + ${logback.version} + test + + + + io.github.demchaav + graph-compose-fonts + ${graphcompose.fonts.version} + test + + + io.github.demchaav + graph-compose-emoji + ${graphcompose.emoji.version} + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven.compiler.plugin.version} + + ${maven.compiler.release} + + + + org.apache.maven.plugins + maven-surefire-plugin + ${maven.surefire.plugin.version} + + + org.apache.maven.plugins + maven-jar-plugin + ${maven.jar.plugin.version} + + + + + + + + release + + + + org.apache.maven.plugins + maven-source-plugin + ${maven.source.plugin.version} + + + attach-sources + package + + jar-no-fork + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${maven.javadoc.plugin.version} + + + attach-javadocs + package + + jar + + + none + false + true + + + + + + org.apache.maven.plugins + maven-gpg-plugin + ${maven.gpg.plugin.version} + + + sign-artifacts + verify + + sign + + + ${gpg.skip} + + --pinentry-mode + loopback + + + + + + + org.sonatype.central + central-publishing-maven-plugin + ${central.publishing.plugin.version} + true + + central + false + validated + + + + + + + diff --git a/src/main/java/com/demcha/compose/document/backend/semantic/DocxSemanticBackend.java b/render-docx/src/main/java/com/demcha/compose/document/backend/semantic/docx/DocxSemanticBackend.java similarity index 99% rename from src/main/java/com/demcha/compose/document/backend/semantic/DocxSemanticBackend.java rename to render-docx/src/main/java/com/demcha/compose/document/backend/semantic/docx/DocxSemanticBackend.java index 94ff939f1..8f3e56688 100644 --- a/src/main/java/com/demcha/compose/document/backend/semantic/DocxSemanticBackend.java +++ b/render-docx/src/main/java/com/demcha/compose/document/backend/semantic/docx/DocxSemanticBackend.java @@ -1,5 +1,7 @@ -package com.demcha.compose.document.backend.semantic; +package com.demcha.compose.document.backend.semantic.docx; +import com.demcha.compose.document.backend.semantic.SemanticBackend; +import com.demcha.compose.document.backend.semantic.SemanticExportContext; import com.demcha.compose.document.chart.ChartData; import com.demcha.compose.document.chart.NumberFormatSpec; import com.demcha.compose.document.dsl.TableBuilder; diff --git a/src/main/java/com/demcha/compose/document/backend/semantic/PptxSemanticBackend.java b/render-docx/src/main/java/com/demcha/compose/document/backend/semantic/pptx/PptxSemanticBackend.java similarity index 87% rename from src/main/java/com/demcha/compose/document/backend/semantic/PptxSemanticBackend.java rename to render-docx/src/main/java/com/demcha/compose/document/backend/semantic/pptx/PptxSemanticBackend.java index da8d5b90b..07a357382 100644 --- a/src/main/java/com/demcha/compose/document/backend/semantic/PptxSemanticBackend.java +++ b/render-docx/src/main/java/com/demcha/compose/document/backend/semantic/pptx/PptxSemanticBackend.java @@ -1,5 +1,8 @@ -package com.demcha.compose.document.backend.semantic; +package com.demcha.compose.document.backend.semantic.pptx; +import com.demcha.compose.document.backend.semantic.SemanticBackend; +import com.demcha.compose.document.backend.semantic.SemanticExportContext; +import com.demcha.compose.document.backend.semantic.SemanticExportManifest; import com.demcha.compose.document.layout.DocumentGraph; import com.demcha.compose.document.exceptions.UnsupportedNodeCapabilityException; import com.demcha.compose.document.node.ContainerNode; diff --git a/src/test/java/com/demcha/compose/document/backend/semantic/DocxGeometryDropTest.java b/render-docx/src/test/java/com/demcha/compose/document/backend/semantic/docx/DocxGeometryDropTest.java similarity index 98% rename from src/test/java/com/demcha/compose/document/backend/semantic/DocxGeometryDropTest.java rename to render-docx/src/test/java/com/demcha/compose/document/backend/semantic/docx/DocxGeometryDropTest.java index 0bb8a906c..93402fd76 100644 --- a/src/test/java/com/demcha/compose/document/backend/semantic/DocxGeometryDropTest.java +++ b/render-docx/src/test/java/com/demcha/compose/document/backend/semantic/docx/DocxGeometryDropTest.java @@ -1,4 +1,4 @@ -package com.demcha.compose.document.backend.semantic; +package com.demcha.compose.document.backend.semantic.docx; import com.demcha.compose.GraphCompose; import com.demcha.compose.document.api.DocumentSession; diff --git a/src/test/java/com/demcha/compose/document/backend/semantic/DocxListParityTest.java b/render-docx/src/test/java/com/demcha/compose/document/backend/semantic/docx/DocxListParityTest.java similarity index 98% rename from src/test/java/com/demcha/compose/document/backend/semantic/DocxListParityTest.java rename to render-docx/src/test/java/com/demcha/compose/document/backend/semantic/docx/DocxListParityTest.java index d417955c6..70dcec541 100644 --- a/src/test/java/com/demcha/compose/document/backend/semantic/DocxListParityTest.java +++ b/render-docx/src/test/java/com/demcha/compose/document/backend/semantic/docx/DocxListParityTest.java @@ -1,4 +1,4 @@ -package com.demcha.compose.document.backend.semantic; +package com.demcha.compose.document.backend.semantic.docx; import com.demcha.compose.GraphCompose; import com.demcha.compose.document.api.DocumentSession; diff --git a/src/test/java/com/demcha/compose/document/backend/semantic/DocxSemanticBackendTest.java b/render-docx/src/test/java/com/demcha/compose/document/backend/semantic/docx/DocxSemanticBackendTest.java similarity index 99% rename from src/test/java/com/demcha/compose/document/backend/semantic/DocxSemanticBackendTest.java rename to render-docx/src/test/java/com/demcha/compose/document/backend/semantic/docx/DocxSemanticBackendTest.java index 7491effc6..2671e66f2 100644 --- a/src/test/java/com/demcha/compose/document/backend/semantic/DocxSemanticBackendTest.java +++ b/render-docx/src/test/java/com/demcha/compose/document/backend/semantic/docx/DocxSemanticBackendTest.java @@ -1,4 +1,4 @@ -package com.demcha.compose.document.backend.semantic; +package com.demcha.compose.document.backend.semantic.docx; import com.demcha.compose.GraphCompose; import com.demcha.compose.document.api.DocumentSession; diff --git a/render-docx/src/test/java/com/demcha/compose/document/backend/semantic/docx/SessionSemanticExportTest.java b/render-docx/src/test/java/com/demcha/compose/document/backend/semantic/docx/SessionSemanticExportTest.java new file mode 100644 index 000000000..0838cd706 --- /dev/null +++ b/render-docx/src/test/java/com/demcha/compose/document/backend/semantic/docx/SessionSemanticExportTest.java @@ -0,0 +1,70 @@ +package com.demcha.compose.document.backend.semantic.docx; + +import com.demcha.compose.GraphCompose; +import com.demcha.compose.document.api.DocumentSession; +import com.demcha.compose.document.backend.semantic.SemanticExportManifest; +import com.demcha.compose.document.backend.semantic.pptx.PptxSemanticBackend; +import com.demcha.compose.document.node.ContainerNode; +import com.demcha.compose.document.node.ParagraphNode; +import com.demcha.compose.document.node.ShapeNode; +import com.demcha.compose.document.node.TextAlign; +import com.demcha.compose.document.style.DocumentColor; +import com.demcha.compose.document.style.DocumentInsets; +import com.demcha.compose.document.style.DocumentStroke; +import com.demcha.compose.document.style.DocumentTextStyle; +import org.junit.jupiter.api.Test; + +import java.awt.Color; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Exercises {@code DocumentSession.export(...)} with the semantic office backends + * from their new home. Moved out of the engine's {@code DocumentSessionTest} when + * the DOCX/PPTX backends were extracted to graph-compose-render-docx (the engine + * test scope can no longer see them). POI is always present in this module, so the + * old no-poi guard is dropped. + */ +class SessionSemanticExportTest { + + @Test + void semanticBackendsShouldExportManifestsFromDocumentGraph() throws Exception { + try (DocumentSession session = GraphCompose.document() + .pageSize(200, 200) + .margin(DocumentInsets.of(10)) + .create()) { + + session.add(new ContainerNode( + "DocxRoot", + List.of(new ParagraphNode("P", "Hello world", DocumentTextStyle.DEFAULT, TextAlign.LEFT, 0, DocumentInsets.zero(), DocumentInsets.zero())), + 8, + DocumentInsets.zero(), + DocumentInsets.zero(), + null, + null)); + + byte[] docx = session.export(new DocxSemanticBackend()); + + assertThat(docx).isNotEmpty(); + // DOCX files are ZIP-archived OOXML packages; the first two bytes + // of any ZIP container are the local-file-header signature. + assertThat(docx[0]).isEqualTo((byte) 'P'); + assertThat(docx[1]).isEqualTo((byte) 'K'); + + session.clear(); + session.add(new ContainerNode( + "PptxRoot", + List.of(new ShapeNode("Box", 40, 20, Color.BLUE, DocumentStroke.of(DocumentColor.BLACK, 1), DocumentInsets.zero(), DocumentInsets.zero())), + 8, + DocumentInsets.zero(), + DocumentInsets.zero(), + null, + null)); + + SemanticExportManifest pptx = session.export(new PptxSemanticBackend()); + assertThat(pptx.backendName()).isEqualTo("pptx-semantic"); + assertThat(pptx.nodeKinds()).contains("ContainerNode", "ShapeNode"); + } + } +} diff --git a/src/test/java/com/demcha/compose/document/api/DocumentSessionTest.java b/src/test/java/com/demcha/compose/document/api/DocumentSessionTest.java index f273924a7..4a5231147 100644 --- a/src/test/java/com/demcha/compose/document/api/DocumentSessionTest.java +++ b/src/test/java/com/demcha/compose/document/api/DocumentSessionTest.java @@ -19,10 +19,7 @@ import com.demcha.compose.engine.measurement.FontLibraryTextMeasurementSystem; import com.demcha.compose.document.backend.fixed.FixedLayoutBackend; import com.demcha.compose.document.backend.fixed.FixedLayoutRenderContext; -import com.demcha.compose.document.backend.semantic.DocxSemanticBackend; import com.demcha.compose.document.backend.fixed.pdf.PdfFixedLayoutBackend; -import com.demcha.compose.document.backend.semantic.PptxSemanticBackend; -import com.demcha.compose.document.backend.semantic.SemanticExportManifest; import com.demcha.compose.document.exceptions.AtomicNodeTooLargeException; import com.demcha.compose.document.image.DocumentImageFitMode; import com.demcha.compose.document.layout.BoxConstraints; @@ -74,7 +71,6 @@ import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.DisabledIfSystemProperty; import org.apache.pdfbox.rendering.PDFRenderer; import org.apache.pdfbox.text.PDFTextStripper; @@ -787,48 +783,6 @@ void registryRegisterOnClosedSessionThrowsIllegalStateException() { .isInstanceOf(IllegalStateException.class); } - @Test - @DisabledIfSystemProperty(named = "no.poi", matches = "true", - disabledReason = "Exercises DocxSemanticBackend; skipped under the no-poi profile that excludes poi-ooxml from the test classpath") - void semanticBackendsShouldExportManifestsFromDocumentGraph() throws Exception { - try (DocumentSession session = GraphCompose.document() - .pageSize(200, 200) - .margin(DocumentInsets.of(10)) - .create()) { - - session.add(new ContainerNode( - "DocxRoot", - List.of(new ParagraphNode("P", "Hello world", DocumentTextStyle.DEFAULT, TextAlign.LEFT, 0, DocumentInsets.zero(), DocumentInsets.zero())), - 8, - DocumentInsets.zero(), - DocumentInsets.zero(), - null, - null)); - - byte[] docx = session.export(new DocxSemanticBackend()); - - assertThat(docx).isNotEmpty(); - // DOCX files are ZIP-archived OOXML packages; the first two bytes - // of any ZIP container are the local-file-header signature. - assertThat(docx[0]).isEqualTo((byte) 'P'); - assertThat(docx[1]).isEqualTo((byte) 'K'); - - session.clear(); - session.add(new ContainerNode( - "PptxRoot", - List.of(new ShapeNode("Box", 40, 20, Color.BLUE, DocumentStroke.of(DocumentColor.BLACK, 1), DocumentInsets.zero(), DocumentInsets.zero())), - 8, - DocumentInsets.zero(), - DocumentInsets.zero(), - null, - null)); - - SemanticExportManifest pptx = session.export(new PptxSemanticBackend()); - assertThat(pptx.backendName()).isEqualTo("pptx-semantic"); - assertThat(pptx.nodeKinds()).contains("ContainerNode", "ShapeNode"); - } - } - @Test void documentLevelPdfOptionsShouldReuseCompiledLayout() throws Exception { try (DocumentSession session = GraphCompose.document() From 129ff461439682551a7cfa0864fb4d0aa2d02bae Mon Sep 17 00:00:00 2001 From: DemchaAV Date: Sun, 5 Jul 2026 16:43:48 +0100 Subject: [PATCH 2/3] build: retire the no-poi machinery and wire render-docx into release/CI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that Apache POI lives only in graph-compose-render-docx, drop the engine's POI-optional plumbing and register the new module in the release/CI pipeline. - Root pom: remove the now-unused poi.version property and the no-poi profile (the surefire POI-exclusion + no.poi system property) — POI is no longer on the engine classpath, so there is nothing to exclude. - ci.yml: drop the no-poi-suite job; add a graph-compose-render-docx install step to the examples-generation job (the DOCX example resolves the backend there). - publish.yml: deploy graph-compose-render-docx to Central on the v* tag, after the engine (its graph-compose dependency). - cut-release.ps1: bump render-docx/pom.xml in lockstep and add it to the commit staging allow-list. - Reword the DocxSemanticBackend "optional POI" javadoc — POI ships with the module now. --- .github/workflows/ci.yml | 34 ++++--------------- .github/workflows/publish.yml | 10 ++++++ pom.xml | 34 ------------------- .../semantic/docx/DocxSemanticBackend.java | 7 ++-- scripts/cut-release.ps1 | 4 +++ 5 files changed, 24 insertions(+), 65 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2f54dc0d3..3201cb851 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -114,6 +114,12 @@ jobs: - name: Install root artifact run: ./mvnw -B -ntp -DskipTests install -pl . + - name: Install graph-compose-render-docx (consumed by the examples module) + # The DOCX export example depends on the render-docx backend module, which + # is not on Central. Install it after the engine (its graph-compose + # dependency) so the examples build resolves it. + run: ./mvnw -B -ntp -f render-docx/pom.xml -DskipTests install + - name: Compile examples module run: ./mvnw -B -ntp -f examples/pom.xml clean compile @@ -137,34 +143,6 @@ jobs: path: examples/target/generated-pdfs/** if-no-files-found: error - no-poi-suite: - name: Test suite without poi-ooxml (optional-deps regression) - if: github.event_name == 'pull_request' - needs: architecture-and-documentation-guards - runs-on: ubuntu-latest - env: - JAVA_TOOL_OPTIONS: -Djava.awt.headless=true - - steps: - - name: Check out repository - uses: actions/checkout@v7 - - - name: Set up Temurin JDK 17 - uses: actions/setup-java@v5 - with: - distribution: temurin - java-version: '17' - cache: maven - - - name: Run suite under -P no-poi - # poi-ooxml is declared true; this job - # validates that callers who don't render DOCX still get a - # green suite without the POI footprint. Tests that require - # poi (DocxSemanticBackend output) carry - # @DisabledIfSystemProperty(named = "no.poi", matches = "true") - # and skip cleanly. See Track I1 in the readiness taskboard. - run: ./mvnw -B -ntp test -pl . -P no-poi - binary-compat: name: Binary Compatibility (japicmp vs pom baseline) if: github.event_name == 'pull_request' diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 7e6e26c35..f0be42a20 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -99,6 +99,16 @@ jobs: CENTRAL_TOKEN: ${{ secrets.CENTRAL_TOKEN }} MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }} + - name: Publish render-docx to Maven Central + # The semantic DOCX/PPTX backend, lockstep-versioned with the engine + # (ships on the same v* tag). graph-compose resolves from the local repo + # installed by the engine deploy above. + run: ./mvnw -B -ntp -f render-docx/pom.xml -P release -DskipTests -Dgpg.skip=false deploy + env: + CENTRAL_USERNAME: ${{ secrets.CENTRAL_USERNAME }} + CENTRAL_TOKEN: ${{ secrets.CENTRAL_TOKEN }} + MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }} + - name: Publish bundle to Maven Central # The graph-compose-bundle convenience aggregate pins this engine # version + a compatible graph-compose-fonts version. It tracks the diff --git a/pom.xml b/pom.xml index f73f309bd..9354ac2c1 100644 --- a/pom.xml +++ b/pom.xml @@ -51,7 +51,6 @@ 1.5.37 1.18.46 3.0.7 - 5.5.1 21.0.2 2.0.18 3.5.4 @@ -636,39 +635,6 @@ - - - no-poi - - - - org.apache.maven.plugins - maven-surefire-plugin - ${maven.surefire.plugin.version} - - - org.apache.poi:poi-ooxml - org.apache.poi:poi - org.apache.poi:poi-ooxml-lite - - - true - - - - - - -