Refactoring

This commit is contained in:
Luca Frosini 2023-01-27 15:54:24 +01:00
parent 120f3b58f7
commit 4119f3f444
16 changed files with 137 additions and 167 deletions

View File

@ -10,7 +10,7 @@ import org.gcube.com.fasterxml.jackson.databind.ObjectMapper;
import org.gcube.com.fasterxml.jackson.databind.node.ArrayNode;
import org.gcube.com.fasterxml.jackson.databind.node.ObjectNode;
import org.gcube.com.fasterxml.jackson.databind.node.TextNode;
import org.gcube.common.software.model.SoftwareConfig;
import org.gcube.common.software.model.GlobalConfig;
import org.gcube.common.software.model.SoftwareVersionConfig;
import org.gcube.common.software.model.Variables;
import org.gcube.common.software.utils.Utils;
@ -20,9 +20,9 @@ import org.slf4j.LoggerFactory;
/**
* @author Luca Frosini (ISTI - CNR)
*/
public class SoftwareConfigAnalyser {
public class ConfigAnalyser {
private static final Logger logger = LoggerFactory.getLogger(SoftwareConfigAnalyser.class);
private static final Logger logger = LoggerFactory.getLogger(ConfigAnalyser.class);
public static final String EXPORT_FILENAME_EXTENSION = ".json";
@ -32,12 +32,12 @@ public class SoftwareConfigAnalyser {
protected ObjectMapper objectMapper;
protected JsonNode jsonNode;
public SoftwareConfigAnalyser(File jsonFile) throws Exception {
public ConfigAnalyser(File jsonFile) throws Exception {
this.objectMapper = Utils.getObjectMapper();
this.jsonNode = objectMapper.readTree(jsonFile);
}
public SoftwareConfigAnalyser(String json) throws Exception {
public ConfigAnalyser(String json) throws Exception {
this.objectMapper = Utils.getObjectMapper();
this.jsonNode = objectMapper.readTree(json);
}
@ -55,21 +55,21 @@ public class SoftwareConfigAnalyser {
return softwareVersion;
}
protected SoftwareConfig actualizeSoftwareConfig(JsonNode node) throws Exception {
protected GlobalConfig actualizeGlobalConfig(JsonNode node) throws Exception {
Variables variables = objectMapper.treeToValue(node, Variables.class);
variables.parse();
JsonNode sc = objectMapper.convertValue(variables.getProperties(), JsonNode.class);
SoftwareConfig softwareConfig = objectMapper.treeToValue(sc, SoftwareConfig.class);
GlobalConfig softwareConfig = objectMapper.treeToValue(sc, GlobalConfig.class);
return softwareConfig;
}
public void analyse() throws Exception {
ObjectNode originalGlobal = (ObjectNode) jsonNode.get(GLOBAL_PROPERTY_NAME).deepCopy();
SoftwareConfig softwareConfig = actualizeSoftwareConfig(originalGlobal);
softwareConfig.setOriginalJson(originalGlobal);
GlobalConfig globalConfig = actualizeGlobalConfig(originalGlobal);
globalConfig.setOriginalJson(originalGlobal);
ObjectNode global = originalGlobal.deepCopy();
global.remove(SoftwareConfig.EXPORT_FILENAME_PROPERTY_NAME);
global.remove(GlobalConfig.EXPORT_FILENAME_PROPERTY_NAME);
ArrayNode versions = (ArrayNode) jsonNode.get(VERSIONS_PROPERTY_NAME);
@ -102,7 +102,7 @@ public class SoftwareConfigAnalyser {
try {
SoftwareVersionConfigAnalyser softwareVersionAnalyser = new SoftwareVersionConfigAnalyser(softwareVersion);
softwareVersionAnalyser.setSoftwareConfig(softwareConfig);
softwareVersionAnalyser.setSoftwareConfig(globalConfig);
softwareVersionAnalyser.setFirst(i==0);
softwareVersionAnalyser.analyse();
@ -120,7 +120,7 @@ public class SoftwareConfigAnalyser {
}
if(newDOI) {
softwareConfig.addAdditionalProperty(SoftwareVersionConfig.DOI_URL_PROPERTY_NAME, new TextNode(doiURL.toString()));
globalConfig.addAdditionalProperty(SoftwareVersionConfig.DOI_URL_PROPERTY_NAME, new TextNode(doiURL.toString()));
originalGlobal.put(SoftwareVersionConfig.DOI_URL_PROPERTY_NAME, doiURL.toString());
}
}
@ -154,7 +154,7 @@ public class SoftwareConfigAnalyser {
toBeExported.replace(VERSIONS_PROPERTY_NAME, exportingVersions);
String fileName = softwareConfig.getExportFileName();
String fileName = globalConfig.getExportFileName();
File file = new File(fileName+EXPORT_FILENAME_EXTENSION);
objectMapper.writeValue(file, toBeExported);

View File

@ -1,23 +1,28 @@
package org.gcube.common.software.analyser;
import java.net.URL;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.gcube.common.software.model.ProcessorConfig;
import org.gcube.common.software.model.SoftwareConfig;
import org.gcube.common.software.export.SoftwareVersionExporter;
import org.gcube.common.software.model.ExporterConfig;
import org.gcube.common.software.model.GlobalConfig;
import org.gcube.common.software.model.SoftwareVersionConfig;
import org.gcube.common.software.model.SoftwareVersionFile;
import org.gcube.common.software.model.Variables;
import org.gcube.common.software.process.export.SoftwareVersionExporter;
import org.gcube.common.software.process.publish.SoftwareVersionPublisher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Luca Frosini (ISTI - CNR)
*/
public class SoftwareVersionConfigAnalyser {
protected SoftwareConfig softwareConfig;
private static final Logger logger = LoggerFactory.getLogger(SoftwareVersionConfigAnalyser.class);
protected GlobalConfig softwareConfig;
protected SoftwareVersionConfig softwareVersionConfig;
protected boolean first;
@ -25,11 +30,11 @@ public class SoftwareVersionConfigAnalyser {
this.softwareVersionConfig = softwareVersionConfig;
}
public SoftwareConfig getSoftwareConfig() {
public GlobalConfig getSoftwareConfig() {
return softwareConfig;
}
public void setSoftwareConfig(SoftwareConfig softwareConfig) {
public void setSoftwareConfig(GlobalConfig softwareConfig) {
this.softwareConfig = softwareConfig;
}
@ -62,27 +67,27 @@ public class SoftwareVersionConfigAnalyser {
svf.setDesiredName(desiredName);
}
Map<String,ProcessorConfig> processors = softwareVersionConfig.getPublishers();
List<SoftwareVersionPublisher> svps = SoftwareVersionPublisher.getPublishers();
for(SoftwareVersionPublisher svp: svps) {
ProcessorConfig processorConfig = processors.get(svp.getClass().getSimpleName());
svp.setSoftwareConfig(softwareConfig);
svp.setSoftwareVersion(softwareVersionConfig);
svp.setProcessorConfig(processorConfig);
svp.setFirst(first);
svp.publish();
Map<String, Class<? extends SoftwareVersionExporter>> availableExporters = SoftwareVersionExporter.getAvailableExporters();
Map<String,ExporterConfig> requestedExporters = softwareVersionConfig.getExporters();
Set<String> availableExporterNames = new HashSet<>(availableExporters.keySet());
Set<String> requestedExporterNames = new HashSet<>(availableExporters.keySet());
if(!availableExporterNames.containsAll(requestedExporterNames)) {
requestedExporterNames.removeAll(availableExporterNames);
throw new Exception("The following requested Exporters does not exists " + requestedExporterNames);
}
Map<String,ProcessorConfig> exporters = softwareVersionConfig.getExporters();
List<SoftwareVersionExporter> sves = SoftwareVersionExporter.getExporters();
for(SoftwareVersionExporter sve: sves) {
ProcessorConfig processorConfig = exporters.get(sve.getClass().getSimpleName());
for(String className : requestedExporters.keySet()) {
logger.debug("Goign to export with {}", className);
Class<? extends SoftwareVersionExporter> exporterClass = availableExporters.get(className);
SoftwareVersionExporter sve = exporterClass.newInstance();
ExporterConfig processorConfig = requestedExporters.get(className);
sve.setSoftwareConfig(softwareConfig);
sve.setSoftwareVersion(softwareVersionConfig);
sve.setProcessorConfig(processorConfig);
sve.setFirst(first);
sve.export();
// sve.export();
}
}

View File

@ -0,0 +1,71 @@
package org.gcube.common.software.export;
import java.util.HashMap;
import java.util.Map;
import org.gcube.common.software.export.biblatex.BibLaTeXSoftwareVersionExporter;
import org.gcube.common.software.export.zenodo.ZenodoSoftwareVersionExporter;
import org.gcube.common.software.model.ExporterConfig;
import org.gcube.common.software.model.GlobalConfig;
import org.gcube.common.software.model.SoftwareVersionConfig;
/**
* @author Luca Frosini (ISTI - CNR)
*/
public abstract class SoftwareVersionExporter {
protected static Map<String, Class<? extends SoftwareVersionExporter>> processors;
static {
processors = new HashMap<>();
add(ZenodoSoftwareVersionExporter.class);
add(BibLaTeXSoftwareVersionExporter.class);
}
private static void add(Class<? extends SoftwareVersionExporter> clz) {
processors.put(clz.getSimpleName(), clz);
}
public static Map<String, Class<? extends SoftwareVersionExporter>> getAvailableExporters() {
return processors;
}
protected GlobalConfig softwareConfig;
protected SoftwareVersionConfig softwareVersionConfig;
protected ExporterConfig processorConfig;
protected boolean first;
public GlobalConfig getSoftwareConfig() {
return softwareConfig;
}
public void setSoftwareConfig(GlobalConfig softwareConfig) {
this.softwareConfig = softwareConfig;
}
public SoftwareVersionConfig getSoftwareVersionConfig() {
return softwareVersionConfig;
}
public void setSoftwareVersion(SoftwareVersionConfig softwareVersionConfig) {
this.softwareVersionConfig = softwareVersionConfig;
}
public ExporterConfig getProcessorConfig() {
return processorConfig;
}
public void setProcessorConfig(ExporterConfig processorConfig) {
this.processorConfig = processorConfig;
}
public boolean isFirst() {
return first;
}
public void setFirst(boolean first) {
this.first = first;
}
public abstract void export() throws Exception;
}

View File

@ -1,4 +1,4 @@
package org.gcube.common.software.process.export.biblatex;
package org.gcube.common.software.export.biblatex;
import java.io.BufferedWriter;
import java.io.File;
@ -9,9 +9,9 @@ import java.util.Set;
import org.gcube.com.fasterxml.jackson.databind.JsonNode;
import org.gcube.com.fasterxml.jackson.databind.node.ArrayNode;
import org.gcube.common.software.export.SoftwareVersionExporter;
import org.gcube.common.software.model.ElaborationType;
import org.gcube.common.software.model.Variables;
import org.gcube.common.software.process.export.SoftwareVersionExporter;
import org.gcube.common.software.utils.FileUtils;
import org.gcube.common.software.utils.Utils;
import org.slf4j.Logger;
@ -27,6 +27,7 @@ public class BibLaTeXSoftwareVersionExporter extends SoftwareVersionExporter {
public static final String EXPORT_FILENAME_EXTENSION = ".bib";
public static final String TEMPLATE_FILENAME = "biblatex.template";
@Override
public void export() throws Exception {
String title = softwareVersionConfig.getTitle();

View File

@ -1,4 +1,4 @@
package org.gcube.common.software.process.publish.zenodo;
package org.gcube.common.software.export.zenodo;
import java.io.BufferedReader;
import java.io.File;
@ -29,9 +29,9 @@ import org.gcube.com.fasterxml.jackson.databind.node.JsonNodeType;
import org.gcube.com.fasterxml.jackson.databind.node.ObjectNode;
import org.gcube.common.gxhttp.request.GXHTTPStringRequest;
import org.gcube.common.software.config.Config;
import org.gcube.common.software.export.SoftwareVersionExporter;
import org.gcube.common.software.model.ElaborationType;
import org.gcube.common.software.model.SoftwareVersionFile;
import org.gcube.common.software.process.publish.SoftwareVersionPublisher;
import org.gcube.common.software.utils.Utils;
import org.glassfish.jersey.client.ClientProperties;
import org.glassfish.jersey.media.multipart.FormDataMultiPart;
@ -43,9 +43,9 @@ import org.slf4j.LoggerFactory;
/**
* @author Luca Frosini (ISTI - CNR)
*/
public class ZenodoSoftwareVersionPublisher extends SoftwareVersionPublisher {
public class ZenodoSoftwareVersionExporter extends SoftwareVersionExporter {
private static final Logger logger = LoggerFactory.getLogger(ZenodoSoftwareVersionPublisher.class);
private static final Logger logger = LoggerFactory.getLogger(ZenodoSoftwareVersionExporter.class);
public static final String GUCBE_ZENODO_SOFTWARE_DEPOSIT = "gCubeSoftwareDeposit";
@ -93,7 +93,7 @@ public class ZenodoSoftwareVersionPublisher extends SoftwareVersionPublisher {
return map;
}
public ZenodoSoftwareVersionPublisher() {}
public ZenodoSoftwareVersionExporter() {}
protected void addFilesToDeposition(List<File> files ) throws Exception {
String depositID = getZenodoIDFromDOIURL(softwareVersionConfig.getVersionDOIURL());
@ -483,7 +483,7 @@ public class ZenodoSoftwareVersionPublisher extends SoftwareVersionPublisher {
}
@Override
public void publish() throws Exception {
public void export() throws Exception {
getZenodoConnectionConfig();
String title = softwareVersionConfig.getTitle();

View File

@ -13,7 +13,7 @@ import org.gcube.com.fasterxml.jackson.databind.JsonNode;
/**
* @author Luca Frosini (ISTI - CNR)
*/
public class ProcessorConfig {
public class ExporterConfig {
public static final String ELABORATION_PROPERTY_NAME = "elaboration";
@ -23,7 +23,7 @@ public class ProcessorConfig {
protected Map<String, JsonNode> properties;
public ProcessorConfig() {
public ExporterConfig() {
properties = new LinkedHashMap<>();
}

View File

@ -16,7 +16,7 @@ import org.gcube.com.fasterxml.jackson.databind.node.ObjectNode;
/**
* @author Luca Frosini (ISTI - CNR)
*/
public class SoftwareConfig {
public class GlobalConfig {
public static final String EXPORT_FILENAME_PROPERTY_NAME = "export_filename";
@ -28,7 +28,7 @@ public class SoftwareConfig {
@JsonIgnore
protected ObjectNode originalJson;
public SoftwareConfig() {
public GlobalConfig() {
this.additionalProperties = new LinkedHashMap<>();
}

View File

@ -36,7 +36,6 @@ public class SoftwareVersionConfig {
public static final String DOI_URL_PROPERTY_NAME = "doi_url";
public static final String VERSION_DOI_URL_PROPERTY_NAME = "version_doi_url";
public static final String GRANTS_PROPERTY_NAME = "grants";
public static final String PUBLISHERS_PROPERTY_NAME = "publishers";
public static final String EXPORTERS_PROPERTY_NAME = "exporters";
@JsonIgnore
@ -85,11 +84,8 @@ public class SoftwareVersionConfig {
@JsonProperty(GRANTS_PROPERTY_NAME)
protected JsonNode grants;
@JsonProperty(PUBLISHERS_PROPERTY_NAME)
protected Map<String,ProcessorConfig> publishers;
@JsonProperty(EXPORTERS_PROPERTY_NAME)
protected Map<String,ProcessorConfig> exporters;
protected Map<String,ExporterConfig> exporters;
protected Map<String, JsonNode> additionalProperties;
@ -204,11 +200,7 @@ public class SoftwareVersionConfig {
return grants;
}
public Map<String,ProcessorConfig> getPublishers() {
return publishers;
}
public Map<String,ProcessorConfig> getExporters() {
public Map<String,ExporterConfig> getExporters() {
return exporters;
}

View File

@ -1,49 +0,0 @@
package org.gcube.common.software.process;
import org.gcube.common.software.model.ProcessorConfig;
import org.gcube.common.software.model.SoftwareConfig;
import org.gcube.common.software.model.SoftwareVersionConfig;
/**
* @author Luca Frosini (ISTI - CNR)
*/
public abstract class SoftwareVersionProcessor {
protected SoftwareConfig softwareConfig;
protected SoftwareVersionConfig softwareVersionConfig;
protected ProcessorConfig processorConfig;
protected boolean first;
public SoftwareConfig getSoftwareConfig() {
return softwareConfig;
}
public void setSoftwareConfig(SoftwareConfig softwareConfig) {
this.softwareConfig = softwareConfig;
}
public SoftwareVersionConfig getSoftwareVersionConfig() {
return softwareVersionConfig;
}
public void setSoftwareVersion(SoftwareVersionConfig softwareVersionConfig) {
this.softwareVersionConfig = softwareVersionConfig;
}
public ProcessorConfig getProcessorConfig() {
return processorConfig;
}
public void setProcessorConfig(ProcessorConfig processorConfig) {
this.processorConfig = processorConfig;
}
public boolean isFirst() {
return first;
}
public void setFirst(boolean first) {
this.first = first;
}
}

View File

@ -1,22 +0,0 @@
package org.gcube.common.software.process.export;
import java.util.ArrayList;
import java.util.List;
import org.gcube.common.software.process.SoftwareVersionProcessor;
import org.gcube.common.software.process.export.biblatex.BibLaTeXSoftwareVersionExporter;
/**
* @author Luca Frosini (ISTI - CNR)
*/
public abstract class SoftwareVersionExporter extends SoftwareVersionProcessor {
public static List<SoftwareVersionExporter> getExporters() {
List<SoftwareVersionExporter> sves = new ArrayList<>();
sves.add(new BibLaTeXSoftwareVersionExporter());
return sves;
}
public abstract void export() throws Exception;
}

View File

@ -1,22 +0,0 @@
package org.gcube.common.software.process.publish;
import java.util.ArrayList;
import java.util.List;
import org.gcube.common.software.process.SoftwareVersionProcessor;
import org.gcube.common.software.process.publish.zenodo.ZenodoSoftwareVersionPublisher;
/**
* @author Luca Frosini (ISTI - CNR)
*/
public abstract class SoftwareVersionPublisher extends SoftwareVersionProcessor {
public static List<SoftwareVersionPublisher> getPublishers() {
List<SoftwareVersionPublisher> svps = new ArrayList<>();
svps.add(new ZenodoSoftwareVersionPublisher());
return svps;
}
public abstract void publish() throws Exception;
}

View File

@ -3,7 +3,7 @@ package org.gcube.common.software.utils;
import java.io.File;
import java.net.URL;
import org.gcube.common.software.process.export.biblatex.BibLaTeXSoftwareVersionExporter;
import org.gcube.common.software.export.biblatex.BibLaTeXSoftwareVersionExporter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

View File

@ -17,7 +17,7 @@ public class SoftwareConceptAnalyserTest {
@Test
public void testUsingTestFile() throws Exception {
File file = FileUtils.getFileFromFilename(FILENAME);
SoftwareConfigAnalyser softwareConceptAnalyser = new SoftwareConfigAnalyser(file);
ConfigAnalyser softwareConceptAnalyser = new ConfigAnalyser(file);
softwareConceptAnalyser.analyse();
}

View File

@ -139,15 +139,13 @@
"url": "https://cordis.europa.eu/project/id/871042"
}
],
"publishers": {
"ZenodoSoftwareVersionPublisher": {
"exporters": {
"ZenodoSoftwareVersionExporter": {
"elaboration": "NONE",
"html_description": "<p><a href=\"https://www.gcube-system.org/\">gCube</a> Catalogue (gCat) Service allows any client to publish items in the gCube Catalogue.</p>\n\n<p><a href=\"https://www.gcube-system.org/\">gCube</a> is an open-source software toolkit used for building and operating Hybrid Data Infrastructures enabling the dynamic deployment of Virtual Research Environments, such as the <a href=\"https://www.d4science.org/\">D4Science Infrastructure</a>, by favouring the realisation of reuse-oriented policies.</p>\n\n<p><a href=\"https://www.gcube-system.org/\">gCube</a> has been used to successfully build and operate infrastructures and virtual research environments for application domains ranging from biodiversity to environmental data management and cultural heritage.</p>\n\n<p><a href=\"https://www.gcube-system.org/\">gCube</a> offers components supporting typical data management workflows including data access, curation, processing, and visualisation on a large set of data typologies ranging from primary biodiversity data to geospatial and tabular data.</p>\n\n<p><a href=\"https://www.d4science.org/\">D4Science</a> is a Hybrid Data Infrastructure combining over 500 software components and integrating data from more than 50 different data providers into a coherent and managed system of hardware, software, and data resources. The D4Science infrastructure drastically reduces the cost of ownership, maintenance, and operation thanks to the exploitation of gCube.</p>\n\n<p>&nbsp;</p>",
"html_code_location": "\n\n<p>The official source code location of this software version is available at:</p>\n\n<p><a href=\"{{code_location}}\">{{code_location}}</a></p>",
"skip_grants": ["004260"]
}
},
"exporters": {
},
"BibLaTeXSoftwareVersionExporter": {
"elaboration": "ALL"
}

View File

@ -129,15 +129,13 @@
"url": "https://cordis.europa.eu/project/id/871042"
}
],
"publishers": {
"ZenodoSoftwareVersionPublisher": {
"exporters": {
"ZenodoSoftwareVersionExporter": {
"elaboration": "NONE",
"html_description": "<p><a href=\"https://www.gcube-system.org/\">gCube</a> Catalogue (gCat) Service allows any client to publish items in the gCube Catalogue.</p>\n\n<p><a href=\"https://www.gcube-system.org/\">gCube</a> is an open-source software toolkit used for building and operating Hybrid Data Infrastructures enabling the dynamic deployment of Virtual Research Environments, such as the <a href=\"https://www.d4science.org/\">D4Science Infrastructure</a>, by favouring the realisation of reuse-oriented policies.</p>\n\n<p><a href=\"https://www.gcube-system.org/\">gCube</a> has been used to successfully build and operate infrastructures and virtual research environments for application domains ranging from biodiversity to environmental data management and cultural heritage.</p>\n\n<p><a href=\"https://www.gcube-system.org/\">gCube</a> offers components supporting typical data management workflows including data access, curation, processing, and visualisation on a large set of data typologies ranging from primary biodiversity data to geospatial and tabular data.</p>\n\n<p><a href=\"https://www.d4science.org/\">D4Science</a> is a Hybrid Data Infrastructure combining over 500 software components and integrating data from more than 50 different data providers into a coherent and managed system of hardware, software, and data resources. The D4Science infrastructure drastically reduces the cost of ownership, maintenance, and operation thanks to the exploitation of gCube.</p>\n\n<p>&nbsp;</p>",
"html_code_location": "\n\n<p>The official source code location of this software version is available at:</p>\n\n<p><a href=\"{{code_location}}\">{{code_location}}</a></p>",
"skip_grants": ["004260"]
}
},
"exporters": {
},
"BibLaTeXSoftwareVersionExporter": {
"elaboration": "ALL"
}

View File

@ -129,15 +129,13 @@
"url": "https://cordis.europa.eu/project/id/871042"
}
],
"publishers": {
"ZenodoSoftwareVersionPublisher": {
"exporters": {
"ZenodoSoftwareVersionExporter": {
"elaboration": "NONE",
"html_description": "<p><a href=\"https://www.gcube-system.org/\">gCube</a> Catalogue (gCat) Service allows any client to publish items in the gCube Catalogue.</p>\n\n<p><a href=\"https://www.gcube-system.org/\">gCube</a> is an open-source software toolkit used for building and operating Hybrid Data Infrastructures enabling the dynamic deployment of Virtual Research Environments, such as the <a href=\"https://www.d4science.org/\">D4Science Infrastructure</a>, by favouring the realisation of reuse-oriented policies.</p>\n\n<p><a href=\"https://www.gcube-system.org/\">gCube</a> has been used to successfully build and operate infrastructures and virtual research environments for application domains ranging from biodiversity to environmental data management and cultural heritage.</p>\n\n<p><a href=\"https://www.gcube-system.org/\">gCube</a> offers components supporting typical data management workflows including data access, curation, processing, and visualisation on a large set of data typologies ranging from primary biodiversity data to geospatial and tabular data.</p>\n\n<p><a href=\"https://www.d4science.org/\">D4Science</a> is a Hybrid Data Infrastructure combining over 500 software components and integrating data from more than 50 different data providers into a coherent and managed system of hardware, software, and data resources. The D4Science infrastructure drastically reduces the cost of ownership, maintenance, and operation thanks to the exploitation of gCube.</p>\n\n<p>&nbsp;</p>",
"html_code_location": "\n\n<p>The official source code location of this software version is available at:</p>\n\n<p><a href=\"{{code_location}}\">{{code_location}}</a></p>",
"skip_grants": ["004260"]
}
},
"exporters": {
},
"BibLaTeXSoftwareVersionExporter": {
"elaboration": "ALL"
}