Commit 781cbe56 authored by lcottret's avatar lcottret
Browse files

Finish tag 0.10

parents d925056a 1d26a07f
...@@ -19,3 +19,4 @@ met4j-core/src/main/java/fr/inra/toulouse/metexplore/met4j_core/Test\.java ...@@ -19,3 +19,4 @@ met4j-core/src/main/java/fr/inra/toulouse/metexplore/met4j_core/Test\.java
dependency-reduced-pom.xml dependency-reduced-pom.xml
/met4j.sif
image: maven:3.6-adoptopenjdk-14
stages:
- build
- test
- deploy
- build-containers
.template_docker:
stage: build-containers
image: docker:latest
services:
- docker:dind
variables: variables:
MAVEN_CLI_OPTS: "-s .m2/settings.xml --batch-mode" MAVEN_CLI_OPTS: "-s .m2/settings.xml --batch-mode"
...@@ -9,19 +21,20 @@ cache: ...@@ -9,19 +21,20 @@ cache:
- .m2/repository/ - .m2/repository/
build: build:
image: maven:3.6-adoptopenjdk-14
stage: build stage: build
script: script:
- mvn compile - mvn compile
test: test:
image: maven:3.6-adoptopenjdk-14
stage: test stage: test
script: script:
- mvn clean test - mvn clean test
- cat coverage/target/site/jacoco-aggregate/index.html | grep -o '<tfoot>.*</tfoot>' - cat coverage/target/site/jacoco-aggregate/index.html | grep -o '<tfoot>.*</tfoot>'
deploySnapshot: deploySnapshot:
image: maven:3.6-adoptopenjdk-14
stage: deploy stage: deploy
script: script:
- mvn $MAVEN_CLI_OPTS deploy -Dmaven.test.skip=true - mvn $MAVEN_CLI_OPTS deploy -Dmaven.test.skip=true
...@@ -29,6 +42,7 @@ deploySnapshot: ...@@ -29,6 +42,7 @@ deploySnapshot:
- develop - develop
deployCentral: deployCentral:
image: maven:3.6-adoptopenjdk-14
stage: deploy stage: deploy
before_script: before_script:
- 'which ssh-agent || ( apt-get update -qy && apt-get install openssh-client -qqy )' - 'which ssh-agent || ( apt-get update -qy && apt-get install openssh-client -qqy )'
...@@ -49,3 +63,47 @@ deployCentral: ...@@ -49,3 +63,47 @@ deployCentral:
- mvn $MAVEN_CLI_OPTS release:perform -Darguments=-Dgpg.passphrase=${GPG_PASSPHRASE} -DlocalCheckout=true - mvn $MAVEN_CLI_OPTS release:perform -Darguments=-Dgpg.passphrase=${GPG_PASSPHRASE} -DlocalCheckout=true
only: only:
- master - master
buildSingularity:
stage: build-containers
image:
name: quay.io/singularity/singularity:v3.4.0
entrypoint: [ "" ]
script:
- singularity build met4j-toolbox.sif met4j.singularity
- singularity push --docker-username "${CI_REGISTRY_USER}" --docker-password "${CI_REGISTRY_PASSWORD}" met4j-toolbox.sif oras://"$CI_REGISTRY_IMAGE"/met4j-singularity:"$CI_COMMIT_TAG"
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
when: manual
- if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH
when: manual
buildDockerProdGitlab:
extends: .template_docker
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
script:
- docker build -t "$CI_REGISTRY/metexplore/met4j/met4j-docker:latest" .
- docker push "$CI_REGISTRY/metexplore/met4j/met4j-docker:latest"
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
when: manual
- if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH
when: manual
buildDockerProdDockerhub:
extends: .template_docker
before_script:
- docker login -u "$DOCKERHUB_USER" -p "$DOCKERHUB_PASSWORD" $DOCKERHUB_REGISTRY
script:
- docker build --pull -t "$DOCKERHUB_IMAGE:latest" .
- docker push "$DOCKERHUB_IMAGE:latest"
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
when: manual
- if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH
when: manual
...@@ -4,6 +4,18 @@ All notable changes to this project will be documented in this file. ...@@ -4,6 +4,18 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## 0.10.0
### Features
[met4j-toolbox] New app: networkAnalysis.CompoundNet: Advanced compound graph building
[met4j-toolbox] New app: attributes.ExtractPathways: SBML sub network creation from a list of pathways
[met4j-toolbox] New app: attributes.ExtractSbmlAnnot: Extract sbml annotations
[met4j-toolbox] App improvements: networkAnalysis.SideCompoundsScan: Handle multiple compartments
## 0.9.1 ## 0.9.1
### Fixed ### Fixed
......
FROM debian:stable-slim
RUN export DEBIAN_FRONTEND=noninteractive
RUN apt-get update \
&& apt-get upgrade -y \
&& apt-get install -y openjdk-11-jre git maven \
&& apt-get clean \
&& apt-get purge
RUN mkdir -p /opt && cd /opt \
&& git clone https://forgemia.inra.fr/metexplore/met4j.git \
&& cd met4j \
&& mvn install \
&& cd met4j-toolbox \
&& mvn package
RUN mkdir -p /opt/bin \
&& cd /opt/met4j/met4j-toolbox \
&& cp target/met4j*.jar /opt/bin/met4j.jar \
&& cd /opt \
&& rm -rf met4j ~/.m2 \
&& apt-get remove -y git && apt-get autoremove -y
COPY ./docker_files/met4j.sh /opt/bin
ENTRYPOINT ["/opt/bin/met4j.sh"]
...@@ -62,7 +62,7 @@ mv ./target/*-jar-with-dependencies.jar ../../../ ...@@ -62,7 +62,7 @@ mv ./target/*-jar-with-dependencies.jar ../../../
## Usage ## Usage
Documentation for the library modules can be found in each module's own README. Documentation for the library modules can be found in each module's own README.
Detailed code examples can be found at [https://forgemia.inra.fr/metexplore/tutorialmet4j](https://cecill.info/licences/Licence_CeCILL_V2.1-en.html). Detailed code examples can be found at [here](https://forgemia.inra.fr/metexplore/tutorialmet4j).
The toolbox can be launched using The toolbox can be launched using
``` ```
...@@ -74,6 +74,14 @@ which will list all the contained applications that can be called using ...@@ -74,6 +74,14 @@ which will list all the contained applications that can be called using
java -cp met4j-toolbox-0.8.0-jar-with-dependencies.jar <App full name> -h java -cp met4j-toolbox-0.8.0-jar-with-dependencies.jar <App full name> -h
``` ```
### With singularity
You need at least [singularity](https://sylabs.io/guides/3.5/user-guide/quick_start.html) v3.5.
```console
singularity pull met4j-toolbox.sif oras://registry.forgemia.inra.fr/metexplore/met4j/met4j-singularity:latest
```
## Contributing ## Contributing
Pull requests are welcome **on the gitlab repo** ([https://forgemia.inra.fr/metexplore/met4j](https://forgemia.inra.fr/metexplore/met4j)). For major changes, please open an issue first to discuss what you would like to change. Pull requests are welcome **on the gitlab repo** ([https://forgemia.inra.fr/metexplore/met4j](https://forgemia.inra.fr/metexplore/met4j)). For major changes, please open an issue first to discuss what you would like to change.
......
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
<parent> <parent>
<groupId>fr.inrae.toulouse.metexplore</groupId> <groupId>fr.inrae.toulouse.metexplore</groupId>
<artifactId>met4j</artifactId> <artifactId>met4j</artifactId>
<version>0.9.1-SNAPSHOT</version> <version>0.10.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
......
#!bin/bash
#
# Copyright INRAE (2022)
#
# contact-metexplore@inrae.fr
#
# This software is a computer program whose purpose is to [describe
# functionalities and technical features of your software].
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "https://cecill.info/licences/Licence_CeCILL_V2.1-en.html".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
#
path_jar=/opt/bin/met4j.jar
# path_jar=../met4j-toolbox/target/met4j-toolbox-0.9.1-SNAPSHOT.jar
if [ $# -lt 1 ]
then
echo "display Help"
exec java -jar $path_jar
else
echo "Lauch met4j-toolbox"
exec java -Dlog4j.configuration= -cp $path_jar fr.inrae.toulouse.metexplore.met4j_toolbox."$@"
fi
\ No newline at end of file
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>fr.inrae.toulouse.metexplore</groupId> <groupId>fr.inrae.toulouse.metexplore</groupId>
<artifactId>met4j</artifactId> <artifactId>met4j</artifactId>
<version>0.9.1-SNAPSHOT</version> <version>0.10.0-SNAPSHOT</version>
</parent> </parent>
<properties> <properties>
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
<dependency> <dependency>
<groupId>fr.inrae.toulouse.metexplore</groupId> <groupId>fr.inrae.toulouse.metexplore</groupId>
<artifactId>met4j-core</artifactId> <artifactId>met4j-core</artifactId>
<version>0.9.1-SNAPSHOT</version> <version>0.10.0-SNAPSHOT</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/org.mockito/mockito-all --> <!-- https://mvnrepository.com/artifact/org.mockito/mockito-all -->
<dependency> <dependency>
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>fr.inrae.toulouse.metexplore</groupId> <groupId>fr.inrae.toulouse.metexplore</groupId>
<artifactId>met4j</artifactId> <artifactId>met4j</artifactId>
<version>0.9.1-SNAPSHOT</version> <version>0.10.0-SNAPSHOT</version>
</parent> </parent>
<scm> <scm>
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>fr.inrae.toulouse.metexplore</groupId> <groupId>fr.inrae.toulouse.metexplore</groupId>
<artifactId>met4j</artifactId> <artifactId>met4j</artifactId>
<version>0.9.1-SNAPSHOT</version> <version>0.10.0-SNAPSHOT</version>
</parent> </parent>
<artifactId>met4j-graph</artifactId> <artifactId>met4j-graph</artifactId>
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
<dependency> <dependency>
<groupId>fr.inrae.toulouse.metexplore</groupId> <groupId>fr.inrae.toulouse.metexplore</groupId>
<artifactId>met4j-core</artifactId> <artifactId>met4j-core</artifactId>
<version>0.9.1-SNAPSHOT</version> <version>0.10.0-SNAPSHOT</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.commons</groupId> <groupId>org.apache.commons</groupId>
...@@ -50,12 +50,12 @@ ...@@ -50,12 +50,12 @@
<dependency> <dependency>
<groupId>fr.inrae.toulouse.metexplore</groupId> <groupId>fr.inrae.toulouse.metexplore</groupId>
<artifactId>met4j-mathUtils</artifactId> <artifactId>met4j-mathUtils</artifactId>
<version>0.9.1-SNAPSHOT</version> <version>0.10.0-SNAPSHOT</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>fr.inrae.toulouse.metexplore</groupId> <groupId>fr.inrae.toulouse.metexplore</groupId>
<artifactId>met4j-chemUtils</artifactId> <artifactId>met4j-chemUtils</artifactId>
<version>0.9.1-SNAPSHOT</version> <version>0.10.0-SNAPSHOT</version>
</dependency> </dependency>
</dependencies> </dependencies>
......
...@@ -4,11 +4,13 @@ import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioMetabolite; ...@@ -4,11 +4,13 @@ import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioMetabolite;
import fr.inrae.toulouse.metexplore.met4j_graph.core.WeightingPolicy; import fr.inrae.toulouse.metexplore.met4j_graph.core.WeightingPolicy;
import fr.inrae.toulouse.metexplore.met4j_graph.core.compound.CompoundGraph; import fr.inrae.toulouse.metexplore.met4j_graph.core.compound.CompoundGraph;
import fr.inrae.toulouse.metexplore.met4j_graph.core.compound.ReactionEdge; import fr.inrae.toulouse.metexplore.met4j_graph.core.compound.ReactionEdge;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.function.Function;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
...@@ -101,6 +103,23 @@ public class AtomMappingWeightPolicy extends WeightingPolicy<BioMetabolite, Reac ...@@ -101,6 +103,23 @@ public class AtomMappingWeightPolicy extends WeightingPolicy<BioMetabolite, Reac
.sep("\t")); .sep("\t"));
} }
public AtomMappingWeightPolicy fromConservedCarbonIndexes(String GSAMoutputFile){
String sep =",";
return this.fromNumberOfConservedCarbons(new WeightsFromFile(GSAMoutputFile, false)
.weightCol(8)
.edgeLabelCol(6)
.sourceCol(0)
.targetCol(3)
.processWeigthCol(new Function<String, Double>() {
@Override
public Double apply(String s) {
return Double.valueOf(s.split(sep).length);
}
})
.sep("\t"))
;
}
@Override @Override
public void setWeight(CompoundGraph compoundGraph) { public void setWeight(CompoundGraph compoundGraph) {
if(conservedCarbons==null) throw new IllegalArgumentException("an atom mapping must be provided"); if(conservedCarbons==null) throw new IllegalArgumentException("an atom mapping must be provided");
...@@ -110,7 +129,8 @@ public class AtomMappingWeightPolicy extends WeightingPolicy<BioMetabolite, Reac ...@@ -110,7 +129,8 @@ public class AtomMappingWeightPolicy extends WeightingPolicy<BioMetabolite, Reac
for(ReactionEdge e : compoundGraph.edgeSet()){ for(ReactionEdge e : compoundGraph.edgeSet()){
Integer cc = null; Integer cc = null;
if(importer !=null){ if(importer !=null){
cc=(int) compoundGraph.getEdgeWeight(e); Double w = compoundGraph.getEdgeWeight(e);
if(!Double.isNaN(w)) cc= Integer.valueOf((int) compoundGraph.getEdgeWeight(e));
}else{ }else{
Map<BioMetabolite,Integer> mapping = conservedCarbons.get(e.getV1()); Map<BioMetabolite,Integer> mapping = conservedCarbons.get(e.getV1());
if(mapping!=null) cc = conservedCarbons.get(e.getV1()).get(e.getV2()); if(mapping!=null) cc = conservedCarbons.get(e.getV1()).get(e.getV2());
......
...@@ -42,6 +42,7 @@ import java.util.Arrays; ...@@ -42,6 +42,7 @@ import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.function.Function;
import fr.inrae.toulouse.metexplore.met4j_graph.core.BioGraph; import fr.inrae.toulouse.metexplore.met4j_graph.core.BioGraph;
import fr.inrae.toulouse.metexplore.met4j_graph.core.Edge; import fr.inrae.toulouse.metexplore.met4j_graph.core.Edge;
...@@ -71,7 +72,12 @@ public class WeightsFromFile<V extends BioEntity, E extends Edge<V>,G extends Bi ...@@ -71,7 +72,12 @@ public class WeightsFromFile<V extends BioEntity, E extends Edge<V>,G extends Bi
private int weightCol = 3; private int weightCol = 3;
private boolean skipHeader = false; private boolean skipHeader = false;
private boolean missingAsNaN = true; private boolean missingAsNaN = true;
private Function<String,Double> process = Double::parseDouble;
public WeightsFromFile<V,E,G> processWeigthCol(Function<String,Double> process) {
this.process = process;
return this;
}
public WeightsFromFile<V,E,G> removeEdgeNotInFile() { public WeightsFromFile<V,E,G> removeEdgeNotInFile() {
this.removeEdgeNotInFile = true; this.removeEdgeNotInFile = true;
return this; return this;
...@@ -151,7 +157,7 @@ public class WeightsFromFile<V extends BioEntity, E extends Edge<V>,G extends Bi ...@@ -151,7 +157,7 @@ public class WeightsFromFile<V extends BioEntity, E extends Edge<V>,G extends Bi
if(e!=null){ if(e!=null){
if(!seenEdges.contains(e)){ if(!seenEdges.contains(e)){
try{ try{
double w = Double.parseDouble(lineParts[weightCol]); double w = process.apply(lineParts[weightCol]);
if(!Double.isNaN(w)){ if(!Double.isNaN(w)){
g.setEdgeWeight(e, w); g.setEdgeWeight(e, w);
seenEdges.add(e); seenEdges.add(e);
......
...@@ -416,6 +416,94 @@ public class TestWeightingPolicy { ...@@ -416,6 +416,94 @@ public class TestWeightingPolicy {
} }
/**
* Test the weights Import
*/
@Test
public void testWeightsFromFileImportIII() {
Path tmpPath = null;
try {
tmpPath = Files.createTempFile("test_edgeWeightmport", ".tmp");
} catch (IOException e1) {
e1.printStackTrace();
Assert.fail("Creation of the temporary directory");
}
String filePath = "EdgeWeightTestFileII.tab";
try {
filePath = TestUtils.copyProjectResource(filePath, tmpPath.toFile());
} catch (IOException e) {
e.printStackTrace();
fail("problem while reading edge weight file");
}
double abWeight,bcWeight,adWeight,efWeight,bxWeight,ebWeight,deWeight,fcWeight,ycWeight;
abWeight=0.2;
bcWeight=0.4;
adWeight=0.6;
efWeight=0.8;
bxWeight=1.0;
ebWeight=1.2;
deWeight=1.4;
fcWeight=1.6;
ycWeight=1.8;
WeightsFromFile<BioMetabolite,ReactionEdge,CompoundGraph> wp =
new WeightsFromFile<BioMetabolite,ReactionEdge,CompoundGraph>(filePath)
.sep(",")
.sourceCol(0)
.targetCol(1)
.edgeLabelCol(2)
.weightCol(4)
.processWeigthCol(s -> {return Double.parseDouble(s)*2;});
wp.setWeight(g);
assertEquals("wrong weight after import", abWeight, g.getEdgeWeight(ab),Double.MIN_VALUE);
assertEquals("wrong weight after import", adWeight, g.getEdgeWeight(ad),Double.MIN_VALUE);
assertEquals("wrong weight after import", bcWeight, g.getEdgeWeight(bc),Double.MIN_VALUE);
assertEquals("wrong weight after import", bxWeight, g.getEdgeWeight(bx),Double.MIN_VALUE);
assertEquals("wrong weight after import", deWeight, g.getEdgeWeight(de),Double.MIN_VALUE);
assertEquals("wrong weight after import", ebWeight, g.getEdgeWeight(eb),Double.MIN_VALUE);
assertEquals("wrong weight after import", efWeight, g.getEdgeWeight(ef),Double.MIN_VALUE);
assertEquals("wrong weight after import", fcWeight, g.getEdgeWeight(fc),Double.MIN_VALUE);
assertEquals("wrong weight after import", ycWeight, g.getEdgeWeight(yc),Double.MIN_VALUE);
}
@Test
public void testAtomMappingWeightPolicy() {
Path tmpPath = null;
try {
tmpPath = Files.createTempFile("test_edgeWeightmport", ".tmp");
} catch (IOException e1) {
e1.printStackTrace();
Assert.fail("Creation of the temporary directory");
}
String filePath = "AAMTestFile.tab";
try {
filePath = TestUtils.copyProjectResource(filePath, tmpPath.toFile());
} catch (IOException e) {
e.printStackTrace();
fail("problem while reading edge weight file");
}
int CCnb1 =21;
int CCnb5 =5;
int CCnb6 =1;
AtomMappingWeightPolicy wp1 = new AtomMappingWeightPolicy().fromConservedCarbonIndexes(filePath);
wp1.setWeight(g);
assertEquals("wrong weight for AAM weight", CCnb1, g.getEdgeWeight(ad),Double.MIN_VALUE);
assertTrue("wrong weight for AAM weight", Double.isNaN(g.getEdgeWeight(ab)));
assertTrue("wrong weight for AAM weight", Double.isNaN(g.getEdgeWeight(bc)));
assertTrue("wrong weight for AAM weight", Double.isNaN(g.getEdgeWeight(bx)));
assertEquals("wrong weight for AAM weight", CCnb5, g.getEdgeWeight(eb),Double.MIN_VALUE);
assertEquals("wrong weight for AAM weight", CCnb6, g.getEdgeWeight(ef),Double.MIN_VALUE);
assertTrue("wrong weight for AAM weight", Double.isNaN(g.getEdgeWeight(yc)));
}
@Test @Test
public void testAtomMappingWeightPolicyI() { public void testAtomMappingWeightPolicyI() {
......
a 60.021129368 4-2 d 60.021129368 4-2 abd 0.0 2,4,5,6,7,9,10,12,13,23,24,26,28,30,31,33,35,37,43,45,47
e 60.021129368 35-33 b 139.98745989 35-33 efb 79.96633052199999 50,52,53,57,59
e 169.998024574 49-47-46 f 265.959269716 49-47-46 efb 95.961245142 54
\ No newline at end of file
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<parent> <parent>
<groupId>fr.inrae.toulouse.metexplore</groupId> <groupId>fr.inrae.toulouse.metexplore</groupId>
<artifactId>met4j</artifactId> <artifactId>met4j</artifactId>
<version>0.9.1-SNAPSHOT</version> <version>0.10.0-SNAPSHOT</version>
</parent> </parent>
<artifactId>met4j-io</artifactId> <artifactId>met4j-io</artifactId>
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
<dependency> <dependency>
<groupId>fr.inrae.toulouse.metexplore</groupId> <groupId>fr.inrae.toulouse.metexplore</groupId>
<artifactId>met4j-core</artifactId>