From 7c49fa8f77a021acfd031f29f6952c1b8b2366e4 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 23 Mar 2025 15:43:59 +0100 Subject: [PATCH 1/5] Add JavaSMT project template for Ivy/Ant --- doc/Example-Ivy-Project/README.md | 23 ++++++ doc/Example-Ivy-Project/build.xml | 80 +++++++++++++++++++ doc/Example-Ivy-Project/ivy.xml | 16 ++++ doc/Example-Ivy-Project/lib/ivy-settings.xml | 25 ++++++ .../lib/native/arm64-linux/libbitwuzlaj.so | 1 + .../lib/native/arm64-linux/libmathsat5j.so | 1 + .../lib/native/arm64-linux/libopensmtj.so | 1 + .../lib/native/arm64-linux/libz3.so | 1 + .../lib/native/arm64-linux/libz3java.so | 1 + .../lib/native/x86_64-linux/libbitwuzlaj.so | 1 + .../lib/native/x86_64-linux/libmathsat5j.so | 1 + .../lib/native/x86_64-linux/libopensmtj.so | 1 + .../lib/native/x86_64-linux/libz3.so | 1 + .../lib/native/x86_64-linux/libz3java.so | 1 + doc/Example-Ivy-Project/src/example/Main.java | 34 ++++++++ 15 files changed, 188 insertions(+) create mode 100644 doc/Example-Ivy-Project/README.md create mode 100644 doc/Example-Ivy-Project/build.xml create mode 100644 doc/Example-Ivy-Project/ivy.xml create mode 100644 doc/Example-Ivy-Project/lib/ivy-settings.xml create mode 120000 doc/Example-Ivy-Project/lib/native/arm64-linux/libbitwuzlaj.so create mode 120000 doc/Example-Ivy-Project/lib/native/arm64-linux/libmathsat5j.so create mode 120000 doc/Example-Ivy-Project/lib/native/arm64-linux/libopensmtj.so create mode 120000 doc/Example-Ivy-Project/lib/native/arm64-linux/libz3.so create mode 120000 doc/Example-Ivy-Project/lib/native/arm64-linux/libz3java.so create mode 120000 doc/Example-Ivy-Project/lib/native/x86_64-linux/libbitwuzlaj.so create mode 120000 doc/Example-Ivy-Project/lib/native/x86_64-linux/libmathsat5j.so create mode 120000 doc/Example-Ivy-Project/lib/native/x86_64-linux/libopensmtj.so create mode 120000 doc/Example-Ivy-Project/lib/native/x86_64-linux/libz3.so create mode 120000 doc/Example-Ivy-Project/lib/native/x86_64-linux/libz3java.so create mode 100644 doc/Example-Ivy-Project/src/example/Main.java diff --git a/doc/Example-Ivy-Project/README.md b/doc/Example-Ivy-Project/README.md new file mode 100644 index 0000000000..6d94b06f17 --- /dev/null +++ b/doc/Example-Ivy-Project/README.md @@ -0,0 +1,23 @@ + + +This is an example application for using JavaSMT with Ant/Ivy. +The example application prints a table of the available SMT solvers, along with their version +number. + +The project supports the following build steps: + +- `resolve` retrieve dependencies with Ivy +- `compile` compile the project +- `package` build a .jar +- `run` run the program +- `clean` clean the project + +Calling `ant` with no target will build and then execute the project. \ No newline at end of file diff --git a/doc/Example-Ivy-Project/build.xml b/doc/Example-Ivy-Project/build.xml new file mode 100644 index 0000000000..5adde30f10 --- /dev/null +++ b/doc/Example-Ivy-Project/build.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/Example-Ivy-Project/ivy.xml b/doc/Example-Ivy-Project/ivy.xml new file mode 100644 index 0000000000..bdbe362cef --- /dev/null +++ b/doc/Example-Ivy-Project/ivy.xml @@ -0,0 +1,16 @@ + + + + + + + + diff --git a/doc/Example-Ivy-Project/lib/ivy-settings.xml b/doc/Example-Ivy-Project/lib/ivy-settings.xml new file mode 100644 index 0000000000..1da8869609 --- /dev/null +++ b/doc/Example-Ivy-Project/lib/ivy-settings.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + diff --git a/doc/Example-Ivy-Project/lib/native/arm64-linux/libbitwuzlaj.so b/doc/Example-Ivy-Project/lib/native/arm64-linux/libbitwuzlaj.so new file mode 120000 index 0000000000..372f592128 --- /dev/null +++ b/doc/Example-Ivy-Project/lib/native/arm64-linux/libbitwuzlaj.so @@ -0,0 +1 @@ +../../java/default/arm64/libbitwuzlaj.so \ No newline at end of file diff --git a/doc/Example-Ivy-Project/lib/native/arm64-linux/libmathsat5j.so b/doc/Example-Ivy-Project/lib/native/arm64-linux/libmathsat5j.so new file mode 120000 index 0000000000..c7eaf57210 --- /dev/null +++ b/doc/Example-Ivy-Project/lib/native/arm64-linux/libmathsat5j.so @@ -0,0 +1 @@ +../../java/default/arm64/libmathsat5j.so \ No newline at end of file diff --git a/doc/Example-Ivy-Project/lib/native/arm64-linux/libopensmtj.so b/doc/Example-Ivy-Project/lib/native/arm64-linux/libopensmtj.so new file mode 120000 index 0000000000..8aadd048bf --- /dev/null +++ b/doc/Example-Ivy-Project/lib/native/arm64-linux/libopensmtj.so @@ -0,0 +1 @@ +../../java/default/arm64/libopensmtj.so \ No newline at end of file diff --git a/doc/Example-Ivy-Project/lib/native/arm64-linux/libz3.so b/doc/Example-Ivy-Project/lib/native/arm64-linux/libz3.so new file mode 120000 index 0000000000..7252d0c3c0 --- /dev/null +++ b/doc/Example-Ivy-Project/lib/native/arm64-linux/libz3.so @@ -0,0 +1 @@ +../../java/default/arm64/libz3.so \ No newline at end of file diff --git a/doc/Example-Ivy-Project/lib/native/arm64-linux/libz3java.so b/doc/Example-Ivy-Project/lib/native/arm64-linux/libz3java.so new file mode 120000 index 0000000000..934e062ea2 --- /dev/null +++ b/doc/Example-Ivy-Project/lib/native/arm64-linux/libz3java.so @@ -0,0 +1 @@ +../../java/default/arm64/libz3java.so \ No newline at end of file diff --git a/doc/Example-Ivy-Project/lib/native/x86_64-linux/libbitwuzlaj.so b/doc/Example-Ivy-Project/lib/native/x86_64-linux/libbitwuzlaj.so new file mode 120000 index 0000000000..ef45bf4c23 --- /dev/null +++ b/doc/Example-Ivy-Project/lib/native/x86_64-linux/libbitwuzlaj.so @@ -0,0 +1 @@ +../../java/default/x64/libbitwuzlaj.so \ No newline at end of file diff --git a/doc/Example-Ivy-Project/lib/native/x86_64-linux/libmathsat5j.so b/doc/Example-Ivy-Project/lib/native/x86_64-linux/libmathsat5j.so new file mode 120000 index 0000000000..c734ccd975 --- /dev/null +++ b/doc/Example-Ivy-Project/lib/native/x86_64-linux/libmathsat5j.so @@ -0,0 +1 @@ +../../java/default/x64/libmathsat5j.so \ No newline at end of file diff --git a/doc/Example-Ivy-Project/lib/native/x86_64-linux/libopensmtj.so b/doc/Example-Ivy-Project/lib/native/x86_64-linux/libopensmtj.so new file mode 120000 index 0000000000..e613c908c0 --- /dev/null +++ b/doc/Example-Ivy-Project/lib/native/x86_64-linux/libopensmtj.so @@ -0,0 +1 @@ +../../java/default/x64/libopensmtj.so \ No newline at end of file diff --git a/doc/Example-Ivy-Project/lib/native/x86_64-linux/libz3.so b/doc/Example-Ivy-Project/lib/native/x86_64-linux/libz3.so new file mode 120000 index 0000000000..e2423e093d --- /dev/null +++ b/doc/Example-Ivy-Project/lib/native/x86_64-linux/libz3.so @@ -0,0 +1 @@ +../../java/default/x64/libz3.so \ No newline at end of file diff --git a/doc/Example-Ivy-Project/lib/native/x86_64-linux/libz3java.so b/doc/Example-Ivy-Project/lib/native/x86_64-linux/libz3java.so new file mode 120000 index 0000000000..392351c46a --- /dev/null +++ b/doc/Example-Ivy-Project/lib/native/x86_64-linux/libz3java.so @@ -0,0 +1 @@ +../../java/default/x64/libz3java.so \ No newline at end of file diff --git a/doc/Example-Ivy-Project/src/example/Main.java b/doc/Example-Ivy-Project/src/example/Main.java new file mode 100644 index 0000000000..4a6298c944 --- /dev/null +++ b/doc/Example-Ivy-Project/src/example/Main.java @@ -0,0 +1,34 @@ +// This file is part of JavaSMT, +// an API wrapper for a collection of SMT solvers: +// https://github.com/sosy-lab/java-smt +// +// SPDX-FileCopyrightText: 2025 Dirk Beyer +// +// SPDX-License-Identifier: Apache-2.0 + +package example; + +import org.sosy_lab.common.ShutdownNotifier; +import org.sosy_lab.common.configuration.Configuration; +import org.sosy_lab.common.configuration.InvalidConfigurationException; +import org.sosy_lab.common.log.LogManager; +import org.sosy_lab.java_smt.SolverContextFactory; +import org.sosy_lab.java_smt.SolverContextFactory.Solvers; +import org.sosy_lab.java_smt.api.SolverContext; + +public class Main { + public static void main(String[] args) { + Configuration config = Configuration.defaultConfiguration(); + LogManager logger = LogManager.createNullLogManager(); + ShutdownNotifier notifier = ShutdownNotifier.createDummy(); + + for (Solvers solver : Solvers.values()) { + try (SolverContext context = + SolverContextFactory.createSolverContext(config, logger, notifier, solver)) { + System.out.println(solver + ", " + context.getVersion()); + } catch (InvalidConfigurationException e) { + System.out.println(solver + " not available"); + } + } + } +} From 0eb07752fff6f1d773249601789ef22da5f04b3a Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Mon, 24 Mar 2025 12:54:50 +0100 Subject: [PATCH 2/5] IvyExampleProject: Copy library files for windows --- doc/Example-Ivy-Project/build.xml | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/doc/Example-Ivy-Project/build.xml b/doc/Example-Ivy-Project/build.xml index 5adde30f10..b315efc27a 100644 --- a/doc/Example-Ivy-Project/build.xml +++ b/doc/Example-Ivy-Project/build.xml @@ -36,7 +36,22 @@ SPDX-License-Identifier: Apache-2.0 - + + + + + + + + + + + + + + + + @@ -72,6 +87,8 @@ SPDX-License-Identifier: Apache-2.0 + + From 7cdb93719d7d4880a00fecef4fa4204ba95ca670 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Mon, 24 Mar 2025 12:56:00 +0100 Subject: [PATCH 3/5] IvyExampleProject: Add symlinks for macOS --- doc/Example-Ivy-Project/lib/native/arm64-macosx/libz3.dylib | 1 + doc/Example-Ivy-Project/lib/native/arm64-macosx/libz3java.dylib | 1 + doc/Example-Ivy-Project/lib/native/x86_64-macosx/libz3.dylib | 1 + doc/Example-Ivy-Project/lib/native/x86_64-macosx/libz3java.dylib | 1 + 4 files changed, 4 insertions(+) create mode 120000 doc/Example-Ivy-Project/lib/native/arm64-macosx/libz3.dylib create mode 120000 doc/Example-Ivy-Project/lib/native/arm64-macosx/libz3java.dylib create mode 120000 doc/Example-Ivy-Project/lib/native/x86_64-macosx/libz3.dylib create mode 120000 doc/Example-Ivy-Project/lib/native/x86_64-macosx/libz3java.dylib diff --git a/doc/Example-Ivy-Project/lib/native/arm64-macosx/libz3.dylib b/doc/Example-Ivy-Project/lib/native/arm64-macosx/libz3.dylib new file mode 120000 index 0000000000..590d25fa37 --- /dev/null +++ b/doc/Example-Ivy-Project/lib/native/arm64-macosx/libz3.dylib @@ -0,0 +1 @@ +../../java/default/arm64/libz3.dylib \ No newline at end of file diff --git a/doc/Example-Ivy-Project/lib/native/arm64-macosx/libz3java.dylib b/doc/Example-Ivy-Project/lib/native/arm64-macosx/libz3java.dylib new file mode 120000 index 0000000000..397941ff52 --- /dev/null +++ b/doc/Example-Ivy-Project/lib/native/arm64-macosx/libz3java.dylib @@ -0,0 +1 @@ +../../java/default/arm64/libz3java.dylib \ No newline at end of file diff --git a/doc/Example-Ivy-Project/lib/native/x86_64-macosx/libz3.dylib b/doc/Example-Ivy-Project/lib/native/x86_64-macosx/libz3.dylib new file mode 120000 index 0000000000..898516499b --- /dev/null +++ b/doc/Example-Ivy-Project/lib/native/x86_64-macosx/libz3.dylib @@ -0,0 +1 @@ +../../java/default/x64/libz3.dylib \ No newline at end of file diff --git a/doc/Example-Ivy-Project/lib/native/x86_64-macosx/libz3java.dylib b/doc/Example-Ivy-Project/lib/native/x86_64-macosx/libz3java.dylib new file mode 120000 index 0000000000..1c865209db --- /dev/null +++ b/doc/Example-Ivy-Project/lib/native/x86_64-macosx/libz3java.dylib @@ -0,0 +1 @@ +../../java/default/x64/libz3java.dylib \ No newline at end of file From aec0884ccdaccd6694f58c40e25e43118dde6e2a Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Wed, 3 Sep 2025 11:32:11 +0200 Subject: [PATCH 4/5] IvyExampleProject: Copy solver binaries and remove the symlinks --- doc/Example-Ivy-Project/build.xml | 47 ++++++++++++++----- .../lib/native/arm64-linux/libbitwuzlaj.so | 1 - .../lib/native/arm64-linux/libmathsat5j.so | 1 - .../lib/native/arm64-linux/libopensmtj.so | 1 - .../lib/native/arm64-linux/libz3.so | 1 - .../lib/native/arm64-linux/libz3java.so | 1 - .../lib/native/arm64-macosx/libz3.dylib | 1 - .../lib/native/arm64-macosx/libz3java.dylib | 1 - .../lib/native/x86_64-linux/libbitwuzlaj.so | 1 - .../lib/native/x86_64-linux/libmathsat5j.so | 1 - .../lib/native/x86_64-linux/libopensmtj.so | 1 - .../lib/native/x86_64-linux/libz3.so | 1 - .../lib/native/x86_64-linux/libz3java.so | 1 - .../lib/native/x86_64-macosx/libz3.dylib | 1 - .../lib/native/x86_64-macosx/libz3java.dylib | 1 - 15 files changed, 36 insertions(+), 25 deletions(-) delete mode 120000 doc/Example-Ivy-Project/lib/native/arm64-linux/libbitwuzlaj.so delete mode 120000 doc/Example-Ivy-Project/lib/native/arm64-linux/libmathsat5j.so delete mode 120000 doc/Example-Ivy-Project/lib/native/arm64-linux/libopensmtj.so delete mode 120000 doc/Example-Ivy-Project/lib/native/arm64-linux/libz3.so delete mode 120000 doc/Example-Ivy-Project/lib/native/arm64-linux/libz3java.so delete mode 120000 doc/Example-Ivy-Project/lib/native/arm64-macosx/libz3.dylib delete mode 120000 doc/Example-Ivy-Project/lib/native/arm64-macosx/libz3java.dylib delete mode 120000 doc/Example-Ivy-Project/lib/native/x86_64-linux/libbitwuzlaj.so delete mode 120000 doc/Example-Ivy-Project/lib/native/x86_64-linux/libmathsat5j.so delete mode 120000 doc/Example-Ivy-Project/lib/native/x86_64-linux/libopensmtj.so delete mode 120000 doc/Example-Ivy-Project/lib/native/x86_64-linux/libz3.so delete mode 120000 doc/Example-Ivy-Project/lib/native/x86_64-linux/libz3java.so delete mode 120000 doc/Example-Ivy-Project/lib/native/x86_64-macosx/libz3.dylib delete mode 120000 doc/Example-Ivy-Project/lib/native/x86_64-macosx/libz3java.dylib diff --git a/doc/Example-Ivy-Project/build.xml b/doc/Example-Ivy-Project/build.xml index b315efc27a..bedc9b252f 100644 --- a/doc/Example-Ivy-Project/build.xml +++ b/doc/Example-Ivy-Project/build.xml @@ -36,22 +36,49 @@ SPDX-License-Identifier: Apache-2.0 - + - - - + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -87,11 +114,9 @@ SPDX-License-Identifier: Apache-2.0 - - + - diff --git a/doc/Example-Ivy-Project/lib/native/arm64-linux/libbitwuzlaj.so b/doc/Example-Ivy-Project/lib/native/arm64-linux/libbitwuzlaj.so deleted file mode 120000 index 372f592128..0000000000 --- a/doc/Example-Ivy-Project/lib/native/arm64-linux/libbitwuzlaj.so +++ /dev/null @@ -1 +0,0 @@ -../../java/default/arm64/libbitwuzlaj.so \ No newline at end of file diff --git a/doc/Example-Ivy-Project/lib/native/arm64-linux/libmathsat5j.so b/doc/Example-Ivy-Project/lib/native/arm64-linux/libmathsat5j.so deleted file mode 120000 index c7eaf57210..0000000000 --- a/doc/Example-Ivy-Project/lib/native/arm64-linux/libmathsat5j.so +++ /dev/null @@ -1 +0,0 @@ -../../java/default/arm64/libmathsat5j.so \ No newline at end of file diff --git a/doc/Example-Ivy-Project/lib/native/arm64-linux/libopensmtj.so b/doc/Example-Ivy-Project/lib/native/arm64-linux/libopensmtj.so deleted file mode 120000 index 8aadd048bf..0000000000 --- a/doc/Example-Ivy-Project/lib/native/arm64-linux/libopensmtj.so +++ /dev/null @@ -1 +0,0 @@ -../../java/default/arm64/libopensmtj.so \ No newline at end of file diff --git a/doc/Example-Ivy-Project/lib/native/arm64-linux/libz3.so b/doc/Example-Ivy-Project/lib/native/arm64-linux/libz3.so deleted file mode 120000 index 7252d0c3c0..0000000000 --- a/doc/Example-Ivy-Project/lib/native/arm64-linux/libz3.so +++ /dev/null @@ -1 +0,0 @@ -../../java/default/arm64/libz3.so \ No newline at end of file diff --git a/doc/Example-Ivy-Project/lib/native/arm64-linux/libz3java.so b/doc/Example-Ivy-Project/lib/native/arm64-linux/libz3java.so deleted file mode 120000 index 934e062ea2..0000000000 --- a/doc/Example-Ivy-Project/lib/native/arm64-linux/libz3java.so +++ /dev/null @@ -1 +0,0 @@ -../../java/default/arm64/libz3java.so \ No newline at end of file diff --git a/doc/Example-Ivy-Project/lib/native/arm64-macosx/libz3.dylib b/doc/Example-Ivy-Project/lib/native/arm64-macosx/libz3.dylib deleted file mode 120000 index 590d25fa37..0000000000 --- a/doc/Example-Ivy-Project/lib/native/arm64-macosx/libz3.dylib +++ /dev/null @@ -1 +0,0 @@ -../../java/default/arm64/libz3.dylib \ No newline at end of file diff --git a/doc/Example-Ivy-Project/lib/native/arm64-macosx/libz3java.dylib b/doc/Example-Ivy-Project/lib/native/arm64-macosx/libz3java.dylib deleted file mode 120000 index 397941ff52..0000000000 --- a/doc/Example-Ivy-Project/lib/native/arm64-macosx/libz3java.dylib +++ /dev/null @@ -1 +0,0 @@ -../../java/default/arm64/libz3java.dylib \ No newline at end of file diff --git a/doc/Example-Ivy-Project/lib/native/x86_64-linux/libbitwuzlaj.so b/doc/Example-Ivy-Project/lib/native/x86_64-linux/libbitwuzlaj.so deleted file mode 120000 index ef45bf4c23..0000000000 --- a/doc/Example-Ivy-Project/lib/native/x86_64-linux/libbitwuzlaj.so +++ /dev/null @@ -1 +0,0 @@ -../../java/default/x64/libbitwuzlaj.so \ No newline at end of file diff --git a/doc/Example-Ivy-Project/lib/native/x86_64-linux/libmathsat5j.so b/doc/Example-Ivy-Project/lib/native/x86_64-linux/libmathsat5j.so deleted file mode 120000 index c734ccd975..0000000000 --- a/doc/Example-Ivy-Project/lib/native/x86_64-linux/libmathsat5j.so +++ /dev/null @@ -1 +0,0 @@ -../../java/default/x64/libmathsat5j.so \ No newline at end of file diff --git a/doc/Example-Ivy-Project/lib/native/x86_64-linux/libopensmtj.so b/doc/Example-Ivy-Project/lib/native/x86_64-linux/libopensmtj.so deleted file mode 120000 index e613c908c0..0000000000 --- a/doc/Example-Ivy-Project/lib/native/x86_64-linux/libopensmtj.so +++ /dev/null @@ -1 +0,0 @@ -../../java/default/x64/libopensmtj.so \ No newline at end of file diff --git a/doc/Example-Ivy-Project/lib/native/x86_64-linux/libz3.so b/doc/Example-Ivy-Project/lib/native/x86_64-linux/libz3.so deleted file mode 120000 index e2423e093d..0000000000 --- a/doc/Example-Ivy-Project/lib/native/x86_64-linux/libz3.so +++ /dev/null @@ -1 +0,0 @@ -../../java/default/x64/libz3.so \ No newline at end of file diff --git a/doc/Example-Ivy-Project/lib/native/x86_64-linux/libz3java.so b/doc/Example-Ivy-Project/lib/native/x86_64-linux/libz3java.so deleted file mode 120000 index 392351c46a..0000000000 --- a/doc/Example-Ivy-Project/lib/native/x86_64-linux/libz3java.so +++ /dev/null @@ -1 +0,0 @@ -../../java/default/x64/libz3java.so \ No newline at end of file diff --git a/doc/Example-Ivy-Project/lib/native/x86_64-macosx/libz3.dylib b/doc/Example-Ivy-Project/lib/native/x86_64-macosx/libz3.dylib deleted file mode 120000 index 898516499b..0000000000 --- a/doc/Example-Ivy-Project/lib/native/x86_64-macosx/libz3.dylib +++ /dev/null @@ -1 +0,0 @@ -../../java/default/x64/libz3.dylib \ No newline at end of file diff --git a/doc/Example-Ivy-Project/lib/native/x86_64-macosx/libz3java.dylib b/doc/Example-Ivy-Project/lib/native/x86_64-macosx/libz3java.dylib deleted file mode 120000 index 1c865209db..0000000000 --- a/doc/Example-Ivy-Project/lib/native/x86_64-macosx/libz3java.dylib +++ /dev/null @@ -1 +0,0 @@ -../../java/default/x64/libz3java.dylib \ No newline at end of file From f17ec991d6ed9423c1830d97a29af4285ff729d2 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Wed, 3 Sep 2025 11:26:43 +0200 Subject: [PATCH 5/5] IvyExampleProject: Update to latest JavaSMT release --- doc/Example-Ivy-Project/ivy.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Example-Ivy-Project/ivy.xml b/doc/Example-Ivy-Project/ivy.xml index bdbe362cef..b5a9d0238c 100644 --- a/doc/Example-Ivy-Project/ivy.xml +++ b/doc/Example-Ivy-Project/ivy.xml @@ -11,6 +11,6 @@ SPDX-License-Identifier: Apache-2.0 - +