diff --git a/pom.xml b/pom.xml index ad0aa93bab..3aeff21c45 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ io.goobi.workflow workflow-base - 24.06 + 24.07 workflow-core @@ -15,6 +15,13 @@ https://nexus.intranda.com/repository/maven-public + + + io.goobi.vocabulary + vocabulary-server-exchange + 1.0.0 + + @@ -79,8 +86,7 @@ ${project.build.directory}/classes/template.properties - ${project.build.directory}/classes/goobi_config.properties - + ${project.build.directory}/classes/goobi_config.properties @@ -100,4 +106,3 @@ - diff --git a/src/main/java/de/sub/goobi/config/ConfigurationHelper.java b/src/main/java/de/sub/goobi/config/ConfigurationHelper.java index 344b6b8cde..4c80de923a 100644 --- a/src/main/java/de/sub/goobi/config/ConfigurationHelper.java +++ b/src/main/java/de/sub/goobi/config/ConfigurationHelper.java @@ -1111,6 +1111,10 @@ public int getNumberOfMetaBackups() { return getLocalInt("numberOfMetaBackups", 9); } + public int getNumberOfBackups() { + return getLocalInt("numberOfBackups", 9); + } + /* * subcategory in goobi_config.properties/METS EDITOR: user interface */ @@ -1291,6 +1295,14 @@ public boolean isPdfAsDownload() { return getLocalBoolean("pdfAsDownload", true); } + public String getVocabularyServerHost() { + return getLocalString("vocabularyServerHost", "localhost"); + } + + public int getVocabularyServerPort() { + return getLocalInt("vocabularyServerPort", 8081); + } + /** * This setter is only used by unit tests and makes manipulation of the configuration possible. * diff --git a/src/main/java/de/sub/goobi/export/download/ExportMets.java b/src/main/java/de/sub/goobi/export/download/ExportMets.java index 8e85b073e9..7fe29fb0e8 100755 --- a/src/main/java/de/sub/goobi/export/download/ExportMets.java +++ b/src/main/java/de/sub/goobi/export/download/ExportMets.java @@ -123,6 +123,7 @@ import ugh.dl.ExportFileformat; import ugh.dl.Fileformat; import ugh.dl.Md; +import ugh.dl.Md.MdType; import ugh.dl.MetadataType; import ugh.dl.Prefs; import ugh.dl.VirtualFileGroup; @@ -407,8 +408,7 @@ private ExportFileformat collectMetadataToSave(Process myProzess, Fileformat gdz } Element techMd = createTechMd(path); if (techMd != null) { - Md md = new Md(techMd); - md.setType("techMD"); + Md md = new Md(techMd, MdType.TECH_MD); md.setId(String.format("AMD_%04d", counter++)); dd.addTechMd(md); page.setAdmId(md.getId()); diff --git a/src/main/java/de/sub/goobi/forms/AdditionalField.java b/src/main/java/de/sub/goobi/forms/AdditionalField.java index 4fab656f2f..38671c9b83 100644 --- a/src/main/java/de/sub/goobi/forms/AdditionalField.java +++ b/src/main/java/de/sub/goobi/forms/AdditionalField.java @@ -99,7 +99,8 @@ public void setInitEnd(String newValue) { } public void setWert(String newValue) { - if (newValue == null || newValue.equals(this.initStart)) { + // TODO: Testing for "null" is not nice, but JSF seems to store empty selection of dropdowns as "null" instead of null + if (newValue == null || "null".equals(newValue) || newValue.equals(this.initStart)) { newValue = ""; } if (newValue.startsWith(this.initStart)) { @@ -204,6 +205,10 @@ public LocalDate getValueAsDate() { } public void setValueAsDate(LocalDate date) { + if (date == null) { + return; + } + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); wert = formatter.format(date); } diff --git a/src/main/java/de/sub/goobi/forms/ProzesskopieForm.java b/src/main/java/de/sub/goobi/forms/ProzesskopieForm.java index 51de8bc5cd..b3ed427e65 100644 --- a/src/main/java/de/sub/goobi/forms/ProzesskopieForm.java +++ b/src/main/java/de/sub/goobi/forms/ProzesskopieForm.java @@ -2,20 +2,20 @@ /** * This file is part of the Goobi Application - a Workflow tool for the support of mass digitization. - * + *

* Visit the websites for more information. - * - https://goobi.io - * - https://www.intranda.com - * + * - https://goobi.io + * - https://www.intranda.com + *

* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) any later version. - * + *

* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * + *

* You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 * Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + *

* Linking this library statically or dynamically with other modules is making a combined work based on this library. Thus, the terms and conditions * of the GNU General Public License cover the whole combination. As a special exception, the copyright holders of this library give you permission to * link this library with independent modules to produce an executable, regardless of the license terms of these independent modules, and to copy and @@ -44,6 +44,7 @@ import java.util.StringTokenizer; import java.util.TreeSet; import java.util.regex.PatternSyntaxException; +import java.util.stream.Collectors; import javax.enterprise.inject.Default; import javax.faces.model.SelectItem; @@ -74,11 +75,9 @@ import org.goobi.production.flow.jobs.HistoryAnalyserJob; import org.goobi.production.plugin.interfaces.IOpacPlugin; import org.goobi.production.plugin.interfaces.IOpacPluginVersion2; +import org.goobi.production.properties.AccessCondition; import org.goobi.production.properties.ProcessProperty; import org.goobi.production.properties.PropertyParser; -import org.goobi.vocabulary.Field; -import org.goobi.vocabulary.VocabRecord; -import org.goobi.vocabulary.Vocabulary; import org.jdom2.Document; import org.jdom2.Element; import org.jdom2.JDOMException; @@ -108,10 +107,12 @@ import de.sub.goobi.persistence.managers.ProjectManager; import de.sub.goobi.persistence.managers.RulesetManager; import de.sub.goobi.persistence.managers.StepManager; -import de.sub.goobi.persistence.managers.VocabularyManager; import de.unigoettingen.sub.search.opac.ConfigOpac; import de.unigoettingen.sub.search.opac.ConfigOpacCatalogue; import de.unigoettingen.sub.search.opac.ConfigOpacDoctype; +import io.goobi.vocabulary.exchange.Vocabulary; +import io.goobi.workflow.api.vocabulary.VocabularyAPIManager; +import io.goobi.workflow.api.vocabulary.helper.ExtendedVocabularyRecord; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.Getter; @@ -141,7 +142,7 @@ @Log4j2 public class ProzesskopieForm implements Serializable { /** - * + * */ private static final long serialVersionUID = 2579641488883675182L; private Helper help = new Helper(); @@ -475,23 +476,21 @@ private AdditionalField readAdditionalFieldConfiguration(HierarchicalConfigurati String vocabularyTitle = item.getString("@vocabulary"); if (StringUtils.isNotBlank(vocabularyTitle)) { - Vocabulary currentVocabulary = VocabularyManager.getVocabularyByTitle(vocabularyTitle); - if (currentVocabulary != null && currentVocabulary.getId() != null) { - VocabularyManager.getAllRecords(currentVocabulary); - List recordList = currentVocabulary.getRecords(); - Collections.sort(recordList); - List selectItems = new ArrayList<>(recordList.size()); - for (VocabRecord vr : recordList) { - for (Field f : vr.getFields()) { - if (f.getDefinition().isMainEntry()) { - selectItems.add(new SelectItem(f.getValue(), f.getValue())); - break; - } - } - } - fa.setSelectList(selectItems); - } - } + Vocabulary vocabulary = VocabularyAPIManager.getInstance().vocabularies().findByName(vocabularyTitle); + List records = VocabularyAPIManager.getInstance() + .vocabularyRecords() + .list(vocabulary.getId()) + .all() + .request() + .getContent(); + fa.setSelectList( + records.stream() + .map(ExtendedVocabularyRecord::getMainValue) + .sorted() + .map(v -> new SelectItem(v, v)) + .collect(Collectors.toList())); + } + // TODO: FIX return fa; } @@ -567,7 +566,7 @@ public String opacAuswerten() { /** * die Eingabefelder für die Eigenschaften mit Inhalten aus der RDF-Datei füllen - * + * * @throws PreferencesException */ private void fillFieldsFromMetadataFile() throws PreferencesException { @@ -666,7 +665,7 @@ private void clearValues() { /** * Auswahl des Processes auswerten - * + * * @throws DAOException * @throws NamingException * @throws SQLException ============================================================== == @@ -691,27 +690,34 @@ public String readMetadataFromTemplate() throws DAOException { if (tempProcess.getEigenschaftenSize() > 0) { fillTemplateFromProperties(tempProcess); } + try { this.myRdf = tempProcess.readMetadataAsTemplateFile(); + + /* falls ein erstes Kind vorhanden ist, sind die Collectionen dafür */ + try { + DocStruct colStruct = this.myRdf.getDigitalDocument().getLogicalDocStruct(); + + List firstChildMetadata = + colStruct.getAllChildren().isEmpty() ? Collections.emptyList() : colStruct.getAllChildren().get(0).getAllMetadata(); + fillTemplateFromMetadata(colStruct.getAllMetadata(), firstChildMetadata); + + removeCollections(colStruct); + colStruct = colStruct.getAllChildren().get(0); + removeCollections(colStruct); + } catch (PreferencesException e) { + Helper.setFehlerMeldung("Error on creating process", e); + log.error("Error on creating process", e); + } catch (RuntimeException e) { + e.printStackTrace(); + /* + * das Firstchild unterhalb des Topstructs konnte nicht ermittelt werden + */ + } } catch (Exception e) { Helper.setFehlerMeldung("Error on reading template-metadata ", e); } - /* falls ein erstes Kind vorhanden ist, sind die Collectionen dafür */ - try { - DocStruct colStruct = this.myRdf.getDigitalDocument().getLogicalDocStruct(); - removeCollections(colStruct); - colStruct = colStruct.getAllChildren().get(0); - removeCollections(colStruct); - } catch (PreferencesException e) { - Helper.setFehlerMeldung("Error on creating process", e); - log.error("Error on creating process", e); - } catch (RuntimeException e) { - /* - * das Firstchild unterhalb des Topstructs konnte nicht ermittelt werden - */ - } - return ""; } @@ -719,14 +725,7 @@ private void fillTemplateFromProperties(Process tempProcess) { for (Processproperty pe : tempProcess.getEigenschaften()) { for (AdditionalField field : this.additionalFields) { if (field.getTitel().equals(pe.getTitel())) { - // multiselect - if (field.isMultiselect()) { - List existingValues = field.getValues(); - existingValues.add(pe.getWert()); - field.setValues(existingValues); - } else { - field.setWert(pe.getWert()); - } + setFieldValue(field, pe.getWert()); } } if ("digitalCollection".equals(pe.getTitel())) { @@ -741,14 +740,7 @@ private void fillTemplateFromTemplate(Process tempProcess) { for (Templateproperty eig : vor.getEigenschaften()) { for (AdditionalField field : this.additionalFields) { if (field.getTitel().equals(eig.getTitel())) { - // multiselect - if (field.isMultiselect()) { - List existingValues = field.getValues(); - existingValues.add(eig.getWert()); - field.setValues(existingValues); - } else { - field.setWert(eig.getWert()); - } + setFieldValue(field, eig.getWert()); } } } @@ -759,14 +751,7 @@ private void fillTemplateFromMasterpiece(Process tempProcess) { for (Masterpieceproperty eig : werk.getEigenschaften()) { for (AdditionalField field : this.additionalFields) { if (field.getTitel().equals(eig.getTitel())) { - // multiselect - if (field.isMultiselect()) { - List existingValues = new ArrayList<>(field.getValues()); - existingValues.add(eig.getWert()); - field.setValues(existingValues); - } else { - field.setWert(eig.getWert()); - } + setFieldValue(field, eig.getWert()); } if ("DocType".equals(eig.getTitel())) { docType = eig.getWert(); @@ -775,9 +760,37 @@ private void fillTemplateFromMasterpiece(Process tempProcess) { } } + private void fillTemplateFromMetadata(List topstruct, List firstChild) { + for (Metadata m : topstruct) { + this.additionalFields.stream() + .filter(f -> "topstruct".equals(f.getDocstruct())) + .filter(f -> f.getMetadata() != null && f.getMetadata().equals(m.getType().getName())) + .findFirst() + .ifPresent(f -> setFieldValue(f, m.getValue())); + } + + for (Metadata m : firstChild) { + this.additionalFields.stream() + .filter(f -> "firstchild".equals(f.getDocstruct())) + .filter(f -> f.getMetadata() != null && f.getMetadata().equals(m.getType().getName())) + .findFirst() + .ifPresent(f -> setFieldValue(f, m.getValue())); + } + } + + private void setFieldValue(AdditionalField field, String value) { + if (field.isMultiselect()) { + List existingValues = field.getValues(); + existingValues.add(value); + field.setValues(existingValues); + } else { + field.setWert(value); + } + } + /** * Validierung der Eingaben - * + * * @return sind Fehler bei den Eingaben vorhanden? ================================================================ */ private boolean isContentValid() { @@ -822,14 +835,26 @@ private boolean isContentValid() { * -------------------------------- Prüfung der additional-Eingaben, die angegeben werden müssen -------------------------------- */ for (AdditionalField field : this.additionalFields) { - if ((field.getWert() == null || "".equals(field.getWert())) && field.isRequired() && field.getShowDependingOnDoctype(getDocType()) - && (StringUtils.isBlank(field.getWert()))) { + if ((field.getWert() == null || field.getWert().isBlank()) && field.isRequired() && field.getShowDependingOnDoctype(getDocType())) { valide = false; Helper.setFehlerMeldung(Helper.getTranslation("UnvollstaendigeDaten") + " " + field.getTitel() + " " + Helper.getTranslation("ProcessCreationErrorFieldIsEmpty")); } } + + // property validation + + for (ProcessProperty pt : configuredProperties) { + if (!pt.isValid() + || (AccessCondition.WRITEREQUIRED.equals(pt.getShowProcessGroupAccessCondition()) + && StringUtils.isBlank(pt.getValue()))) { + Helper.setFehlerMeldung(Helper.getTranslation("UnvollstaendigeDaten") + " " + pt.getName() + " " + + Helper.getTranslation("ProcessCreationErrorFieldIsEmpty")); + } + + } + return valide; } @@ -841,7 +866,7 @@ public void showTablesOfExistingProcess() { /** * print the infos of the existing process - * + * * @param processName title that has already been used by some process */ @SuppressWarnings("unused") @@ -912,7 +937,7 @@ public String openPage2() { /** * Anlegen des Processes und Speichern der Metadaten ================================================================ - * + * * @throws DAOException * @throws SwapException * @throws WriteException @@ -1452,7 +1477,7 @@ private void copyMetadata(DocStruct oldDocStruct, DocStruct newDocStruct) { /* * this is needed for GUI, render multiple select only if this is false if this is true use the only choice - * + * * @author Wulf */ public boolean isSingleChoiceCollection() { @@ -1462,7 +1487,7 @@ public boolean isSingleChoiceCollection() { /* * this is needed for GUI, render multiple select only if this is false if isSingleChoiceCollection is true use this choice - * + * * @author Wulf */ public String getDigitalCollectionIfSingleChoice() { @@ -1695,8 +1720,17 @@ public void calculateProcessTitle() { } /* den Inhalt zum Titel hinzufügen */ - if (myField.getTitel().equals(myString) && myField.getShowDependingOnDoctype(getDocType()) && myField.getWert() != null) { - gen.addToken(calcProcesstitelCheck(myField.getTitel(), myField.getWert()), ManipulationType.NORMAL); + if (myField.getTitel().equals(myString) && myField.getShowDependingOnDoctype(getDocType())) { + String value = myField.getWert(); + if (value == null) { + value = ""; + } + + // Skip process title generation if a required field is not present + if (myField.isRequired() && value.isBlank()) { + return; + } + gen.addToken(calcProcesstitelCheck(myField.getTitel(), value), ManipulationType.NORMAL); } } } @@ -1976,7 +2010,7 @@ private int getIndexOfFolder(String folder) { /** * Get get temporary folder to upload to - * + * * @return path to temporary folder */ private Path getTemporaryFolder() { @@ -1992,7 +2026,7 @@ private Path getTemporaryFolder() { /** * Handle the upload of a file - * + * * @param event */ public void uploadFile(FileUploadEvent event) { @@ -2006,7 +2040,7 @@ public void uploadFile(FileUploadEvent event) { /** * Save the uploaded file temporary in the tmp-folder inside of goobi in a subfolder for the user - * + * * @param fileName * @param in * @throws IOException diff --git a/src/main/java/de/sub/goobi/helper/DateTimeHelper.java b/src/main/java/de/sub/goobi/helper/DateTimeHelper.java new file mode 100644 index 0000000000..16c540101d --- /dev/null +++ b/src/main/java/de/sub/goobi/helper/DateTimeHelper.java @@ -0,0 +1,14 @@ +package de.sub.goobi.helper; + +import java.time.LocalDateTime; + +/** + * Due to PowerMock mocking issues of LocalDateTime.now(), this class is used to retrieve local dates and times and mocked in testing. + * + * Feel free to extend this class with any DateTime related methods you might find useful. + */ +public class DateTimeHelper { + public static LocalDateTime localDateTimeNow() { + return LocalDateTime.now(); + } +} diff --git a/src/main/java/de/sub/goobi/helper/VariableReplacer.java b/src/main/java/de/sub/goobi/helper/VariableReplacer.java index 43cfe40cc1..7c53627138 100644 --- a/src/main/java/de/sub/goobi/helper/VariableReplacer.java +++ b/src/main/java/de/sub/goobi/helper/VariableReplacer.java @@ -34,6 +34,8 @@ import java.nio.file.FileSystems; import java.nio.file.Path; import java.nio.file.Paths; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.List; import java.util.regex.MatchResult; @@ -144,6 +146,7 @@ private enum MetadataLevel { private static final String REGEX_TEMPLATE = PREFIX + "template\\.([^)}]+?)" + SUFFIX; private static final String REGEX_PROCESS = PREFIX + "process\\.([^)}]+?)" + SUFFIX; private static final String REGEX_DB_META = PREFIX + "db_meta\\.([^)}]+?)" + SUFFIX; + private static final String REGEX_DATETIME = PREFIX + "datetime\\.([^)}]+?)" + SUFFIX; @Getter @Setter @@ -511,6 +514,17 @@ public String replace(String inString) { } } + for (MatchResult r : findRegexMatches(REGEX_DATETIME, inString)) { + try { + LocalDateTime now = DateTimeHelper.localDateTimeNow(); + String pattern = r.group(1); + DateTimeFormatter format = DateTimeFormatter.ofPattern(pattern); + inString = inString.replace(r.group(), now.format(format)); + } catch (IllegalArgumentException e) { + log.error(e); + } + } + return inString; } diff --git a/src/main/java/de/sub/goobi/metadaten/MetaCorporate.java b/src/main/java/de/sub/goobi/metadaten/MetaCorporate.java index b093dbd25b..001d6daa15 100644 --- a/src/main/java/de/sub/goobi/metadaten/MetaCorporate.java +++ b/src/main/java/de/sub/goobi/metadaten/MetaCorporate.java @@ -36,8 +36,6 @@ import org.goobi.api.display.enums.DisplayType; import org.goobi.api.display.helper.NormDatabase; import org.goobi.beans.Process; -import org.goobi.production.cli.helper.StringPair; -import org.goobi.vocabulary.VocabRecord; import de.intranda.digiverso.normdataimporter.NormDataImporter; import de.intranda.digiverso.normdataimporter.model.NormData; @@ -46,6 +44,7 @@ import de.sub.goobi.config.ConfigurationHelper; import de.sub.goobi.metadaten.search.EasyDBSearch; import de.sub.goobi.metadaten.search.ViafSearch; +import io.goobi.workflow.api.vocabulary.helper.ExtendedVocabularyRecord; import lombok.Data; import ugh.dl.Corporate; import ugh.dl.HoldingElement; @@ -81,11 +80,13 @@ public class MetaCorporate implements SearchableMetadata { private List normdataList; private int totalResults; private EasyDBSearch easydbSearch = new EasyDBSearch(); - private List vocabularySearchFields; + private List vocabularySearchFields; private String vocabularyName; - private List records; + private List records; private String vocabularyUrl; - private VocabRecord selectedVocabularyRecord; + private ExtendedVocabularyRecord selectedVocabularyRecord; + private long currentVocabularySearchField; + private String vocabularySearchQuery; /** * constructor @@ -184,13 +185,13 @@ public String getData() { String x156 = "\\x156"; for (NormData normdata : currentData) { - if (normdata.getKey().equals("NORM_IDENTIFIER")) { + if ("NORM_IDENTIFIER".equals(normdata.getKey())) { corporate.setAutorityFile("gnd", "http://d-nb.info/gnd/", normdata.getValues().get(0).getText()); - } else if (normdata.getKey().equals("NORM_ORGANIZATION")) { + } else if ("NORM_ORGANIZATION".equals(normdata.getKey())) { mainValue = normdata.getValues().get(0).getText().replace(x152, "").replace(x156, ""); - } else if (normdata.getKey().equals("NORM_SUB_ORGANIZATION")) { + } else if ("NORM_SUB_ORGANIZATION".equals(normdata.getKey())) { subNames.add(new NamePart(SUBNAME, normdata.getValues().get(0).getText().replace(x152, "").replace(x156, ""))); - } else if (normdata.getKey().equals("NORM_PART_ORGANIZATION")) { + } else if ("NORM_PART_ORGANIZATION".equals(normdata.getKey())) { if (partName.length() > 0) { partName.append("; "); } diff --git a/src/main/java/de/sub/goobi/metadaten/MetaPerson.java b/src/main/java/de/sub/goobi/metadaten/MetaPerson.java index 4f4a3fcfaf..8b47f36487 100644 --- a/src/main/java/de/sub/goobi/metadaten/MetaPerson.java +++ b/src/main/java/de/sub/goobi/metadaten/MetaPerson.java @@ -39,8 +39,6 @@ import org.goobi.api.display.enums.DisplayType; import org.goobi.api.display.helper.NormDatabase; import org.goobi.beans.Process; -import org.goobi.production.cli.helper.StringPair; -import org.goobi.vocabulary.VocabRecord; import de.intranda.digiverso.normdataimporter.NormDataImporter; import de.intranda.digiverso.normdataimporter.model.NormData; @@ -50,6 +48,7 @@ import de.sub.goobi.metadaten.search.EasyDBSearch; import de.sub.goobi.metadaten.search.KulturNavImporter; import de.sub.goobi.metadaten.search.ViafSearch; +import io.goobi.workflow.api.vocabulary.helper.ExtendedVocabularyRecord; import lombok.Data; import ugh.dl.DocStruct; import ugh.dl.HoldingElement; @@ -95,11 +94,13 @@ public class MetaPerson implements SearchableMetadata { private List normdataList; private int totalResults; private EasyDBSearch easydbSearch = new EasyDBSearch(); - private List vocabularySearchFields; + private List vocabularySearchFields; private String vocabularyName; - private List records; + private List records; private String vocabularyUrl; - private VocabRecord selectedVocabularyRecord; + private ExtendedVocabularyRecord selectedVocabularyRecord; + private long currentVocabularySearchField; + private String vocabularySearchQuery; /** * Allgemeiner Konstruktor () diff --git a/src/main/java/de/sub/goobi/metadaten/Metadaten.java b/src/main/java/de/sub/goobi/metadaten/Metadaten.java index f201577f0e..4a3f24ba31 100644 --- a/src/main/java/de/sub/goobi/metadaten/Metadaten.java +++ b/src/main/java/de/sub/goobi/metadaten/Metadaten.java @@ -5207,18 +5207,25 @@ public String getAuthorityMetadataJSON() { List authorityList = new ArrayList<>(); for (Person person : persons) { - AuthorityData data = new AuthorityData(person.getDisplayname(), person.getAuthorityURI() + person.getAuthorityValue()); + AuthorityData data = + new AuthorityData(person.getDisplayname(), + URI.create(Optional.ofNullable(person.getAuthorityURI()).orElse("")).resolve(person.getAuthorityValue()).toString()); authorityList.add(data); } for (Corporate corporate : corporates) { - AuthorityData data = new AuthorityData(corporate.getMainName(), corporate.getAuthorityURI() + corporate.getAuthorityValue()); + AuthorityData data = new AuthorityData(corporate.getMainName(), + URI.create(Optional.ofNullable(corporate.getAuthorityURI()).orElse("")).resolve(corporate.getAuthorityValue()).toString()); authorityList.add(data); } for (Metadata md : metadata) { - AuthorityData data = new AuthorityData(md.getValue(), md.getAuthorityURI() + md.getAuthorityValue()); + AuthorityData data = new AuthorityData(md.getValue(), + URI.create(Optional.ofNullable(md.getAuthorityURI()).orElse("")).resolve(md.getAuthorityValue()).toString()); authorityList.add(data); } + Collections.sort(authorityList, + (a, b) -> Optional.ofNullable(a.getValue()).orElse("").compareTo(Optional.ofNullable(b.getValue()).orElse(""))); + return new Gson().toJson(authorityList); } } diff --git a/src/main/java/de/sub/goobi/metadaten/MetadatenVerifizierung.java b/src/main/java/de/sub/goobi/metadaten/MetadatenVerifizierung.java index ee8c21e8af..390c36dec5 100644 --- a/src/main/java/de/sub/goobi/metadaten/MetadatenVerifizierung.java +++ b/src/main/java/de/sub/goobi/metadaten/MetadatenVerifizierung.java @@ -32,15 +32,15 @@ import java.util.regex.PatternSyntaxException; import java.util.stream.Collectors; +import io.goobi.workflow.api.vocabulary.VocabularyAPIManager; +import io.goobi.workflow.api.vocabulary.helper.ExtendedVocabulary; +import io.goobi.workflow.api.vocabulary.helper.ExtendedVocabularyRecord; import org.apache.commons.configuration.HierarchicalConfiguration; import org.apache.commons.lang3.StringUtils; import org.goobi.api.display.Item; import org.goobi.api.display.enums.DisplayType; import org.goobi.api.display.helper.ConfigDisplayRules; import org.goobi.beans.Process; -import org.goobi.vocabulary.Field; -import org.goobi.vocabulary.VocabRecord; -import org.goobi.vocabulary.Vocabulary; import de.sub.goobi.config.ConfigProjects; import de.sub.goobi.config.ConfigurationHelper; @@ -49,7 +49,6 @@ import de.sub.goobi.helper.exceptions.InvalidImagesException; import de.sub.goobi.helper.exceptions.SwapException; import de.sub.goobi.helper.exceptions.UghHelperException; -import de.sub.goobi.persistence.managers.VocabularyManager; import lombok.Getter; import lombok.extern.log4j.Log4j2; import ugh.dl.Corporate; @@ -492,15 +491,16 @@ private List checkSelectFromVocabularyList(Process inProcess, DocStruct if (allowedItems.get(0) == null) { break; } - Vocabulary vocabulary = VocabularyManager.getVocabularyByTitle(allowedItems.get(0).getSource()); - VocabularyManager.getAllRecords(vocabulary); - List records = vocabulary.getRecords(); - List allowedValues = new ArrayList<>(); - for (VocabRecord vocabularyRecord : records) { - for (Field field : vocabularyRecord.getFields()) { - allowedValues.add(field.getValue()); - } - } + ExtendedVocabulary vocabulary = VocabularyAPIManager.getInstance().vocabularies().findByName(allowedItems.get(0).getSource()); + List records = VocabularyAPIManager.getInstance().vocabularyRecords() + .list(vocabulary.getId()) + .all() + .request() + .getContent(); + List allowedValues = records.stream() + .map(ExtendedVocabularyRecord::getMainValue) + .collect(Collectors.toList()); + List ll = null; ll = inStruct.getAllMetadataByType(mdt); for (Metadata md : ll) { diff --git a/src/main/java/de/sub/goobi/metadaten/MetadatumImpl.java b/src/main/java/de/sub/goobi/metadaten/MetadatumImpl.java index 8f832b5897..f3f1e67ec7 100644 --- a/src/main/java/de/sub/goobi/metadaten/MetadatumImpl.java +++ b/src/main/java/de/sub/goobi/metadaten/MetadatumImpl.java @@ -1,23 +1,25 @@ package de.sub.goobi.metadaten; -import java.net.URL; -import java.nio.file.Paths; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - -import javax.faces.context.FacesContext; -import javax.faces.model.SelectItem; -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.core.UriBuilder; - +import de.intranda.digiverso.normdataimporter.NormDataImporter; +import de.intranda.digiverso.normdataimporter.dante.DanteImport; +import de.intranda.digiverso.normdataimporter.model.NormData; +import de.intranda.digiverso.normdataimporter.model.NormDataRecord; +import de.sub.goobi.config.ConfigPlugins; +import de.sub.goobi.config.ConfigurationHelper; +import de.sub.goobi.helper.Helper; +import de.sub.goobi.helper.StorageProvider; +import de.sub.goobi.metadaten.search.EasyDBSearch; +import de.sub.goobi.metadaten.search.KulturNavImporter; +import de.sub.goobi.metadaten.search.ViafSearch; +import de.sub.goobi.persistence.managers.MetadataManager; +import io.goobi.vocabulary.exchange.FieldDefinition; +import io.goobi.vocabulary.exchange.Vocabulary; +import io.goobi.vocabulary.exchange.VocabularySchema; +import io.goobi.workflow.api.vocabulary.APIException; +import io.goobi.workflow.api.vocabulary.VocabularyAPIManager; +import io.goobi.workflow.api.vocabulary.helper.ExtendedVocabularyRecord; +import lombok.Data; +import lombok.extern.log4j.Log4j2; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.configuration.HierarchicalConfiguration; import org.apache.commons.configuration.XMLConfiguration; @@ -37,32 +39,11 @@ import org.goobi.api.rest.request.SearchRequest; import org.goobi.beans.Process; import org.goobi.beans.Project; -import org.goobi.production.cli.helper.StringPair; -import org.goobi.vocabulary.Field; -import org.goobi.vocabulary.VocabRecord; -import org.goobi.vocabulary.Vocabulary; import org.jdom2.Document; import org.jdom2.Element; import org.jdom2.filter.Filters; import org.jdom2.xpath.XPathExpression; import org.jdom2.xpath.XPathFactory; - -import de.intranda.digiverso.normdataimporter.NormDataImporter; -import de.intranda.digiverso.normdataimporter.dante.DanteImport; -import de.intranda.digiverso.normdataimporter.model.NormData; -import de.intranda.digiverso.normdataimporter.model.NormDataRecord; -import de.sub.goobi.config.ConfigPlugins; -import de.sub.goobi.config.ConfigurationHelper; -import de.sub.goobi.helper.FacesContextHelper; -import de.sub.goobi.helper.Helper; -import de.sub.goobi.helper.StorageProvider; -import de.sub.goobi.metadaten.search.EasyDBSearch; -import de.sub.goobi.metadaten.search.KulturNavImporter; -import de.sub.goobi.metadaten.search.ViafSearch; -import de.sub.goobi.persistence.managers.MetadataManager; -import de.sub.goobi.persistence.managers.VocabularyManager; -import lombok.Data; -import lombok.extern.log4j.Log4j2; import ugh.dl.DocStruct; import ugh.dl.Metadata; import ugh.dl.MetadataGroup; @@ -72,6 +53,22 @@ import ugh.exceptions.MetadataTypeNotAllowedException; import ugh.fileformats.mets.ModsHelper; +import javax.faces.model.SelectItem; +import java.net.URL; +import java.nio.file.Paths; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + /** * This file is part of the Goobi Application - a Workflow tool for the support of mass digitization. *

@@ -134,13 +131,11 @@ public class MetadatumImpl implements Metadatum, SearchableMetadata { /** * The table of available normdata objects - * */ private List> dataList; /** * The list of current normdata objects - * */ private List currentData; @@ -174,11 +169,14 @@ public class MetadatumImpl implements Metadatum, SearchableMetadata { private EasyDBSearch easydbSearch = new EasyDBSearch(); // search in vocabulary - private List vocabularySearchFields; + private VocabularyAPIManager vocabularyAPI = VocabularyAPIManager.getInstance(); + private List vocabularySearchFields; + private long currentVocabularySearchField; + private String vocabularySearchQuery; private String vocabularyName; - private List records; - private String vocabularyUrl; - private VocabRecord selectedVocabularyRecord; + private List records; + private List definitions; + private ExtendedVocabularyRecord selectedVocabularyRecord; private boolean validationErrorPresent; private String validationMessage; @@ -202,30 +200,17 @@ public MetadatumImpl(Metadata m, int inID, Prefs inPrefs, Process inProcess, Met } public void searchVocabulary() { - - FacesContext context = FacesContextHelper.getCurrentFacesContext(); - HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest(); - String contextPath = request.getContextPath(); - String scheme = request.getScheme(); // http - String serverName = request.getServerName(); // hostname.com - int serverPort = request.getServerPort(); // 80 - String reqUrl = scheme + "://" + serverName + contextPath; - // if there is a port lower than the typical ones (443) don't show it in the url (http://mygoobi.io/xyz instead of http://mygoobi.io:80/xyz) - if (serverPort > 443) { - reqUrl = scheme + "://" + serverName + ":" + serverPort + contextPath; - } - UriBuilder ub = UriBuilder.fromUri(reqUrl); - vocabularyUrl = ub.path("api").path("vocabulary").path("records").build().toString(); - - records = VocabularyManager.findRecords(vocabulary, vocabularySearchFields); - - if (records == null || records.isEmpty()) { - showNotHits = true; - } else { - showNotHits = false; - } - Collections.sort(records); - + Vocabulary vocabulary = vocabularyAPI.vocabularies().findByName(this.vocabulary); + VocabularySchema schema = vocabularyAPI.vocabularySchemas().get(vocabulary.getSchemaId()); + definitions = schema.getDefinitions().stream() + .filter(d -> Boolean.TRUE.equals(d.getTitleField())) + .sorted(Comparator.comparingLong(FieldDefinition::getId)) + .collect(Collectors.toList()); + records = vocabularyAPI.vocabularyRecords().list(vocabulary.getId()) + .search(currentVocabularySearchField + ":" + vocabularySearchQuery) + .request() + .getContent(); + showNotHits = records.isEmpty(); } private void initializeValues() { @@ -262,28 +247,111 @@ private void initializeValues() { searchRequest.newGroup(); } else if (metadataDisplaytype == DisplayType.vocabularySearch) { vocabularyName = myValues.getItemList().get(0).getSource(); - String fields = myValues.getItemList().get(0).getField(); + Set fieldsNames = Stream.of(myValues.getItemList().get(0).getField().split(";")) + .map(String::trim) + .collect(Collectors.toSet()); - String[] fieldNames = fields.split(";"); - vocabularySearchFields = new ArrayList<>(); - for (String fieldname : fieldNames) { - StringPair sp = new StringPair(fieldname.trim(), ""); - vocabularySearchFields.add(sp); - } + Vocabulary currentVocabulary = vocabularyAPI.vocabularies().findByName(vocabularyName); + VocabularySchema vocabularySchema = vocabularyAPI.vocabularySchemas().get(currentVocabulary.getSchemaId()); + vocabularySearchFields = vocabularySchema.getDefinitions().stream() + .filter(d -> fieldsNames.contains(d.getName())) + .map(d -> new SelectItem(d.getId(), d.getName())) + .collect(Collectors.toList()); } else if (metadataDisplaytype == DisplayType.vocabularyList) { + try { + String vocabularyTitle = myValues.getItemList().get(0).getSource(); + String fields = myValues.getItemList().get(0).getField(); + Vocabulary currentVocabulary = vocabularyAPI.vocabularies().findByName(vocabularyTitle); + VocabularySchema schema = vocabularyAPI.vocabularySchemas().get(currentVocabulary.getSchemaId()); + + if (Boolean.TRUE.equals(schema.getHierarchicalRecords())) { + Helper.setFehlerMeldung(Helper.getTranslation("mets_error_configuredVocabularyListHierarchical", md.getType().getName(), vocabularyTitle)); + return; + } + + if (StringUtils.isBlank(fields)) { + try { + List recordList = vocabularyAPI.vocabularyRecords() + .list(currentVocabulary.getId()) + .all() + .request() + .getContent(); + ArrayList itemList = new ArrayList<>(recordList.size() + 1); + List selectItems = new ArrayList<>(recordList.size() + 1); + + String defaultLabel = myValues.getItemList().get(0).getLabel(); + if (StringUtils.isNotBlank(defaultLabel)) { + List defaultitems = new ArrayList<>(); + defaultitems.add(defaultLabel); + setDefaultItems(defaultitems); + } + itemList.add(new Item(Helper.getTranslation("bitteAuswaehlen"), "", false, "", "")); + selectItems.add(new SelectItem("", Helper.getTranslation("bitteAuswaehlen"))); + + for (ExtendedVocabularyRecord vr : recordList) { + selectItems.add(new SelectItem(vr.getMainValue(), vr.getMainValue())); + Item item = new Item(vr.getMainValue(), vr.getMainValue(), false, "", ""); + if (StringUtils.isNotBlank(defaultLabel) && defaultLabel.equals(vr.getMainValue())) { + item.setSelected(true); + } + itemList.add(item); + } + setPossibleItems(selectItems); + myValues.setItemList(itemList); + } catch (APIException e) { + Helper.setFehlerMeldung(Helper.getTranslation("mets_error_configuredVocabularyInvalid", md.getType().getName(), vocabularyTitle)); + metadataDisplaytype = DisplayType.input; + myValues.overwriteConfiguredElement(myProcess, md.getType()); + } + } else { + if (fields.contains(";")) { + Helper.setFehlerMeldung("vocabularyList with multiple fields is not supported right now"); + return; + } + + String searchFilter = fields.trim(); + Optional sorting = Optional.empty(); + if (searchFilter.contains("@")) { + String[] parts = searchFilter.split("@"); + searchFilter = parts[0]; + sorting = Optional.of(parts[1]); + } - String vocabularyTitle = myValues.getItemList().get(0).getSource(); + String fieldName = searchFilter; + Optional fieldValueFilter = Optional.empty(); - String fields = myValues.getItemList().get(0).getField(); + if (fieldName.contains("=")) { + String[] parts = searchFilter.split("="); + fieldName = parts[0]; + fieldValueFilter = Optional.of(parts[1]); + } - if (StringUtils.isBlank(fields)) { - Vocabulary currentVocabulary = VocabularyManager.getVocabularyByTitle(vocabularyTitle); - VocabularyManager.getAllRecords(currentVocabulary); + String finalFieldName = fieldName; + Optional searchField = schema.getDefinitions().stream() + .filter(d -> d.getName().equals(finalFieldName)) + .findFirst(); + + if (searchField.isEmpty()) { + Helper.setFehlerMeldung("Field " + fieldName + " not found in vocabulary " + currentVocabulary.getName()); + return; + } + + Optional sortingQuery = Optional.empty(); + if (sorting.isPresent()) { + sortingQuery = Optional.of(searchField.get().getId() + "," + sorting.get()); + } + Optional searchQuery = Optional.empty(); + if (fieldValueFilter.isPresent()) { + searchQuery = Optional.of(searchField.get().getId() + ":" + fieldValueFilter.get()); + } + List recordList = vocabularyAPI.vocabularyRecords() + .list(currentVocabulary.getId()) + .search(searchQuery) + .sorting(sortingQuery) + .request() + .getContent(); - if (currentVocabulary != null && currentVocabulary.getId() != null) { - List recordList = currentVocabulary.getRecords(); - Collections.sort(recordList); ArrayList itemList = new ArrayList<>(recordList.size() + 1); List selectItems = new ArrayList<>(recordList.size() + 1); @@ -296,60 +364,19 @@ private void initializeValues() { itemList.add(new Item(Helper.getTranslation("bitteAuswaehlen"), "", false, "", "")); selectItems.add(new SelectItem("", Helper.getTranslation("bitteAuswaehlen"))); - for (VocabRecord vr : recordList) { - for (Field f : vr.getFields()) { - if (f.getDefinition().isMainEntry()) { - selectItems.add(new SelectItem(f.getValue(), f.getValue())); - Item item = new Item(f.getValue(), f.getValue(), false, "", ""); - if (StringUtils.isNotBlank(defaultLabel) && defaultLabel.equals(f.getValue())) { - item.setSelected(true); - } - itemList.add(item); - break; - } + for (ExtendedVocabularyRecord vr : recordList) { + selectItems.add(new SelectItem(vr.getMainValue(), vr.getMainValue())); + Item item = new Item(vr.getMainValue(), vr.getMainValue(), false, "", ""); + if (StringUtils.isNotBlank(defaultLabel) && defaultLabel.equals(vr.getMainValue())) { + item.setSelected(true); } + itemList.add(item); } setPossibleItems(selectItems); myValues.setItemList(itemList); - } else { - Helper.setFehlerMeldung(Helper.getTranslation("mets_error_configuredVocabularyInvalid", md.getType().getName(), vocabularyTitle)); - metadataDisplaytype = DisplayType.input; - myValues.overwriteConfiguredElement(myProcess, md.getType()); - } - } else { - String[] fieldNames = fields.split(";"); - vocabularySearchFields = new ArrayList<>(); - for (String fieldname : fieldNames) { - String[] parts = fieldname.trim().split("="); - if (parts.length > 1) { - String name = parts[0]; - String value = parts[1]; - StringPair sp = new StringPair(name, value); - vocabularySearchFields.add(sp); - } - } - List recordList = VocabularyManager.findRecords(vocabularyTitle, vocabularySearchFields); - Collections.sort(recordList); - - if (recordList != null && !recordList.isEmpty()) { - ArrayList itemList = new ArrayList<>(recordList.size()); - List selectItems = new ArrayList<>(recordList.size()); - for (VocabRecord vr : recordList) { - for (Field f : vr.getFields()) { - if (f.getDefinition().isMainEntry()) { - selectItems.add(new SelectItem(f.getValue(), f.getValue())); - itemList.add(new Item(f.getValue(), f.getValue(), false, "", "")); - break; - } - } - } - setPossibleItems(selectItems); - myValues.setItemList(itemList); - } else { - Helper.setFehlerMeldung(Helper.getTranslation("mets_error_configuredVocabularyInvalid", md.getType().getName(), vocabularyTitle)); - metadataDisplaytype = DisplayType.input; - myValues.overwriteConfiguredElement(myProcess, md.getType()); } + } catch (APIException e) { + Helper.setFehlerMeldung(e); } } else if (metadataDisplaytype == DisplayType.generate) { for (Item item : myValues.getItemList()) { @@ -504,7 +531,7 @@ public String getSelectedItem() { String value = this.md.getValue(); if (value != null && value.length() != 0) { for (Item i : this.myValues.getItemList()) { - if (i.getValue().equals(value)) { + if (value.equals(i.getValue())) { return i.getLabel(); } } @@ -770,20 +797,7 @@ public String getData() { easydbSearch.getMetadata(md); break; case vocabularySearch: - for (Field currentField : selectedVocabularyRecord.getFields()) { - if (currentField.getDefinition().isMainEntry()) { - md.setValue(currentField.getValue()); - } - } - String url = ConfigurationHelper.getInstance().getGoobiAuthorityServerUrl(); - String user = ConfigurationHelper.getInstance().getGoobiAuthorityServerUser(); - Integer vocabularyId = selectedVocabularyRecord.getVocabularyId(); - Integer recordId = selectedVocabularyRecord.getId(); - if (StringUtils.isNotBlank(user) && StringUtils.isNotBlank(url)) { - md.setAutorityFile(vocabulary, url, url + user + "/vocabularies/" + vocabularyId + "/records/" + recordId); - } else { - md.setAutorityFile(vocabulary, vocabularyUrl, vocabularyUrl + "/jskos/" + vocabularyId + "/" + recordId); - } + selectedVocabularyRecord.writeReferenceMetadata(md); break; default: break; diff --git a/src/main/java/de/sub/goobi/metadaten/SearchableMetadata.java b/src/main/java/de/sub/goobi/metadaten/SearchableMetadata.java index dac8c8e89a..00a55cf108 100644 --- a/src/main/java/de/sub/goobi/metadaten/SearchableMetadata.java +++ b/src/main/java/de/sub/goobi/metadaten/SearchableMetadata.java @@ -110,4 +110,12 @@ default String filter(String str) { } return filtered.toString(); } + + public long getCurrentVocabularySearchField(); + + public void setCurrentVocabularySearchField(long field); + + public String getVocabularySearchQuery(); + + public void setVocabularySearchQuery(String query); } diff --git a/src/main/java/de/sub/goobi/persistence/managers/DatabaseVersion.java b/src/main/java/de/sub/goobi/persistence/managers/DatabaseVersion.java index 4a0eb4cd90..9e2b69e54c 100644 --- a/src/main/java/de/sub/goobi/persistence/managers/DatabaseVersion.java +++ b/src/main/java/de/sub/goobi/persistence/managers/DatabaseVersion.java @@ -42,9 +42,6 @@ import org.goobi.beans.User; import org.goobi.beans.Usergroup; import org.goobi.production.enums.LogType; -import org.goobi.vocabulary.Definition; -import org.goobi.vocabulary.VocabRecord; -import org.goobi.vocabulary.Vocabulary; import com.google.gson.Gson; @@ -934,48 +931,7 @@ private static void updateToVersion39() throws SQLException { } if (DatabaseVersion.checkIfTableExists("vocabularies")) { - String allVocabularies = "SELECT * FROM vocabularies"; - Connection connection = null; - try { - connection = MySQLHelper.getInstance().getConnection(); - QueryRunner runner = new QueryRunner(); - List vocabularyList = runner.query(connection, allVocabularies, VocabularyManager.resultSetToVocabularyListHandler); - String insert = "INSERT INTO vocabulary_record (id, vocabulary_id) VALUES (?,?)"; - String insertField = - "INSERT INTO vocabulary_record_data (record_id,vocabulary_id, definition_id, label, language, value) VALUES (?,?,?,?,?,?)"; - - for (Vocabulary vocabulary : vocabularyList) { - DatabaseVersion.runSql("INSERT INTO vocabulary(id, title, description) VALUES (" + vocabulary.getId() + ",'" - + vocabulary.getTitle() + "', '" + vocabulary.getDescription() + "')"); - for (Definition def : vocabulary.getStruct()) { - VocabularyManager.saveDefinition(vocabulary.getId(), def); - } - VocabularyManager.loadRecordsForVocabulary(vocabulary); - - for (VocabRecord rec : vocabulary.getRecords()) { - runner.insert(connection, insert, MySQLHelper.resultSetToIntegerHandler, rec.getId(), vocabulary.getId()); - - for (org.goobi.vocabulary.Field field : rec.getFields()) { - int fieldId = runner.insert(connection, insertField, MySQLHelper.resultSetToIntegerHandler, rec.getId(), - vocabulary.getId(), field.getDefinition().getId(), field.getLabel(), field.getLanguage(), field.getValue()); - field.setId(fieldId); - } - } - } - DatabaseVersion.runSql("drop table vocabularyRecords"); - DatabaseVersion.runSql("drop table vocabularies"); - - } catch (SQLException e) { - log.error(e); - } finally { - if (connection != null) { - try { - MySQLHelper.closeConnection(connection); - } catch (SQLException exception) { - log.warn(exception); - } - } - } + log.error("The vocabulary migration logic for this version has been removed. Please try to manually re-create the vocabularies or contact the support."); } } diff --git a/src/main/java/de/sub/goobi/persistence/managers/VocabularyManager.java b/src/main/java/de/sub/goobi/persistence/managers/VocabularyManager.java deleted file mode 100644 index 8faada094c..0000000000 --- a/src/main/java/de/sub/goobi/persistence/managers/VocabularyManager.java +++ /dev/null @@ -1,669 +0,0 @@ -/** - * This file is part of the Goobi Application - a Workflow tool for the support of mass digitization. - * - * Visit the websites for more information. - * - https://goobi.io - * - https://www.intranda.com - * - https://github.com/intranda/goobi-workflow - * - * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Linking this library statically or dynamically with other modules is making a combined work based on this library. Thus, the terms and conditions - * of the GNU General Public License cover the whole combination. As a special exception, the copyright holders of this library give you permission to - * link this library with independent modules to produce an executable, regardless of the license terms of these independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that you also meet, for each linked independent module, the terms and - * conditions of the license of that module. An independent module is a module which is not derived from or based on this library. If you modify this - * library, you may extend this exception to your version of the library, but you are not obliged to do so. If you do not wish to do so, delete this - * exception statement from your version. - */ -package de.sub.goobi.persistence.managers; - -import java.io.Serializable; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Timestamp; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -import org.apache.commons.dbutils.ResultSetHandler; -import org.goobi.beans.DatabaseObject; -import org.goobi.beans.Institution; -import org.goobi.production.cli.helper.StringPair; -import org.goobi.vocabulary.Definition; -import org.goobi.vocabulary.Field; -import org.goobi.vocabulary.VocabRecord; -import org.goobi.vocabulary.Vocabulary; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; - -import de.sub.goobi.helper.exceptions.DAOException; -import lombok.extern.log4j.Log4j2; - -@Log4j2 -public class VocabularyManager implements IManager, Serializable { - - private static final long serialVersionUID = 3577063138324090483L; - - @SuppressWarnings("deprecation") - private static JsonParser jsonParser = new JsonParser(); - - private static Gson gson = new GsonBuilder().create(); - - @Override - public int getHitSize(String order, String filter, Institution institution) throws DAOException { - try { - return VocabularyMysqlHelper.getVocabularyCount(filter); - } catch (SQLException e) { - log.error(e); - } - return 0; - } - - @Override - public List getList(String order, String filter, Integer start, Integer count, Institution institution) - throws DAOException { - try { - return VocabularyMysqlHelper.getVocabularies(order, filter, start, count); - } catch (SQLException e) { - log.error(e); - } - return null; - } - - public int getHitSize(String order, String filter) throws DAOException { - try { - return VocabularyMysqlHelper.getVocabularyCount(filter); - } catch (SQLException e) { - log.error(e); - } - return 0; - } - - public List getList(String order, String filter, Integer start, Integer count) throws DAOException { - try { - return VocabularyMysqlHelper.getVocabularies(order, filter, start, count); - } catch (SQLException e) { - log.error(e); - } - return null; - } - - @Override - public List getIdList(String order, String filter, Institution institution) { - return null; - } - - public static Vocabulary getVocabularyByTitle(String title) { - try { - return VocabularyMysqlHelper.getVocabularyByTitle(title); - } catch (SQLException e) { - log.error(e); - } - return null; - } - - public static Vocabulary getVocabularyById(Integer id) { - try { - return VocabularyMysqlHelper.getVocabularyById(id); - } catch (SQLException e) { - log.error(e); - } - return null; - } - - public static boolean isTitleUnique(Vocabulary vocabulary) { - try { - return VocabularyMysqlHelper.isTitleUnique(vocabulary); - } catch (SQLException e) { - log.error(e); - } - return false; - } - - /** - * @deprecated This handler is not used anymore - */ - @Deprecated(since = "23.05", forRemoval = false) - public static ResultSetHandler> resultSetToVocabularyListHandler = new ResultSetHandler>() { - - @Override - public List handle(ResultSet rs) throws SQLException { - List answer = new ArrayList<>(); - while (rs.next()) { - Vocabulary vocabulary = convert(rs); - answer.add(vocabulary); - } - return answer; - } - }; - - /** - * @deprecated This handler is not used anymore - */ - @Deprecated(since = "23.05", forRemoval = false) - public static ResultSetHandler resultSetToVocabularyHandler = new ResultSetHandler() { - - @Override - public Vocabulary handle(ResultSet rs) throws SQLException { - if (rs.next()) { - return convert(rs); - } - return null; - } - }; - - /** - * @deprecated This method is not used anymore - * - * @param rs - * @return - */ - @Deprecated(since = "23.05", forRemoval = false) - @SuppressWarnings("unchecked") - private static Vocabulary convert(ResultSet rs) throws SQLException { - int vocabId = rs.getInt("vocabId"); - String strVocabTitle = rs.getString("title"); - String strDescription = rs.getString("description"); - String jsonStruct = rs.getString("structure"); - ArrayList lstDefs = new ArrayList<>(); - - JsonArray struct = jsonParser.parse(jsonStruct).getAsJsonArray(); - - if (struct != null) { - for (JsonElement jsonElt : struct) { - - JsonObject jsonObj = jsonElt.getAsJsonObject(); - - String strLabel = jsonObj.get("label").getAsString(); - String strLanguage = jsonObj.get("language").getAsString(); - String strType = jsonObj.get("type").getAsString(); - String strValidation = jsonObj.get("validation").getAsString(); - - boolean bRequired = jsonObj.get("required").getAsBoolean(); - boolean bMainEntry = jsonObj.get("mainEntry").getAsBoolean(); - boolean bUnique = jsonObj.get("unique").getAsBoolean(); - - ArrayList selecteableValues = new ArrayList<>(); - JsonElement obj = jsonObj.get("selecteableValues"); - if (obj != null) { - JsonArray array = obj.getAsJsonArray(); - if (array != null) { - selecteableValues = gson.fromJson(array, ArrayList.class); - } - } - if (strLabel != null) { - Definition def = new Definition(strLabel, strLanguage, strType, strValidation, bRequired, bMainEntry, bUnique, bMainEntry); - def.setSelecteableValues(selecteableValues); - lstDefs.add(def); - - } - } - } - - Vocabulary vocab = new Vocabulary(); - vocab.setId(vocabId); - vocab.setTitle(strVocabTitle); - vocab.setDescription(strDescription); - vocab.setStruct(lstDefs); - vocab.setRecords(new ArrayList<>()); - return vocab; - } - - public static ResultSetHandler> vocabularyRecordListHandler = new ResultSetHandler>() { - - @Override - public List handle(ResultSet rs) throws SQLException { - - Map recordMap = new HashMap<>(); - List records = new LinkedList<>(); - - while (rs.next()) { - Integer fieldId = rs.getInt("id"); - Integer recordId = rs.getInt("record_id"); - Integer vocabularyId = rs.getInt("vocabulary_id"); - Integer definitionId = rs.getInt("definition_id"); - String label = rs.getString("label"); - String language = rs.getString("language"); - String value = rs.getString("value"); - - Field field = new Field(); - field.setId(fieldId); - field.setLabel(label); - field.setLanguage(language); - field.setValue(value); - field.setDefinitionId(definitionId); - VocabRecord rec = null; - if (recordMap.containsKey(recordId)) { - rec = recordMap.get(recordId); - } else { - rec = new VocabRecord(); - rec.setId(recordId); - rec.setVocabularyId(vocabularyId); - recordMap.put(recordId, rec); - records.add(rec); - } - rec.getFields().add(field); - } - - return records; - } - - }; - - public final static ResultSetHandler> vocabularyRecordMapHandler = new ResultSetHandler>() { - - @Override - public Map handle(ResultSet rs) throws SQLException { - - Map recordMap = new HashMap<>(); - Map records = new HashMap<>(); - - while (rs.next()) { - Integer fieldId = rs.getInt("id"); - Integer recordId = rs.getInt("record_id"); - Integer vocabularyId = rs.getInt("vocabulary_id"); - Integer definitionId = rs.getInt("definition_id"); - String label = rs.getString("label"); - String language = rs.getString("language"); - String value = rs.getString("value"); - - String idField = rs.getString("identifier"); - - Field field = new Field(); - field.setId(fieldId); - field.setLabel(label); - field.setLanguage(language); - field.setValue(value); - field.setDefinitionId(definitionId); - VocabRecord rec = null; - if (recordMap.containsKey(recordId)) { - rec = recordMap.get(recordId); - } else { - rec = new VocabRecord(); - rec.setId(recordId); - rec.setVocabularyId(vocabularyId); - recordMap.put(recordId, rec); - records.put(idField, rec); - } - rec.getFields().add(field); - } - - return records; - } - - }; - - /** - * @deprecated This handler is not used anymore - */ - @Deprecated(since = "23.05", forRemoval = false) - public static ResultSetHandler> resultSetToVocabularyRecordListHandler = new ResultSetHandler>() { - - @Override - public List handle(ResultSet rs) throws SQLException { - List records = new LinkedList<>(); - while (rs.next()) { - VocabRecord rec = convertRecord(rs); - if (rec != null) { - records.add(rec); - } - } - return records; - } - - }; - - /** - * @deprecated This handler is not used anymore - */ - @Deprecated(since = "23.05", forRemoval = false) - public static ResultSetHandler resultSetToVocabularyRecordHandler = new ResultSetHandler() { - - @Override - public VocabRecord handle(ResultSet rs) throws SQLException { - if (rs.next()) { - return convertRecord(rs); - } - return null; - } - - }; - - /** - * @deprecated This method is not used anymore - * - * @param rs - * @return - */ - @Deprecated(since = "23.05", forRemoval = false) - private static VocabRecord convertRecord(ResultSet rs) throws SQLException { - - int iRecordId = rs.getInt("recordId"); - List lstFields = new ArrayList<>(); - - int iVocabId = rs.getInt("vocabId"); - - JsonElement eltAttr = null; - if (rs.getString("attr") != null) { - eltAttr = jsonParser.parse(rs.getString("attr")); - } - - if (eltAttr != null) { - try { - JsonArray attr = eltAttr.getAsJsonArray(); - if (attr != null) { - for (JsonElement jsonElt : attr) { - - JsonObject jsonField = jsonElt.getAsJsonObject(); - lstFields.add(gson.fromJson(jsonField, Field.class)); - } - } - return new VocabRecord(iRecordId, iVocabId, lstFields); - } catch (Exception e) { - log.error(e); - } - } - return null; - } - - public static void saveVocabulary(Vocabulary vocabulary) { - try { - VocabularyMysqlHelper.saveVocabulary(vocabulary); - setVocabularyLastAltered(vocabulary); - } catch (SQLException e) { - log.error(e); - } - } - - public static void deleteVocabulary(Vocabulary vocabulary) { - try { - VocabularyMysqlHelper.deleteVocabulary(vocabulary); - } catch (SQLException e) { - log.error(e); - } - - } - - /** - * @deprecated This method is replaced by getAllRecords(Vocabulary) - * - * @param vocabulary - */ - @Deprecated(since = "23.05", forRemoval = false) - public static void loadRecordsForVocabulary(Vocabulary vocabulary) { - try { - VocabularyMysqlHelper.loadRecordsForVocabulary(vocabulary); - } catch (SQLException e) { - log.error(e); - } - } - - public static void getAllRecords(Vocabulary vocabulary) { - try { - VocabularyMysqlHelper.getAllRecords(vocabulary); - } catch (SQLException e) { - log.error(e); - } - } - - public static void deleteRecord(VocabRecord vocabRecord) { - try { - VocabularyMysqlHelper.deleteRecord(vocabRecord); - setVocabularyLastAltered(vocabRecord.getVocabularyId()); - } catch (SQLException e) { - log.error(e); - } - - } - - public static void deleteAllRecords(Vocabulary vocabulary) { - try { - VocabularyMysqlHelper.deleteAllRecords(vocabulary); - setVocabularyLastAltered(vocabulary); - } catch (SQLException e) { - log.error(e); - } - } - - public static void saveRecords(Vocabulary vocabulary) { - try { - VocabularyMysqlHelper.saveRecords(vocabulary); - setVocabularyLastAltered(vocabulary); - } catch (SQLException e) { - log.error(e); - } - } - - public static void saveRecord(Integer vocabularyId, VocabRecord vocabRecord) { - try { - VocabularyMysqlHelper.saveRecord(vocabularyId, vocabRecord); - setVocabularyLastAltered(vocabularyId); - } catch (SQLException e) { - log.error(e); - } - } - - /** - * Find the vocabulary records which contain a given string in given fields. This search does not search for exact string match. It does a - * 'contains'-search - * - * @param vocabularyName the vocabulary to search for - * @param searchValue the value to be searched as term that must be contained within the defined field - * @param fieldNames the list of fields to search in - * @return a list of vocabulary records - * - * @throws SQLException - */ - public static List findRecords(String vocabularyName, String searchValue, String... fieldNames) { - try { - return VocabularyMysqlHelper.findRecords(vocabularyName, searchValue, false, fieldNames); - } catch (SQLException e) { - log.error(e); - } - return null; - } - - /** - * Find the vocabulary records which match exactly the given string in the defined fields. This search does search for exact string match. - * - * @param vocabularyName the vocabulary to search for - * @param searchValue the value to be searched as term that must be identical in the defined field - * @param fieldNames the list of fields to search in - * @return a list of vocabulary records - * - * @throws SQLException - */ - public static List findExactRecords(String vocabularyName, String searchValue, String... fieldNames) { - try { - return VocabularyMysqlHelper.findRecords(vocabularyName, searchValue, true, fieldNames); - } catch (SQLException e) { - log.error(e); - } - return null; - } - - public static VocabRecord getRecord(Integer vocabularyId, Integer recordId) { - try { - return VocabularyMysqlHelper.getRecord(vocabularyId, recordId); - } catch (SQLException e) { - log.error(e); - } - return null; - } - - /** - * Search in the vocabulary for String Pairs which contain the searched terms. This search does not contain exact matches as it does a - * contains-search - * - * @param vocabularyName the vocabulary to search within - * @param data the StringPair to use for searching - * @return Vocabulary records - * - * @throws SQLException - */ - public static List findRecords(String vocabularyName, List data) { - try { - return VocabularyMysqlHelper.findRecords(vocabularyName, data, false); - } catch (SQLException e) { - log.error(e); - } - return null; - } - - /** - * Search in the vocabulary for String Pairs which match exactly the searched terms. This search lists only exact matches. - * - * @param vocabularyName the vocabulary to search within - * @param data the StringPair to use for searching - * @return Vocabulary records - * - * @throws SQLException - */ - public static List findExactRecords(String vocabularyName, List data) { - try { - return VocabularyMysqlHelper.findRecords(vocabularyName, data, true); - } catch (SQLException e) { - log.error(e); - } - return null; - } - - public static Map getRecordMap(int vacabularyId, int definitionId) { - try { - return VocabularyMysqlHelper.getRecordMap(vacabularyId, definitionId); - } catch (SQLException e) { - log.error(e); - } - return Collections.emptyMap(); - } - - /** - * @deprecated This method is not used anymore - * - * @param vocabulary - */ - @Deprecated(since = "23.05", forRemoval = false) - public static void getPaginatedRecords(Vocabulary vocabulary) { - try { - VocabularyMysqlHelper.getRecords(vocabulary); - } catch (SQLException e) { - log.error(e); - } - } - - public static void saveDefinition(Integer vocabularyId, Definition definition) { - try { - VocabularyMysqlHelper.saveDefinition(vocabularyId, definition); - setVocabularyLastAltered(vocabularyId); - } catch (SQLException e) { - log.error(e); - } - } - - public static void deleteDefinition(Definition definition) { - try { - VocabularyMysqlHelper.deleteDefinition(definition); - } catch (SQLException e) { - log.error(e); - } - } - - public static void insertNewRecords(List records, Integer vocabularyID) { - try { - VocabularyMysqlHelper.insertNewRecords(records, vocabularyID); - setVocabularyLastAltered(vocabularyID); - } catch (SQLException e) { - log.error(e); - } - } - - public static void batchUpdateRecords(List records, Integer vocabularyID) { - try { - VocabularyMysqlHelper.batchUpdateRecords(records, vocabularyID); - setVocabularyLastAltered(vocabularyID); - } catch (SQLException e) { - log.error(e); - } - - } - - private static void setVocabularyLastAltered(int vocabularyId) { - Vocabulary vocab = getVocabularyById(vocabularyId); - setVocabularyLastAltered(vocab); - } - - public static void setVocabularyLastAltered(Vocabulary vocabulary) { - try { - VocabularyMysqlHelper.setVocabularyLastAltered(vocabulary); - } catch (SQLException e) { - log.error(e); - } - } - - public static void setVocabularyLastUploaded(Vocabulary vocabulary) { - try { - VocabularyMysqlHelper.setVocabularyLastUploaded(vocabulary); - } catch (SQLException e) { - log.error(e); - } - } - - public static Timestamp getVocabularyLastAltered(Vocabulary vocabulary) { - try { - return VocabularyMysqlHelper.getVocabularyLastAltered(vocabulary); - } catch (SQLException e) { - log.error(e); - } - - return null; - } - - public static Timestamp getVocabularyLastUploaded(Vocabulary vocabulary) { - try { - return VocabularyMysqlHelper.getVocabularyLastUploaded(vocabulary); - } catch (SQLException e) { - log.error(e); - } - return null; - } - - public static ResultSetHandler resultSetGetLastUploadedHandler = new ResultSetHandler() { - - @Override - public Timestamp handle(ResultSet rs) throws SQLException { - if (rs.next()) { - return rs.getTimestamp("lastUploaded"); - } - return null; - } - - }; - - public static ResultSetHandler resultSetGetLastAlteredHandler = new ResultSetHandler() { - - @Override - public Timestamp handle(ResultSet rs) throws SQLException { - if (rs.next()) { - return rs.getTimestamp("lastAltered"); - } - return null; - } - - }; -} diff --git a/src/main/java/de/sub/goobi/persistence/managers/VocabularyMysqlHelper.java b/src/main/java/de/sub/goobi/persistence/managers/VocabularyMysqlHelper.java deleted file mode 100644 index 91ae10ffdc..0000000000 --- a/src/main/java/de/sub/goobi/persistence/managers/VocabularyMysqlHelper.java +++ /dev/null @@ -1,1031 +0,0 @@ -/** - * This file is part of the Goobi Application - a Workflow tool for the support of mass digitization. - * - * Visit the websites for more information. - * - https://goobi.io - * - https://www.intranda.com - * - https://github.com/intranda/goobi-workflow - * - * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Linking this library statically or dynamically with other modules is making a combined work based on this library. Thus, the terms and conditions - * of the GNU General Public License cover the whole combination. As a special exception, the copyright holders of this library give you permission to - * link this library with independent modules to produce an executable, regardless of the license terms of these independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that you also meet, for each linked independent module, the terms and - * conditions of the license of that module. An independent module is a module which is not derived from or based on this library. If you modify this - * library, you may extend this exception to your version of the library, but you are not obliged to do so. If you do not wish to do so, delete this - * exception statement from your version. - */ -package de.sub.goobi.persistence.managers; - -import java.io.Serializable; -import java.sql.Connection; -import java.sql.SQLException; -import java.sql.Timestamp; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import org.apache.commons.dbutils.QueryRunner; -import org.apache.commons.dbutils.StatementConfiguration; -import org.apache.commons.dbutils.handlers.BeanHandler; -import org.apache.commons.dbutils.handlers.BeanListHandler; -import org.apache.commons.lang3.StringUtils; -import org.goobi.production.cli.helper.StringPair; -import org.goobi.vocabulary.Definition; -import org.goobi.vocabulary.Field; -import org.goobi.vocabulary.VocabRecord; -import org.goobi.vocabulary.Vocabulary; - -import com.google.gson.Gson; - -import de.sub.goobi.persistence.managers.MySQLHelper.SQLTYPE; - -/** - * @author steffen - * - */ -class VocabularyMysqlHelper implements Serializable { - - private static final long serialVersionUID = 5141386688477409583L; - - private static final Integer MAXIMAL_QUERY_RESULTS = 10_000; - - private static final Integer QUERY_TIMEOUT_IN_SECONDS = 20; - - private static String vocabTable = "vocabulary"; - - static Vocabulary getVocabularyByTitle(String title) throws SQLException { - StringBuilder sql = new StringBuilder(); - sql.append("SELECT * FROM vocabulary v WHERE v.title = ?"); - Connection connection = null; - try { - connection = MySQLHelper.getInstance().getConnection(); - Vocabulary ret = new QueryRunner().query(connection, sql.toString(), new BeanHandler<>(Vocabulary.class), title); - if (ret != null) { - ret.setStruct(getDefinitionsForVocabulary(ret.getId())); - } - return ret; - } finally { - if (connection != null) { - MySQLHelper.closeConnection(connection); - } - } - } - - static List getDefinitionsForVocabulary(Integer vocabularyId) throws SQLException { - StringBuilder sql = new StringBuilder(); - sql.append("SELECT * FROM vocabulary_structure v WHERE v.vocabulary_id = ?"); - Connection connection = null; - try { - connection = MySQLHelper.getInstance().getConnection(); - return new QueryRunner().query(connection, sql.toString(), new BeanListHandler<>(Definition.class), vocabularyId); - } finally { - if (connection != null) { - MySQLHelper.closeConnection(connection); - } - } - } - - static Vocabulary getVocabularyById(Integer id) throws SQLException { - StringBuilder sql = new StringBuilder(); - sql.append("SELECT * FROM vocabulary v WHERE v.id = ?"); - Connection connection = null; - try { - connection = MySQLHelper.getInstance().getConnection(); - Vocabulary ret = new QueryRunner().query(connection, sql.toString(), new BeanHandler<>(Vocabulary.class), id); - ret.setStruct(getDefinitionsForVocabulary(ret.getId())); - return ret; - } finally { - if (connection != null) { - MySQLHelper.closeConnection(connection); - } - } - } - - static List getVocabularies(String order, String filter, Integer start, Integer count) throws SQLException { - Connection connection = null; - StringBuilder sql = new StringBuilder(); - sql.append("SELECT * FROM vocabulary"); - if (filter != null && !filter.isEmpty()) { - sql.append(" WHERE " + filter); - } - if (order != null && !order.isEmpty()) { - sql.append(" ORDER BY " + order); - } - if (start != null && count != null) { - sql.append(" LIMIT " + start + ", " + count); - } - try { - connection = MySQLHelper.getInstance().getConnection(); - - List ret = new QueryRunner().query(connection, sql.toString(), new BeanListHandler<>(Vocabulary.class)); - for (Vocabulary v : ret) { - v.setStruct(getDefinitionsForVocabulary(v.getId())); - } - return ret; - } finally { - if (connection != null) { - MySQLHelper.closeConnection(connection); - } - } - } - - static int getVocabularyCount(String filter) throws SQLException { - Connection connection = null; - StringBuilder sql = new StringBuilder(); - sql.append("SELECT COUNT(1) FROM vocabulary"); - if (filter != null && !filter.isEmpty()) { - sql.append(" WHERE " + filter); - } - try { - connection = MySQLHelper.getInstance().getConnection(); - - return new QueryRunner().query(connection, sql.toString(), MySQLHelper.resultSetToIntegerHandler); - } finally { - if (connection != null) { - MySQLHelper.closeConnection(connection); - } - } - } - - static boolean isTitleUnique(Vocabulary vocabulary) throws SQLException { - String sql; - if (vocabulary.getId() == null) { - // new vocabulary, check against all vocabularies - sql = "SELECT count(1) FROM vocabulary WHERE title = ?"; - } else { - // existing vocabulary, exclude current vocabulary from check - sql = "SELECT count(1) FROM vocabulary WHERE title = ? and id !=" + vocabulary.getId(); - } - Connection connection = null; - try { - connection = MySQLHelper.getInstance().getConnection(); - int numberOfProcessesWithTitle = new QueryRunner().query(connection, sql, MySQLHelper.resultSetToIntegerHandler, vocabulary.getTitle()); - return (numberOfProcessesWithTitle == 0); - } finally { - if (connection != null) { - MySQLHelper.closeConnection(connection); - } - } - } - - static void saveVocabulary(Vocabulary vocabulary) throws SQLException { - StringBuilder sql = new StringBuilder(); - if (vocabulary.getId() == null) { - sql.append("INSERT INTO vocabulary (title, description) "); - sql.append("VALUES (?,?)"); - } else { - sql.append("UPDATE vocabulary "); - sql.append("SET title = ?, description = ? "); - sql.append("WHERE id = " + vocabulary.getId()); - } - Connection connection = null; - try { - connection = MySQLHelper.getInstance().getConnection(); - QueryRunner run = new QueryRunner(); - if (vocabulary.getId() == null) { - Integer id = run.insert(connection, sql.toString(), MySQLHelper.resultSetToIntegerHandler, vocabulary.getTitle(), - vocabulary.getDescription()); - vocabulary.setId(id); - } else { - run.update(connection, sql.toString(), vocabulary.getTitle(), vocabulary.getDescription()); - } - - } finally { - if (connection != null) { - MySQLHelper.closeConnection(connection); - } - } - for (Definition definition : vocabulary.getStruct()) { - saveDefinition(vocabulary.getId(), definition); - } - } - - static void saveDefinition(Integer vocabularyId, Definition definition) throws SQLException { - StringBuilder sql = new StringBuilder(); - if (definition.getId() == null) { - sql.append("INSERT INTO vocabulary_structure (vocabulary_id, label,language, type,validation,"); - sql.append("required ,mainEntry,distinctive,selection, titleField) "); - sql.append("VALUES (?,?,?,?,?,?,?,?,?,?)"); - } else { - sql.append("UPDATE vocabulary_structure "); - sql.append("SET vocabulary_id = ?, label = ?, "); - sql.append("language = ?, type = ?, "); - sql.append("validation = ?, required = ?, "); - sql.append("mainEntry = ?, distinctive = ?, selection = ?, titleField = ? "); - sql.append("WHERE id = " + definition.getId()); - } - Connection connection = null; - try { - connection = MySQLHelper.getInstance().getConnection(); - QueryRunner run = new QueryRunner(); - if (definition.getId() == null) { - Integer id = run.insert(connection, sql.toString(), MySQLHelper.resultSetToIntegerHandler, vocabularyId, definition.getLabel(), - definition.getLanguage(), definition.getType(), definition.getValidation(), definition.isRequired(), definition.isMainEntry(), - definition.isDistinctive(), definition.getSelection(), definition.isTitleField()); - definition.setId(id); - } else { - run.update(connection, sql.toString(), vocabularyId, definition.getLabel(), definition.getLanguage(), definition.getType(), - definition.getValidation(), definition.isRequired(), definition.isMainEntry(), definition.isDistinctive(), - definition.getSelection(), definition.isTitleField()); - } - } finally { - if (connection != null) { - MySQLHelper.closeConnection(connection); - } - } - } - - static void deleteDefinition(Definition definition) throws SQLException { - Connection connection = null; - try { - connection = MySQLHelper.getInstance().getConnection(); - QueryRunner run = new QueryRunner(); - run.update(connection, "DELETE FROM vocabulary_structure WHERE id = ?", definition.getId()); - } finally { - if (connection != null) { - MySQLHelper.closeConnection(connection); - } - } - } - - /** - * @deprecated This method is not used anymore - * - * @param vocabulary - * @param gson - */ - @Deprecated(since = "23.05", forRemoval = true) - static void saveVocabulary(Vocabulary vocabulary, Gson gson) throws SQLException { - StringBuilder sql = new StringBuilder(); - - if (vocabulary.getId() == null) { - sql.append("INSERT INTO " + vocabTable + "(title, description, structure) "); - sql.append("VALUES (?,?,?)"); - } else { - sql.append("UPDATE " + vocabTable + " "); - sql.append("SET title = ?, description = ?, structure = ? "); - sql.append("WHERE vocabId = " + vocabulary.getId()); - } - Connection connection = null; - - try { - connection = MySQLHelper.getInstance().getConnection(); - QueryRunner run = new QueryRunner(); - if (vocabulary.getId() == null) { - Integer id = run.insert(connection, sql.toString(), MySQLHelper.resultSetToIntegerHandler, vocabulary.getTitle(), - vocabulary.getDescription(), gson.toJson(vocabulary.getStruct())); - vocabulary.setId(id); - } else { - run.update(connection, sql.toString(), vocabulary.getTitle(), vocabulary.getDescription(), gson.toJson(vocabulary.getStruct())); - } - } finally { - if (connection != null) { - MySQLHelper.closeConnection(connection); - } - } - - } - - static void deleteVocabulary(Vocabulary vocabulary) throws SQLException { - if (vocabulary.getId() != null) { - String deleteRecords = "DELETE FROM vocabulary_record WHERE vocabulary_id = ?"; - String deleteRecordData = "DELETE FROM vocabulary_record_data WHERE vocabulary_id = ?"; - String deleteVocabulary = "DELETE from vocabulary WHERE id = ?"; - String deleteDefinitions = "DELETE from vocabulary_structure WHERE vocabulary_id = ?"; - Connection connection = null; - try { - connection = MySQLHelper.getInstance().getConnection(); - QueryRunner run = new QueryRunner(); - run.update(connection, deleteRecordData, vocabulary.getId()); - run.update(connection, deleteRecords, vocabulary.getId()); - run.update(connection, deleteDefinitions, vocabulary.getId()); - run.update(connection, deleteVocabulary, vocabulary.getId()); - } finally { - if (connection != null) { - MySQLHelper.closeConnection(connection); - } - } - } - } - - static void getAllRecords(Vocabulary vocabulary) throws SQLException { - if (vocabulary != null && vocabulary.getId() != null) { - String sql = "SELECT * FROM vocabulary_record_data WHERE vocabulary_id = ?"; - Connection connection = null; - try { - connection = MySQLHelper.getInstance().getConnection(); - List records = - new QueryRunner().query(connection, sql, VocabularyManager.vocabularyRecordListHandler, vocabulary.getId()); - for (VocabRecord rec : records) { - setDefinitionsToRecord(rec, vocabulary); - } - vocabulary.setRecords(records); - } finally { - if (connection != null) { - MySQLHelper.closeConnection(connection); - } - } - } - } - - /** - * @deprecated This method is not used anymore - * - * @param vocabulary - */ - @Deprecated(since = "23.05", forRemoval = true) - static void loadRecordsForVocabulary(Vocabulary vocabulary) throws SQLException { - if (vocabulary != null && vocabulary.getId() != null) { - String sql = "SELECT * FROM vocabularyRecords WHERE vocabId = ?"; - Connection connection = null; - try { - connection = MySQLHelper.getInstance().getConnection(); - List records = - new QueryRunner().query(connection, sql, VocabularyManager.resultSetToVocabularyRecordListHandler, vocabulary.getId()); - for (VocabRecord rec : records) { - // merge expected definitions with existing definitions - mergeRecordAndVocabulary(vocabulary, rec); - } - vocabulary.setRecords(records); - } finally { - if (connection != null) { - MySQLHelper.closeConnection(connection); - } - } - } - } - - /** - * @deprecated This method is not used anymore - * - * @param vocabulary - * @param rec - */ - @Deprecated(since = "23.05", forRemoval = true) - private static void mergeRecordAndVocabulary(Vocabulary vocabulary, VocabRecord rec) { - for (Definition definition : vocabulary.getStruct()) { - boolean fieldFound = false; - for (Field f : rec.getFields()) { - if (f.getLabel().equals(definition.getLabel()) - && ((StringUtils.isBlank(f.getLanguage()) && StringUtils.isBlank(definition.getLanguage())) - || definition.getLanguage().equals(f.getLanguage()))) { - f.setDefinition(definition); - fieldFound = true; - break; - } - } - if (!fieldFound) { - Field field = new Field(definition.getLabel(), definition.getLanguage(), "", definition); - rec.getFields().add(field); - } - } - // check if field definition was deleted - // if this is the case, remove the field as well - List fieldsToDelete = new ArrayList<>(); - for (Field f : rec.getFields()) { - if (f.getDefinition() == null) { - fieldsToDelete.add(f); - } - } - if (!fieldsToDelete.isEmpty()) { - for (Field f : fieldsToDelete) { - rec.getFields().remove(f); - } - } - // set field order - List orderedList = new ArrayList<>(rec.getFields().size()); - for (Definition definition : vocabulary.getStruct()) { - for (Field f : rec.getFields()) { - if (f.getDefinition().equals(definition)) { - orderedList.add(f); - break; - } - } - } - rec.setFields(orderedList); - } - - static void deleteRecord(VocabRecord vocabRecord) throws SQLException { - if (vocabRecord.getId() != null) { - String deleteFields = "DELETE from vocabulary_record_data WHERE record_id = ?"; - String deleteRecord = "DELETE from vocabulary_record WHERE id = ?"; - Connection connection = null; - try { - connection = MySQLHelper.getInstance().getConnection(); - QueryRunner run = new QueryRunner(); - run.update(connection, deleteFields, vocabRecord.getId()); - run.update(connection, deleteRecord, vocabRecord.getId()); - } finally { - if (connection != null) { - MySQLHelper.closeConnection(connection); - } - } - } - } - - static void deleteAllRecords(Vocabulary vocabulary) throws SQLException { - if (vocabulary.getId() != null) { - String deleteFields = "DELETE from vocabulary_record_data WHERE vocabulary_id = ? "; - String deleteRecords = "DELETE from vocabulary_record WHERE vocabulary_id = ? "; - Connection connection = null; - try { - connection = MySQLHelper.getInstance().getConnection(); - QueryRunner run = new QueryRunner(); - run.update(connection, deleteFields, vocabulary.getId()); - run.update(connection, deleteRecords, vocabulary.getId()); - } finally { - if (connection != null) { - MySQLHelper.closeConnection(connection); - } - } - } - } - - static void saveRecords(Vocabulary vocabulary) throws SQLException { - String insertRecord = "INSERT INTO vocabulary_record (vocabulary_id) VALUES (?)"; - String insertField = - "INSERT INTO vocabulary_record_data (record_id,vocabulary_id, definition_id, label, language, value) VALUES (?,?,?,?,?,?)"; - String updateField = - "UPDATE vocabulary_record_data set record_id=?,vocabulary_id=?, definition_id=?, label=?, language=?, value=? WHERE id = ?"; - Connection connection = null; - try { - connection = MySQLHelper.getInstance().getConnection(); - QueryRunner run = new QueryRunner(); - for (VocabRecord vocabRecord : vocabulary.getRecords()) { - if (vocabRecord.getId() == null) { - Integer id = run.insert(connection, insertRecord, MySQLHelper.resultSetToIntegerHandler, vocabulary.getId()); - vocabRecord.setId(id); - } - for (Field field : vocabRecord.getFields()) { - if (field.getId() == null) { - Integer id = run.insert(connection, insertField, MySQLHelper.resultSetToIntegerHandler, vocabRecord.getId(), - vocabulary.getId(), field.getDefinition().getId(), field.getLabel(), field.getLanguage(), field.getValue()); - field.setId(id); - } else { - run.update(connection, updateField, vocabRecord.getId(), vocabulary.getId(), field.getDefinition().getId(), field.getLabel(), - field.getLanguage(), field.getValue(), field.getId()); - } - } - } - } finally { - if (connection != null) { - MySQLHelper.closeConnection(connection); - } - } - } - - static void saveRecord(Integer vocabularyId, VocabRecord vocabRecord) throws SQLException { - String insertRecord = "INSERT INTO vocabulary_record (vocabulary_id) VALUES (?)"; - String insertField = - "INSERT INTO vocabulary_record_data (record_id,vocabulary_id, definition_id, label, language, value) VALUES (?,?,?,?,?,?)"; - String updateField = - "UPDATE vocabulary_record_data set record_id=?,vocabulary_id=?, definition_id=?, label=?, language=?, value=? WHERE id = ?"; - Connection connection = null; - try { - connection = MySQLHelper.getInstance().getConnection(); - QueryRunner run = new QueryRunner(); - if (vocabRecord.getId() == null) { - Integer id = run.insert(connection, insertRecord, MySQLHelper.resultSetToIntegerHandler, vocabularyId); - vocabRecord.setId(id); - } - for (Field field : vocabRecord.getFields()) { - if (field.getId() == null) { - Integer id = run.insert(connection, insertField, MySQLHelper.resultSetToIntegerHandler, vocabRecord.getId(), vocabularyId, - field.getDefinition().getId(), field.getLabel(), field.getLanguage(), field.getValue()); - field.setId(id); - } else { - run.update(connection, updateField, vocabRecord.getId(), vocabularyId, field.getDefinition().getId(), field.getLabel(), - field.getLanguage(), field.getValue(), field.getId()); - } - } - - } finally { - if (connection != null) { - MySQLHelper.closeConnection(connection); - } - } - } - - static List findRecords(String vocabularyName, String searchValue, boolean exact, String... fieldNames) throws SQLException { - String likeStr = "like"; - if (MySQLHelper.getInstance().getSqlType() == SQLTYPE.H2) { - likeStr = "ilike"; - } - - searchValue = MySQLHelper.escapeSql(searchValue.replace("\"", "_")); - StringBuilder sb = new StringBuilder(); - sb.append("SELECT distinct record_id FROM vocabulary_record_data r LEFT JOIN vocabulary v ON v.id = r.vocabulary_id WHERE v.title = ? "); - sb.append("AND r.value "); - sb.append(likeStr); - sb.append(" '"); - if (!exact) { - sb.append("%"); - } - sb.append(searchValue); - if (!exact) { - sb.append("%"); - } - sb.append("' "); - if (fieldNames != null && fieldNames.length > 0) { - sb.append(" AND ("); - StringBuilder subQuery = new StringBuilder(); - for (String fieldName : fieldNames) { - if (subQuery.length() > 0) { - subQuery.append(" OR "); - } - subQuery.append("r.label ='" + MySQLHelper.escapeSql(fieldName) + "'"); - } - sb.append(subQuery.toString()); - sb.append(")"); - - } - - Connection connection = null; - try { - connection = MySQLHelper.getInstance().getConnection(); - QueryRunner runner = new QueryRunner(); - List idList = - runner.query(connection, sb.toString(), MySQLHelper.resultSetToIntegerListHandler, MySQLHelper.escapeSql(vocabularyName)); - - if (idList.isEmpty()) { - return Collections.emptyList(); - } - StringBuilder query = new StringBuilder(); - query.append("SELECT * FROM vocabulary_record_data r LEFT JOIN vocabulary v ON v.id = r.vocabulary_id WHERE r.record_id in ("); - StringBuilder sub = new StringBuilder(); - - for (Integer id : idList) { - if (sub.length() > 0) { - sub.append(", "); - } - sub.append(id); - } - - query.append(sub.toString()); - query.append(")"); - List records = new QueryRunner().query(connection, query.toString(), VocabularyManager.vocabularyRecordListHandler); - - Vocabulary vocabulary = getVocabularyByTitle(vocabularyName); - for (VocabRecord rec : records) { - setDefinitionsToRecord(rec, vocabulary); - } - - return records; - - } finally { - if (connection != null) { - MySQLHelper.closeConnection(connection); - } - } - } - - private static void setDefinitionsToRecord(VocabRecord rec, Vocabulary vocabulary) { - for (Definition def : vocabulary.getStruct()) { - boolean fieldFound = false; - for (Field field : rec.getFields()) { - if (def.getId().equals(field.getDefinitionId())) { - field.setDefinition(def); - fieldFound = true; - break; - } - } - if (!fieldFound) { - Field field = new Field(); - field.setDefinition(def); - field.setLabel(def.getLabel()); - field.setLanguage(def.getLanguage()); - rec.getFields().add(field); - } - } - } - - static VocabRecord getRecord(Integer vocabularyId, Integer recordId) throws SQLException { - if (vocabularyId == null || recordId == null) { - return null; - } - String sql = "SELECT * FROM vocabulary_record_data WHERE vocabulary_id = ? AND record_id = ?"; - Connection connection = null; - try { - connection = MySQLHelper.getInstance().getConnection(); - - List recordList = - new QueryRunner().query(connection, sql, VocabularyManager.vocabularyRecordListHandler, vocabularyId, recordId); - VocabRecord rec = null; - if (!recordList.isEmpty()) { - Vocabulary vocabulary = getVocabularyById(vocabularyId); - rec = recordList.get(0); - setDefinitionsToRecord(rec, vocabulary); - } - return rec; - } finally { - if (connection != null) { - MySQLHelper.closeConnection(connection); - } - } - } - - /** - * @deprecated This method is not used anymore - * - * @param vocabulary - */ - @Deprecated(since = "23.05", forRemoval = true) - static void getRecords(Vocabulary vocabulary) throws SQLException { - String likeStr = "like"; - if (MySQLHelper.getInstance().getSqlType() == SQLTYPE.H2) { - likeStr = "ilike"; - } - - StringBuilder sb = new StringBuilder(); - sb.append("SELECT vocabularyRecords.* FROM vocabularyRecords LEFT JOIN " + vocabTable + " ON vocabularyRecords.vocabId=" + vocabTable - + ".vocabId "); - sb.append("WHERE " + vocabTable + ".vocabId = ? "); - StringBuilder subQuery = new StringBuilder(); - - if (StringUtils.isNotBlank(vocabulary.getSearchField())) { - if (subQuery.length() == 0) { - subQuery.append(" AND "); - subQuery.append("("); - } else { - subQuery.append(" OR "); - } - subQuery.append("attr "); - subQuery.append(likeStr); - subQuery.append(" '%label\":\"" + MySQLHelper.escapeSql(vocabulary.getMainFieldName()) + "\",\"language\":\"%\",\"value\":\"%" - + MySQLHelper.escapeSql(vocabulary.getSearchField().replace("\"", "_")) + "%' "); - } - - if (subQuery.length() > 0) { - subQuery.append(")"); - sb.append(subQuery.toString()); - } - - Connection connection = null; - - try { - connection = MySQLHelper.getInstance().getConnection(); - QueryRunner runner = new QueryRunner(); - - // total number of records - - int numberOfRecords = runner.query(connection, "SELECT COUNT(1) FROM (" + sb.toString() + ") a", MySQLHelper.resultSetToIntegerHandler, - vocabulary.getId()); - vocabulary.setTotalNumberOfRecords(numberOfRecords); - - // order - if (MySQLHelper.isJsonCapable()) { - String sqlPathToField = "SELECT REPLACE(JSON_SEARCH(attr, 'one', '" + vocabulary.getMainFieldName() - + "'), 'label','value') from vocabularyRecords WHERE vocabId= ? limit 1"; - String field = runner.query(connection, sqlPathToField, MySQLHelper.resultSetToStringHandler, vocabulary.getId()); - sb.append(" ORDER BY " + "JSON_EXTRACT(attr, " + field + ") "); - if (StringUtils.isNotBlank(vocabulary.getOrder())) { - sb.append(vocabulary.getOrder()); - } - } - // limit - sb.append(" LIMIT " + (vocabulary.getPageNo() * vocabulary.getNumberOfRecordsPerPage()) + ", " + vocabulary.getNumberOfRecordsPerPage()); - - List records = - runner.query(connection, sb.toString(), VocabularyManager.resultSetToVocabularyRecordListHandler, vocabulary.getId()); - for (VocabRecord rec : records) { - // merge expected definitions with existing definitions - mergeRecordAndVocabulary(vocabulary, rec); - } - vocabulary.setRecords(records); - - } finally { - if (connection != null) { - MySQLHelper.closeConnection(connection); - } - } - } - - static List findRecords(String vocabularyName, List data, boolean exactSearch) throws SQLException { - String likeStr = "like"; - if (MySQLHelper.getInstance().getSqlType() == SQLTYPE.H2) { - likeStr = "ilike"; - } - - StringBuilder sb = new StringBuilder(); - sb.append("SELECT r.* FROM vocabulary_record_data r LEFT JOIN vocabulary v ON v.id = r.vocabulary_id WHERE v.title = ? "); - - StringBuilder subQuery = new StringBuilder(); - for (StringPair sp : data) { - if (StringUtils.isNotBlank(sp.getTwo())) { - if (subQuery.length() > 0) { - subQuery.append(" OR "); - } - subQuery.append("(value "); - subQuery.append(likeStr); - subQuery.append(" '"); - if (!exactSearch) { - subQuery.append("%"); - } - subQuery.append(MySQLHelper.escapeSql(sp.getTwo().replace("\"", "_"))); - if (!exactSearch) { - subQuery.append("%"); - } - subQuery.append("' AND "); - subQuery.append("label ='" + MySQLHelper.escapeSql(sp.getOne()) + "') "); - } - } - if (subQuery.length() > 0) { - sb.append(" AND r.record_id in (select distinct record_id from vocabulary_record_data where "); - sb.append(subQuery.toString()); - sb.append(")"); - } - Connection connection = null; - try { - connection = MySQLHelper.getInstance().getConnection(); - StatementConfiguration stmtConfig = - new StatementConfiguration.Builder().maxRows(MAXIMAL_QUERY_RESULTS).queryTimeout(QUERY_TIMEOUT_IN_SECONDS).build(); - QueryRunner queryRunner = new QueryRunner(stmtConfig); - List records = queryRunner.query(connection, sb.toString(), VocabularyManager.vocabularyRecordListHandler, vocabularyName); - Vocabulary vocabulary = getVocabularyByTitle(vocabularyName); - for (VocabRecord rec : records) { - setDefinitionsToRecord(rec, vocabulary); - } - return records; - - } finally { - if (connection != null) { - MySQLHelper.closeConnection(connection); - } - } - } - - public static void insertNewRecords(List records, Integer vocabularyID) throws SQLException { - StringBuilder insertRecordQuery = new StringBuilder(); - insertRecordQuery.append("INSERT INTO vocabulary_record (id, vocabulary_id) VALUES "); - - for (int i = 0; i < records.size(); i++) { - - if (i == 0) { - insertRecordQuery.append(" (?, ?)"); - } else { - insertRecordQuery.append(", (?, ?)"); - } - } - Connection connection = null; - QueryRunner runner = new QueryRunner(); - try { - connection = MySQLHelper.getInstance().getConnection(); - try { - if (MySQLHelper.getInstance().getSqlType() != SQLTYPE.H2) { - runner.execute(connection, "Lock tables vocabulary_record write"); - } - int id = runner.query(connection, "SELECT MAX(id) +1 FROM vocabulary_record", MySQLHelper.resultSetToIntegerHandler); - Object[] parameter = new Object[records.size() * 2]; - for (int i = 0; i < records.size(); i++) { - VocabRecord rec = records.get(i); - rec.setId(id); - parameter[i * 2] = id; - parameter[i * 2 + 1] = vocabularyID; - id = id + 1; - } - runner.execute(connection, insertRecordQuery.toString(), parameter); - } finally { - if (MySQLHelper.getInstance().getSqlType() != SQLTYPE.H2) { - runner.execute(connection, "unlock tables"); - } - } - fieldsBatchInsertion(records, vocabularyID, connection, runner); - } finally { - if (connection != null) { - MySQLHelper.closeConnection(connection); - } - } - - } - - private static void fieldsBatchInsertion(List records, Integer vocabularyID, Connection connection, QueryRunner runner) - throws SQLException { - // create a single query for all fields - String fieldQuery = "INSERT INTO vocabulary_record_data (record_id,vocabulary_id, definition_id, label, language, value) VALUES "; - int totalNumberOfRecords = records.size(); - int currentBatchNo = 0; - int numberOfRecordsPerBatch = 50; - while (totalNumberOfRecords > (currentBatchNo * numberOfRecordsPerBatch)) { - List subList; - if (totalNumberOfRecords > (currentBatchNo * numberOfRecordsPerBatch) + numberOfRecordsPerBatch) { - subList = records.subList(currentBatchNo * numberOfRecordsPerBatch, - (currentBatchNo * numberOfRecordsPerBatch) + numberOfRecordsPerBatch); - } else { - subList = records.subList(currentBatchNo * numberOfRecordsPerBatch, totalNumberOfRecords); - } - - List parameter = new ArrayList<>(); - - StringBuilder insertFieldQuery = new StringBuilder(); - insertFieldQuery.append(fieldQuery); - boolean isFirst = true; - for (int i = 0; i < subList.size(); i++) { - VocabRecord rec = subList.get(i); - for (int j = 0; j < rec.getFields().size(); j++) { - if (isFirst) { - isFirst = false; - insertFieldQuery.append("(?,?,?,?,?,?) "); - } else { - insertFieldQuery.append(", (?,?,?,?,?,?) "); - } - Field f = rec.getFields().get(j); - parameter.add(rec.getId()); - parameter.add(vocabularyID); - parameter.add(f.getDefinition().getId()); - parameter.add(f.getLabel()); - parameter.add(f.getLanguage()); - parameter.add(MySQLHelper.escapeSql(f.getValue())); - } - } - runner.execute(connection, insertFieldQuery.toString(), parameter.toArray()); - currentBatchNo = currentBatchNo + 1; - } - } - - // private static void fieldsBatchInsertion(List records, Integer vocabularyID, Connection connection, QueryRunner runner) - // throws SQLException { - // // create a single query for all fields - // int totalNumberOfRecords = records.size(); - // int currentBatchNo = 0; - // int numberOfRecordsPerBatch = 200; - // connection.setAutoCommit(false); - // PreparedStatement pstmt = connection.prepareStatement( - // "INSERT INTO vocabulary_record_data (record_id,vocabulary_id, definition_id, label, language, value) VALUES (?,?,?,?,?,?)"); - // while (totalNumberOfRecords > (currentBatchNo * numberOfRecordsPerBatch)) { - // List subList; - // if (totalNumberOfRecords > (currentBatchNo * numberOfRecordsPerBatch) + numberOfRecordsPerBatch) { - // subList = records.subList(currentBatchNo * numberOfRecordsPerBatch, - // (currentBatchNo * numberOfRecordsPerBatch) + numberOfRecordsPerBatch); - // } else { - // subList = records.subList(currentBatchNo * numberOfRecordsPerBatch, totalNumberOfRecords); - // } - // - // - // pstmt.clearParameters(); - // pstmt.clearBatch(); - // for (int i = 0; i < subList.size(); i++) { - // VocabRecord rec = subList.get(i); - // for (int j = 0; j < rec.getFields().size(); j++) { - // - // Field f = rec.getFields().get(j); - // pstmt.setInt(1, rec.getId()); - // pstmt.setInt(2, vocabularyID); - // pstmt.setInt(3, f.getDefinition().getId()); - // pstmt.setString(4, f.getLabel()); - // pstmt.setString(5, f.getLanguage()); - // pstmt.setString(6, MySQLHelper.escapeSql(f.getValue())); - // // Add row to the batch. - // pstmt.addBatch(); - // } - // } - // pstmt.executeBatch(); - // currentBatchNo = currentBatchNo + 1; - // } - // connection.commit(); - // } - - public static void batchUpdateRecords(List records, Integer vocabularyID) throws SQLException { - // 1.) delete old fields - StringBuilder sql = new StringBuilder(); - sql.append("DELETE from vocabulary_record_data WHERE record_id IN ("); - - StringBuilder ids = new StringBuilder(); - - for (VocabRecord rec : records) { - if (ids.length() > 0) { - ids.append(", "); - } - ids.append(rec.getId()); - } - sql.append(ids.toString()); - sql.append(")"); - - Connection connection = null; - try { - QueryRunner runner = new QueryRunner(); - connection = MySQLHelper.getInstance().getConnection(); - runner.execute(connection, sql.toString()); - // 2.) insert new fields - fieldsBatchInsertion(records, vocabularyID, connection, runner); - } finally { - if (connection != null) { - MySQLHelper.closeConnection(connection); - } - } - - } - - public static Timestamp getVocabularyLastAltered(Vocabulary vocabulary) throws SQLException { - - if (vocabulary == null) { - return null; - } - String sql = "SELECT * FROM vocabulary WHERE id = ? "; - Connection connection = null; - try { - connection = MySQLHelper.getInstance().getConnection(); - - return new QueryRunner().query(connection, sql, VocabularyManager.resultSetGetLastAlteredHandler, vocabulary.getId()); - - } finally { - if (connection != null) { - MySQLHelper.closeConnection(connection); - } - } - } - - public static void setVocabularyLastAltered(Vocabulary vocabulary) throws SQLException { - - if (vocabulary == null) { - return; - } - - String updateSql = "UPDATE vocabulary SET lastAltered = ? WHERE id = ?"; - Connection connection = null; - - try { - Calendar calendar = Calendar.getInstance(); - Timestamp timeNow = new Timestamp(calendar.getTime().getTime()); - connection = MySQLHelper.getInstance().getConnection(); - - new QueryRunner().update(connection, updateSql, timeNow, vocabulary.getId()); - - } finally { - if (connection != null) { - MySQLHelper.closeConnection(connection); - } - } - - } - - public static Timestamp getVocabularyLastUploaded(Vocabulary vocabulary) throws SQLException { - if (vocabulary == null) { - return null; - } - String sql = "SELECT * FROM " + vocabTable + " WHERE id = ? "; - Connection connection = null; - try { - connection = MySQLHelper.getInstance().getConnection(); - - return new QueryRunner().query(connection, sql, VocabularyManager.resultSetGetLastUploadedHandler, vocabulary.getId()); - - } finally { - if (connection != null) { - MySQLHelper.closeConnection(connection); - } - } - } - - public static void setVocabularyLastUploaded(Vocabulary vocabulary) throws SQLException { - - if (vocabulary == null) { - return; - } - - String updateSql = "UPDATE vocabulary SET lastUploaded = ? WHERE id = ?"; - Connection connection = null; - - try { - Calendar calendar = Calendar.getInstance(); - Timestamp timeNow = new Timestamp(calendar.getTime().getTime()); - connection = MySQLHelper.getInstance().getConnection(); - - new QueryRunner().update(connection, updateSql, timeNow, vocabulary.getId()); - - } finally { - if (connection != null) { - MySQLHelper.closeConnection(connection); - } - } - } - - public static Map getRecordMap(int vocabularyId, int definitionId) throws SQLException { - - StringBuilder sql = new StringBuilder(); - sql.append("SELECT r2.value as identifier, r1.* FROM vocabulary_record_data r1 "); - sql.append("left join vocabulary_record_data r2 on r1.record_id = r2.record_id and r2.definition_id = ? "); - sql.append("WHERE r1.vocabulary_id = ? "); - - Connection connection = null; - try { - connection = MySQLHelper.getInstance().getConnection(); - return new QueryRunner().query(connection, sql.toString(), VocabularyManager.vocabularyRecordMapHandler, definitionId, vocabularyId); - - } finally { - if (connection != null) { - MySQLHelper.closeConnection(connection); - } - } - } -} diff --git a/src/main/java/io/goobi/workflow/api/vocabulary/APIException.java b/src/main/java/io/goobi/workflow/api/vocabulary/APIException.java new file mode 100644 index 0000000000..84d3b846ac --- /dev/null +++ b/src/main/java/io/goobi/workflow/api/vocabulary/APIException.java @@ -0,0 +1,24 @@ +package io.goobi.workflow.api.vocabulary; + +import io.goobi.vocabulary.exception.VocabularyException; +import lombok.Getter; + +@Getter +public class APIException extends RuntimeException { + private final String url; + private final String method; + private final int statusCode; + private final String reason; + private final VocabularyException vocabularyCause; + private final Exception cause; + + public APIException(String url, String method, int statusCode, String reason, VocabularyException vocabularyCause, Exception cause) { + super("API call was not successful" + (statusCode >= 0 ? " with status code [" + statusCode + "]" : "") + ": " + method + " -> " + url + ", Reason:\n" + reason); + this.url = url; + this.method = method; + this.statusCode = statusCode; + this.reason = reason; + this.vocabularyCause = vocabularyCause; + this.cause = cause; + } +} diff --git a/src/main/java/io/goobi/workflow/api/vocabulary/CRUDAPI.java b/src/main/java/io/goobi/workflow/api/vocabulary/CRUDAPI.java new file mode 100644 index 0000000000..8b1649c344 --- /dev/null +++ b/src/main/java/io/goobi/workflow/api/vocabulary/CRUDAPI.java @@ -0,0 +1,58 @@ +package io.goobi.workflow.api.vocabulary; + +import io.goobi.vocabulary.exchange.Identifiable; + +import java.util.Optional; + +public abstract class CRUDAPI { + protected final RESTAPI restApi; + private final Class instanceTypeClass; + private final Class pageResultTypeClass; + private final String commonEndpoint; + private final String instanceEndpoint; + + protected CRUDAPI(String host, int port, Class instanceTypeClass, Class pageResultTypeClass, String commonEndpoint, String instanceEndpoint) { + this.restApi = new RESTAPI(host, port); + this.instanceTypeClass = instanceTypeClass; + this.pageResultTypeClass = pageResultTypeClass; + this.commonEndpoint = commonEndpoint; + this.instanceEndpoint = instanceEndpoint; + } + + public PageResultType list() { + return restApi.get(commonEndpoint, pageResultTypeClass); + } + + public PageResultType list(Optional size, Optional page) { + String params = ""; + if (size.isPresent()) { + params += params.isEmpty() ? "?" : "&"; + params += "size=" + size.get(); + } + if (page.isPresent()) { + params += params.isEmpty() ? "?" : "&"; + params += "page=" + page.get(); + } + return restApi.get(commonEndpoint + params, pageResultTypeClass); + } + + public InstanceType get(long id) { + return restApi.get(instanceEndpoint, instanceTypeClass, id); + } + + public InstanceType create(InstanceType obj) { + return restApi.post(commonEndpoint, instanceTypeClass, obj); + } + + public InstanceType change(InstanceType obj) { + long id = obj.getId(); + obj.setId(null); + InstanceType newObj = restApi.put(instanceEndpoint, instanceTypeClass, obj, id); + obj.setId(id); + return newObj; + } + + public void delete(InstanceType obj) { + restApi.delete(instanceEndpoint, instanceTypeClass, obj.getId()); + } +} diff --git a/src/main/java/io/goobi/workflow/api/vocabulary/FieldTypeAPI.java b/src/main/java/io/goobi/workflow/api/vocabulary/FieldTypeAPI.java new file mode 100644 index 0000000000..bdddc058e3 --- /dev/null +++ b/src/main/java/io/goobi/workflow/api/vocabulary/FieldTypeAPI.java @@ -0,0 +1,22 @@ +package io.goobi.workflow.api.vocabulary; + +import io.goobi.vocabulary.exchange.FieldType; +import io.goobi.workflow.api.vocabulary.hateoas.FieldTypePageResult; +import io.goobi.workflow.api.vocabulary.helper.CachedLookup; + +public class FieldTypeAPI extends CRUDAPI { + private static final String COMMON_ENDPOINT = "/api/v1/types"; + private static final String INSTANCE_ENDPOINT = COMMON_ENDPOINT + "/{{0}}"; + + private final CachedLookup singleLookupCache; + + public FieldTypeAPI(String host, int port) { + super(host, port, FieldType.class, FieldTypePageResult.class, COMMON_ENDPOINT, INSTANCE_ENDPOINT); + this.singleLookupCache = new CachedLookup<>(super::get); + } + + @Override + public FieldType get(long id) { + return this.singleLookupCache.getCached(id); + } +} diff --git a/src/main/java/io/goobi/workflow/api/vocabulary/LanguageAPI.java b/src/main/java/io/goobi/workflow/api/vocabulary/LanguageAPI.java new file mode 100644 index 0000000000..3350a0e1a3 --- /dev/null +++ b/src/main/java/io/goobi/workflow/api/vocabulary/LanguageAPI.java @@ -0,0 +1,22 @@ +package io.goobi.workflow.api.vocabulary; + +import io.goobi.vocabulary.exchange.Language; +import io.goobi.workflow.api.vocabulary.hateoas.LanguagePageResult; +import io.goobi.workflow.api.vocabulary.helper.CachedLookup; + +public class LanguageAPI extends CRUDAPI { + private static final String COMMON_ENDPOINT = "/api/v1/languages"; + private static final String FIND_INSTANCE_ENDPOINT = "/api/v1/languages/by-abbreviation/{{0}}"; + private static final String INSTANCE_ENDPOINT = COMMON_ENDPOINT + "/{{0}}"; + + private final CachedLookup singleLookupCache; + + public LanguageAPI(String host, int port) { + super(host, port, Language.class, LanguagePageResult.class, COMMON_ENDPOINT, INSTANCE_ENDPOINT); + this.singleLookupCache = new CachedLookup<>(abbreviation -> restApi.get(FIND_INSTANCE_ENDPOINT, Language.class, abbreviation)); + } + + public Language findByAbbreviation(String abbreviation) { + return this.singleLookupCache.getCached(abbreviation); + } +} diff --git a/src/main/java/io/goobi/workflow/api/vocabulary/RESTAPI.java b/src/main/java/io/goobi/workflow/api/vocabulary/RESTAPI.java new file mode 100644 index 0000000000..2283c71bc6 --- /dev/null +++ b/src/main/java/io/goobi/workflow/api/vocabulary/RESTAPI.java @@ -0,0 +1,167 @@ +package io.goobi.workflow.api.vocabulary; + +import io.goobi.vocabulary.exception.VocabularyException; +import lombok.Setter; +import org.glassfish.jersey.media.multipart.FormDataMultiPart; +import org.glassfish.jersey.media.multipart.MultiPart; +import org.glassfish.jersey.media.multipart.MultiPartFeature; +import org.glassfish.jersey.media.multipart.file.FileDataBodyPart; +import org.glassfish.jersey.media.multipart.file.StreamDataBodyPart; + +import javax.servlet.http.Part; +import javax.ws.rs.client.Client; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.client.Entity; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class RESTAPI { + @Setter + private static Client client = ClientBuilder.newBuilder() + .register(MultiPartFeature.class) + .register(FileDataBodyPart.class) + .build(); + private String baseUrl; + + protected RESTAPI(String host, int port) { + baseUrl = "http://" + host + ":" + port; + } + + private String generateUrl(String endpoint, Object... parameters) { + String url = endpoint; + if (!url.startsWith(baseUrl)) { + url = baseUrl + url; + } + List queryParams = new ArrayList<>(); + for (int i = 0; i < parameters.length; i++) { + if (url.contains("{{" + i + "}}")) { + url = url.replace("{{" + i + "}}", parameters[i].toString()); + } else { + queryParams.add(parameters[i].toString()); + } + } + if (!queryParams.isEmpty()) { + url = url + "?" + String.join("&", queryParams); + } + return url; + } + + public T get(String endpoint, Class clazz, Object... parameters) { + try { + try (Response response = client + .target(generateUrl(endpoint, parameters)) + .request(MediaType.APPLICATION_JSON) + .get()) { + if (response.getStatus() / 100 != 2) { + throw new APIException(generateUrl(endpoint, parameters), "GET", response.getStatus(), "Vocabulary server error", response.readEntity(VocabularyException.class), null); + } + return response.readEntity(clazz); + } + } catch (APIException e) { + throw e; + } catch (RuntimeException e) { + throw new APIException(generateUrl(endpoint, parameters), "GET", -1, e.getMessage(), null, e); + } + } + + public T post(String endpoint, Class clazz, T obj, Object... parameters) { + try { + try (Response response = client + .target(generateUrl(endpoint, parameters)) + .request(MediaType.APPLICATION_JSON) + .post(Entity.json(obj))) { + if (response.getStatus() / 100 != 2) { + throw new APIException(generateUrl(endpoint, parameters), "POST", response.getStatus(), "Vocabulary server error", response.readEntity(VocabularyException.class), null); + } + return response.readEntity(clazz); + } + } catch (APIException e) { + throw e; + } catch (RuntimeException e) { + throw new APIException(generateUrl(endpoint, parameters), "POST", -1, e.getMessage(), null, e); + } + } + + public T put(String endpoint, Class clazz, T obj, Object... parameters) { + try { + try (Response response = client + .target(generateUrl(endpoint, parameters)) + .request(MediaType.APPLICATION_JSON) + .put(Entity.json(obj))) { + if (response.getStatus() / 100 != 2) { + throw new APIException(generateUrl(endpoint, parameters), "PUT", response.getStatus(), "Vocabulary server error", response.readEntity(VocabularyException.class), null); + } + return response.readEntity(clazz); + } + } catch (APIException e) { + throw e; + } catch (RuntimeException e) { + throw new APIException(generateUrl(endpoint, parameters), "PUT", -1, e.getMessage(), null, e); + } + } + + public Response put(String endpoint, Part part, Object... parameters) { + try { + StreamDataBodyPart body = new StreamDataBodyPart("file", part.getInputStream()); + try (MultiPart multiPart = new FormDataMultiPart()) { + multiPart.bodyPart(body); + try (Response response = client + .target(generateUrl(endpoint, parameters)) + .request(MediaType.MULTIPART_FORM_DATA) + .put(Entity.entity(multiPart, multiPart.getMediaType()), Response.class)) { + if (response.getStatus() / 100 != 2) { + throw new APIException(generateUrl(endpoint, parameters), "PUT", response.getStatus(), "Vocabulary server error", response.readEntity(VocabularyException.class), null); + } + return response.readEntity(Response.class); + } + } + } catch (APIException e) { + throw e; + } catch (RuntimeException | IOException e) { + throw new APIException(generateUrl(endpoint, parameters), "PUT", -1, e.getMessage(), null, e); + } + } + + public Response post(String endpoint, Part part, Object... parameters) { + try { + StreamDataBodyPart body = new StreamDataBodyPart("file", part.getInputStream()); + try (MultiPart multiPart = new FormDataMultiPart()) { + multiPart.bodyPart(body); + try (Response response = client + .target(generateUrl(endpoint, parameters)) + .request(MediaType.MULTIPART_FORM_DATA) + .post(Entity.entity(multiPart, multiPart.getMediaType()), Response.class)) { + if (response.getStatus() / 100 != 2) { + throw new APIException(generateUrl(endpoint, parameters), "POST", response.getStatus(), "Vocabulary server error", response.readEntity(VocabularyException.class), null); + } + return response.readEntity(Response.class); + } + } + } catch (APIException e) { + throw e; + } catch (RuntimeException | IOException e) { + throw new APIException(generateUrl(endpoint, parameters), "POST", -1, e.getMessage(), null, e); + } + } + + public T delete(String endpoint, Class clazz, Object... parameters) { + try { + try (Response response = client + .target(generateUrl(endpoint, parameters)) + .request(MediaType.APPLICATION_JSON) + .delete()) { + if (response.getStatus() / 100 != 2) { + throw new APIException(generateUrl(endpoint, parameters), "DELETE", response.getStatus(), "Vocabulary server error", response.readEntity(VocabularyException.class), null); + } + return response.readEntity(clazz); + } + } catch (APIException e) { + throw e; + } catch (RuntimeException e) { + throw new APIException(generateUrl(endpoint, parameters), "DELETE", -1, e.getMessage(), null, e); + } + } +} diff --git a/src/main/java/io/goobi/workflow/api/vocabulary/VocabularyAPI.java b/src/main/java/io/goobi/workflow/api/vocabulary/VocabularyAPI.java new file mode 100644 index 0000000000..7fdeee933f --- /dev/null +++ b/src/main/java/io/goobi/workflow/api/vocabulary/VocabularyAPI.java @@ -0,0 +1,66 @@ +package io.goobi.workflow.api.vocabulary; + +import io.goobi.vocabulary.exchange.Vocabulary; +import io.goobi.workflow.api.vocabulary.hateoas.VocabularyPageResult; +import io.goobi.workflow.api.vocabulary.helper.CachedLookup; +import io.goobi.workflow.api.vocabulary.helper.ExtendedVocabulary; + +import javax.servlet.http.Part; +import java.util.List; + +public class VocabularyAPI extends CRUDAPI { + private static final String COMMON_ENDPOINT = "/api/v1/vocabularies"; + private static final String FIND_INSTANCE_ENDPOINT = "/api/v1/vocabularies/by-name/{{0}}"; + private static final String IMPORT_CSV_ENDPOINT = "/api/v1/vocabularies/{{0}}/import/csv"; + private static final String IMPORT_EXCEL_ENDPOINT = "/api/v1/vocabularies/{{0}}/import/excel"; + private static final String INSTANCE_ENDPOINT = COMMON_ENDPOINT + "/{{0}}"; + + private final CachedLookup singleLookupCache; + + public VocabularyAPI(String host, int port) { + super(host, port, Vocabulary.class, VocabularyPageResult.class, COMMON_ENDPOINT, INSTANCE_ENDPOINT); + this.singleLookupCache = new CachedLookup<>(id -> new ExtendedVocabulary(super.get(id))); + } + + @Override + public ExtendedVocabulary get(long id) { + return this.singleLookupCache.getCached(id); + } + + public List all() { + return restApi.get(COMMON_ENDPOINT, VocabularyPageResult.class, "all=1").getContent(); + } + + @Override + public ExtendedVocabulary change(Vocabulary vocabulary) { + ExtendedVocabulary result = new ExtendedVocabulary(super.change(vocabulary)); + this.singleLookupCache.update(vocabulary.getId(), result); + return result; + } + + @Override + public void delete(Vocabulary vocabulary) { + super.delete(vocabulary); + this.singleLookupCache.invalidate(vocabulary.getId()); + } + + public ExtendedVocabulary findByName(String name) { + return new ExtendedVocabulary(restApi.get(FIND_INSTANCE_ENDPOINT, Vocabulary.class, name)); + } + + public void cleanImportCsv(long id, Part uploadedFile) { + restApi.put(IMPORT_CSV_ENDPOINT, uploadedFile, id); + } + + public void importCsv(long id, Part uploadedFile) { + restApi.post(IMPORT_CSV_ENDPOINT, uploadedFile, id); + } + + public void cleanImportExcel(long id, Part uploadedFile) { + restApi.put(IMPORT_EXCEL_ENDPOINT, uploadedFile, id); + } + + public void importExcel(long id, Part uploadedFile) { + restApi.post(IMPORT_EXCEL_ENDPOINT, uploadedFile, id); + } +} diff --git a/src/main/java/io/goobi/workflow/api/vocabulary/VocabularyAPIManager.java b/src/main/java/io/goobi/workflow/api/vocabulary/VocabularyAPIManager.java new file mode 100644 index 0000000000..e738ab690c --- /dev/null +++ b/src/main/java/io/goobi/workflow/api/vocabulary/VocabularyAPIManager.java @@ -0,0 +1,50 @@ +package io.goobi.workflow.api.vocabulary; + +import de.sub.goobi.config.ConfigurationHelper; + +public class VocabularyAPIManager { + private static VocabularyAPIManager instance; + + private FieldTypeAPI fieldTypeAPI; + private LanguageAPI languageAPI; + private VocabularySchemaAPI vocabularySchemaAPI; + private VocabularyAPI vocabularyAPI; + private VocabularyRecordAPI vocabularyRecordAPI; + + private VocabularyAPIManager() { + final String host = ConfigurationHelper.getInstance().getVocabularyServerHost(); + final int port = ConfigurationHelper.getInstance().getVocabularyServerPort(); + this.fieldTypeAPI = new FieldTypeAPI(host, port); + this.languageAPI = new LanguageAPI(host, port); + this.vocabularySchemaAPI = new VocabularySchemaAPI(host, port); + this.vocabularyAPI = new VocabularyAPI(host, port); + this.vocabularyRecordAPI = new VocabularyRecordAPI(host, port); + } + + public synchronized static VocabularyAPIManager getInstance() { + if (instance == null) { + instance = new VocabularyAPIManager(); + } + return instance; + } + + public FieldTypeAPI fieldTypes() { + return fieldTypeAPI; + } + + public LanguageAPI languages() { + return languageAPI; + } + + public VocabularySchemaAPI vocabularySchemas() { + return vocabularySchemaAPI; + } + + public VocabularyAPI vocabularies() { + return vocabularyAPI; + } + + public VocabularyRecordAPI vocabularyRecords() { + return vocabularyRecordAPI; + } +} diff --git a/src/main/java/io/goobi/workflow/api/vocabulary/VocabularyRecordAPI.java b/src/main/java/io/goobi/workflow/api/vocabulary/VocabularyRecordAPI.java new file mode 100644 index 0000000000..d1c44fe7e8 --- /dev/null +++ b/src/main/java/io/goobi/workflow/api/vocabulary/VocabularyRecordAPI.java @@ -0,0 +1,285 @@ +package io.goobi.workflow.api.vocabulary; + +import io.goobi.vocabulary.exception.VocabularyException; +import io.goobi.vocabulary.exchange.FieldInstance; +import io.goobi.vocabulary.exchange.FieldValue; +import io.goobi.vocabulary.exchange.TranslationInstance; +import io.goobi.vocabulary.exchange.VocabularyRecord; +import io.goobi.workflow.api.vocabulary.hateoas.VocabularyRecordPageResult; +import io.goobi.workflow.api.vocabulary.helper.CachedLookup; +import io.goobi.workflow.api.vocabulary.helper.ExtendedVocabulary; +import io.goobi.workflow.api.vocabulary.helper.ExtendedVocabularyRecord; +import lombok.extern.log4j.Log4j2; + +import javax.faces.model.SelectItem; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +@Log4j2 +public class VocabularyRecordAPI { + private static final String IN_VOCABULARY_RECORDS_ENDPOINT = "/api/v1/vocabularies/{{0}}/records"; + private static final String METADATA_ENDPOINT = "/api/v1/vocabularies/{{0}}/metadata"; + private static final String INSTANCE_ENDPOINT = "/api/v1/records/{{0}}"; + + private final RESTAPI restApi; + private final CachedLookup singleLookupCache; + + public class VocabularyRecordQueryBuilder { + private final long vocabularyId; + private Optional page = Optional.empty(); + private Optional pageSize = Optional.empty(); + private Optional sorting = Optional.empty(); + private Optional search = Optional.empty(); + private Optional all = Optional.empty(); + + private VocabularyRecordQueryBuilder(long vocabularyId) { + this.vocabularyId = vocabularyId; + } + + public VocabularyRecordQueryBuilder page(int page) { + this.page = Optional.of(page); + return this; + } + + public VocabularyRecordQueryBuilder page(Optional page) { + this.page = page; + return this; + } + + public VocabularyRecordQueryBuilder pageSize(int pageSize) { + this.pageSize = Optional.of(pageSize); + return this; + } + + public VocabularyRecordQueryBuilder pageSize(Optional pageSize) { + this.pageSize = pageSize; + return this; + } + + public VocabularyRecordQueryBuilder sorting(String sorting) { + this.sorting = Optional.of(sorting); + return this; + } + + public VocabularyRecordQueryBuilder sorting(Optional sorting) { + this.sorting = sorting; + return this; + } + + public VocabularyRecordQueryBuilder search(String search) { + this.search = Optional.of(search); + return this; + } + + public VocabularyRecordQueryBuilder search(Optional search) { + this.search = search; + return this; + } + + public VocabularyRecordQueryBuilder all() { + this.all = Optional.of(true); + return this; + } + + public VocabularyRecordPageResult request() { + return list(this.vocabularyId, this.pageSize, this.page, this.sorting, this.search, this.all); + } + } + + public VocabularyRecordAPI(String host, int port) { + this.restApi = new RESTAPI(host, port); + this.singleLookupCache = new CachedLookup<>(id -> { + VocabularyRecord r = restApi.get(INSTANCE_ENDPOINT, VocabularyRecord.class, id); + VocabularyAPIManager.getInstance().vocabularySchemas().load(r.getVocabularyId()); + return new ExtendedVocabularyRecord(r); + }); + } + + public VocabularyRecordQueryBuilder list(long vocabularyId) { + return new VocabularyRecordQueryBuilder(vocabularyId); + } + + private VocabularyRecordPageResult list(long vocabularyId, Optional size, Optional page, Optional sorting, Optional search, Optional all) { + String params = ""; + if (size.isPresent()) { + params += params.isEmpty() ? "?" : "&"; + params += "size=" + size.get(); + } + if (page.isPresent()) { + params += params.isEmpty() ? "?" : "&"; + params += "page=" + page.get(); + } + if (sorting.isPresent()) { + params += params.isEmpty() ? "?" : "&"; + params += "sort=" + sorting.get(); + } + if (search.isPresent()) { + params += params.isEmpty() ? "?" : "&"; + params += "search=" + search.get(); + } + if (all.isPresent() && Boolean.TRUE.equals(all.get())) { + params += params.isEmpty() ? "?" : "&"; + params += "all=1"; + } + // Load schema to populate definition resolver + VocabularyAPIManager.getInstance().vocabularySchemas().load(vocabularyId); + + VocabularyRecordPageResult result = restApi.get(IN_VOCABULARY_RECORDS_ENDPOINT + params, VocabularyRecordPageResult.class, vocabularyId); + result.getContent().forEach(r -> this.singleLookupCache.update(r.getId(), r)); + return result; + } + + public ExtendedVocabularyRecord get(long id) { + return singleLookupCache.getCached(id); + } + + public ExtendedVocabularyRecord get(String url) { + return new ExtendedVocabularyRecord(restApi.get(url, VocabularyRecord.class)); + } + + public ExtendedVocabularyRecord save(VocabularyRecord vocabularyRecord) { + cleanUpRecord(vocabularyRecord); + if (Boolean.TRUE.equals(vocabularyRecord.getMetadata())) { + return changeMetadata(vocabularyRecord); + } + if (vocabularyRecord.getId() != null) { + return change(vocabularyRecord); + } else { + return create(vocabularyRecord); + } + } + + private ExtendedVocabularyRecord create(VocabularyRecord vocabularyRecord) { + long vocabularyId = vocabularyRecord.getVocabularyId(); + vocabularyRecord.setVocabularyId(null); + ExtendedVocabularyRecord newRecord; + if (vocabularyRecord.getParentId() == null) { + newRecord = new ExtendedVocabularyRecord(restApi.post(IN_VOCABULARY_RECORDS_ENDPOINT, VocabularyRecord.class, vocabularyRecord, vocabularyId)); + } else { + long parentId = vocabularyRecord.getParentId(); + vocabularyRecord.setParentId(null); + newRecord = new ExtendedVocabularyRecord(restApi.post(INSTANCE_ENDPOINT, VocabularyRecord.class, vocabularyRecord, parentId)); + vocabularyRecord.setParentId(parentId); + this.singleLookupCache.invalidate(vocabularyRecord.getParentId()); + } + vocabularyRecord.setId(vocabularyId); + this.singleLookupCache.update(newRecord.getId(), newRecord); + return newRecord; + } + + private ExtendedVocabularyRecord change(VocabularyRecord vocabularyRecord) { + long id = vocabularyRecord.getId(); + vocabularyRecord.setId(null); + ExtendedVocabularyRecord newRecord = new ExtendedVocabularyRecord(restApi.put(INSTANCE_ENDPOINT, VocabularyRecord.class, vocabularyRecord, id)); + vocabularyRecord.setId(id); + this.singleLookupCache.update(newRecord.getId(), newRecord); + return newRecord; + } + + public void delete(VocabularyRecord vocabularyRecord) { + restApi.delete(INSTANCE_ENDPOINT, VocabularyRecord.class, vocabularyRecord.getId()); + this.singleLookupCache.invalidate(vocabularyRecord.getId()); + if (vocabularyRecord.getParentId() != null) { + this.singleLookupCache.invalidate(vocabularyRecord.getParentId()); + } + } + + public ExtendedVocabularyRecord getMetadata(Long id) { + // TODO: Make this more elegant + try { + return new ExtendedVocabularyRecord(restApi.get(METADATA_ENDPOINT, VocabularyRecord.class, id)); + } catch (APIException e) { + // Throw all exceptions that are not missing metadata, ignore missing metadata and just continue with empty record creation + if (e.getVocabularyCause() == null || e.getVocabularyCause().getErrorType() != VocabularyException.ErrorCode.EntityNotFound) { + throw e; + } + } + ExtendedVocabulary vocabulary = VocabularyAPIManager.getInstance().vocabularies().get(id); + return createEmptyRecord(vocabulary.getId(), null, true); + } + + private ExtendedVocabularyRecord changeMetadata(VocabularyRecord metadataRecord) { + if (!Boolean.TRUE.equals(metadataRecord.getMetadata())) { + throw new IllegalArgumentException("Cannot perform changeMetadata on normal record"); + } + Long id = metadataRecord.getId(); + long vocabularyId = metadataRecord.getVocabularyId(); + metadataRecord.setId(null); + metadataRecord.setVocabularyId(null); + metadataRecord.setMetadata(null); + ExtendedVocabularyRecord newRecord; + if (id == null) { + newRecord = new ExtendedVocabularyRecord(restApi.post(METADATA_ENDPOINT, VocabularyRecord.class, metadataRecord, vocabularyId)); + } else { + newRecord = new ExtendedVocabularyRecord(restApi.put(METADATA_ENDPOINT, VocabularyRecord.class, metadataRecord, vocabularyId)); + } + metadataRecord.setId(id); + metadataRecord.setVocabularyId(vocabularyId); + metadataRecord.setMetadata(true); + return newRecord; + } + + public ExtendedVocabularyRecord createEmptyRecord(long vocabularyId, Long parentId, boolean metadata) { + VocabularyRecord record = new VocabularyRecord(); + record.setVocabularyId(vocabularyId); + record.setParentId(parentId); + record.setMetadata(metadata); + record.setFields(new HashSet<>()); + return new ExtendedVocabularyRecord(record); + } + + private void cleanUpRecord(VocabularyRecord currentRecord) { + for (FieldInstance field : currentRecord.getFields()) { + for (FieldValue value : field.getValues()) { + value.getTranslations().removeIf(this::translationIsEmpty); + } + field.getValues().removeIf(this::valueIsEmpty); + } + currentRecord.getFields().removeIf(this::fieldIsEmpty); + } + + private boolean translationIsEmpty(TranslationInstance translationInstance) { + return translationInstance.getValue().isEmpty(); + } + + private boolean valueIsEmpty(FieldValue fieldValue) { + return fieldValue.getTranslations().isEmpty(); + } + + private boolean fieldIsEmpty(FieldInstance fieldInstance) { + return fieldInstance.getValues().isEmpty(); + } + + public List getRecordMainValues(long vocabularyId) { + return getRecordMainValues(list(vocabularyId)); + } + + public List getRecordMainValues(VocabularyRecordQueryBuilder query) { + return query + .all() + .request() + .getContent() + .stream() + .map(ExtendedVocabularyRecord::getMainValue) + .sorted() + .collect(Collectors.toList()); + } + + public List getRecordSelectItems(long vocabularyId) { + return getRecordSelectItems(list(vocabularyId)); + } + + public List getRecordSelectItems(VocabularyRecordQueryBuilder query) { + return query + .all() + .request() + .getContent() + .stream() + .map(r -> new SelectItem(String.valueOf(r.getId()), r.getMainValue())) + .sorted(Comparator.comparing(SelectItem::getLabel)) + .collect(Collectors.toList()); + } +} diff --git a/src/main/java/io/goobi/workflow/api/vocabulary/VocabularySchemaAPI.java b/src/main/java/io/goobi/workflow/api/vocabulary/VocabularySchemaAPI.java new file mode 100644 index 0000000000..a3693f9031 --- /dev/null +++ b/src/main/java/io/goobi/workflow/api/vocabulary/VocabularySchemaAPI.java @@ -0,0 +1,64 @@ +package io.goobi.workflow.api.vocabulary; + +import io.goobi.vocabulary.exchange.FieldDefinition; +import io.goobi.vocabulary.exchange.Vocabulary; +import io.goobi.vocabulary.exchange.VocabularyRecord; +import io.goobi.vocabulary.exchange.VocabularySchema; +import io.goobi.workflow.api.vocabulary.hateoas.VocabularySchemaPageResult; +import io.goobi.workflow.api.vocabulary.helper.CachedLookup; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +public class VocabularySchemaAPI extends CRUDAPI { + private static final String COMMON_ENDPOINT = "/api/v1/schemas"; + private static final String INSTANCE_ENDPOINT = COMMON_ENDPOINT + "/{{0}}"; + + // TODO: Make this generic + private Map definitionMap = new HashMap<>(); + private final CachedLookup singleLookupCache; + + public VocabularySchemaAPI(String host, int port) { + super(host, port, VocabularySchema.class, VocabularySchemaPageResult.class, COMMON_ENDPOINT, INSTANCE_ENDPOINT); + this.singleLookupCache = new CachedLookup<>(this::request); + } + + @Override + public VocabularySchema get(long id) { + return this.singleLookupCache.getCached(id); + } + + private VocabularySchema request(long id) { + VocabularySchema schema = super.get(id); + schema.getDefinitions().forEach(d -> definitionMap.put(d.getId(), d)); + return schema; + } + + public FieldDefinition getDefinition(Long definitionId) { + return this.definitionMap.get(definitionId); + } + + public VocabularySchema getSchema(VocabularyRecord vocabularyRecord) { + return getSchema(VocabularyAPIManager.getInstance().vocabularies().get(vocabularyRecord.getVocabularyId())); + } + + public VocabularySchema getSchema(Vocabulary vocabulary) { + return get(vocabulary.getSchemaId()); + } + + public Optional getMetadataSchema(VocabularyRecord vocabularyRecord) { + return getMetadataSchema(VocabularyAPIManager.getInstance().vocabularies().get(vocabularyRecord.getVocabularyId())); + } + + public Optional getMetadataSchema(Vocabulary vocabulary) { + if (vocabulary.getMetadataSchemaId() == null) { + return Optional.empty(); + } + return Optional.of(get(vocabulary.getMetadataSchemaId())); + } + + public void load(long vocabularyId) { + getSchema(VocabularyAPIManager.getInstance().vocabularies().get(vocabularyId)); + } +} diff --git a/src/main/java/io/goobi/workflow/api/vocabulary/hateoas/BasePageResult.java b/src/main/java/io/goobi/workflow/api/vocabulary/hateoas/BasePageResult.java new file mode 100644 index 0000000000..7b9dc4e413 --- /dev/null +++ b/src/main/java/io/goobi/workflow/api/vocabulary/hateoas/BasePageResult.java @@ -0,0 +1,14 @@ +package io.goobi.workflow.api.vocabulary.hateoas; + +import io.goobi.vocabulary.exchange.HateoasHref; +import lombok.Data; + +import java.util.List; +import java.util.Map; + +@Data +public abstract class BasePageResult { + private Map _links; + private PageInformation page; + public abstract List getContent(); +} diff --git a/src/main/java/io/goobi/workflow/api/vocabulary/hateoas/FieldTypePageResult.java b/src/main/java/io/goobi/workflow/api/vocabulary/hateoas/FieldTypePageResult.java new file mode 100644 index 0000000000..40ef8064cd --- /dev/null +++ b/src/main/java/io/goobi/workflow/api/vocabulary/hateoas/FieldTypePageResult.java @@ -0,0 +1,26 @@ +package io.goobi.workflow.api.vocabulary.hateoas; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import io.goobi.vocabulary.exchange.FieldType; +import lombok.Data; + +import java.util.Collections; +import java.util.List; + +@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class FieldTypePageResult extends BasePageResult { + @Data + private class EmbeddedWrapper { + private List fieldTypeList; + } + + private EmbeddedWrapper _embedded; + + public List getContent() { + if (_embedded == null) { + return Collections.emptyList(); + } + return _embedded.getFieldTypeList(); + } +} diff --git a/src/main/java/io/goobi/workflow/api/vocabulary/hateoas/HATEOASPaginator.java b/src/main/java/io/goobi/workflow/api/vocabulary/hateoas/HATEOASPaginator.java new file mode 100644 index 0000000000..574ce83e30 --- /dev/null +++ b/src/main/java/io/goobi/workflow/api/vocabulary/hateoas/HATEOASPaginator.java @@ -0,0 +1,368 @@ +package io.goobi.workflow.api.vocabulary.hateoas; + +import io.goobi.vocabulary.exception.VocabularyException; +import io.goobi.vocabulary.exchange.Identifiable; +import io.goobi.workflow.api.vocabulary.APIException; +import lombok.Data; +import lombok.Setter; +import org.apache.commons.lang3.NotImplementedException; +import org.goobi.managedbeans.Paginator; + +import javax.ws.rs.client.Client; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class HATEOASPaginator> implements Paginator { + public static final String NAVIGATE_PREVIOUS = "prev"; + public static final String NAVIGATE_NEXT = "next"; + public static final String NAVIGATE_FIRST = "first"; + public static final String NAVIGATE_LAST = "last"; + + @Data + class Node { + private Long id; + private T data; + private List children; + private boolean visible = false; + + public void load() { + if (data != null) { + return; + } + + data = postLoader.apply(getId()); + prepareChildren(); + } + + private void prepareChildren() { + if (getData() != null) { + childrenExtractor.ifPresent(e -> { + Collection extractedChildren = e.apply(getData()); + if (extractedChildren != null) { + setChildren(new LinkedList<>( + extractedChildren.stream().map(c -> { + Node child = new Node(); + child.setId(c); + return child; + }).collect(Collectors.toList()))); + } + }); + } + if (getChildren() == null) { + setChildren(new LinkedList<>()); + } + } + } + + @Setter + private Client client = ClientBuilder.newClient(); + private final Optional>> childrenExtractor; + private final Optional> parentExtractor; + private final Function postLoader; + private Optional searchParameter = Optional.empty(); + private Optional sortField = Optional.empty(); + + private Class pageClass; + private PageT currentPage; + private List tree = new LinkedList<>(); + private Map treeMap = new HashMap<>(); + private List items = new LinkedList<>(); + + public HATEOASPaginator(Class pageClass, PageT initialPage, Function> childrenExtractor, Function parentExtractor, Function postLoader) { + this.pageClass = pageClass; + this.childrenExtractor = Optional.ofNullable(childrenExtractor); + this.parentExtractor = Optional.ofNullable(parentExtractor); + this.postLoader = postLoader; + setCurrentPage(initialPage); + } + + private void setCurrentPage(PageT page) { + this.currentPage = page; + this.tree.clear(); + this.currentPage.getContent().forEach(this::insertElement); + this.tree.forEach(this::recursiveShow); + rebuildTree(); + } + + private void recursiveShow(Node node) { + if (node.getData() == null) { + return; + } + node.setVisible(true); + if (node.getChildren() != null) { + node.getChildren().forEach(this::recursiveShow); + } + } + + private void rebuildTree() { + this.items.clear(); + this.treeMap.clear(); + this.tree.stream() + .filter(Node::isVisible) + .forEachOrdered(this::addToFlatList); + } + + private void addToFlatList(Node node) { + if (node.isVisible() && node.getData() != null) { + this.items.add(node.getData()); + } + this.treeMap.put(node.getId(), node); + if (node.getData() != null) { + node.getChildren().forEach(this::addToFlatList); + } + } + + public void expand(T entry) { + Node node = this.treeMap.get(entry.getId()); + node.getChildren().forEach(child -> { + child.load(); + child.setVisible(true); + }); + rebuildTree(); + } + + public void collapse(T entry) { + Node node = this.treeMap.get(entry.getId()); + this.recursiveCollapseChildren(node); + rebuildTree(); + } + + private void recursiveCollapseChildren(Node node) { + if (node.getChildren() == null) { + return; + } + node.getChildren().forEach(child -> { + child.setVisible(false); + this.recursiveCollapseChildren(child); + }); + } + + private void recursiveParentExpanding(Node node) { + node.load(); + node.setVisible(true); + this.parentExtractor.ifPresent(e -> { + Long parentId = e.apply(node.getData()); + if (parentId == null) { + return; + } + Node parent = getOrCreateParent(parentId); + parent.setVisible(true); + recursiveParentExpanding(parent); + }); + } + + public boolean isExpanded(T entry) { + List children = this.treeMap.get(entry.getId()).getChildren(); + if (children == null) { + return false; + } + return children.stream().anyMatch(Node::isVisible); + } + + public void setSearchParameter(String searchParameter) { + if (searchParameter.isBlank()) { + searchParameter = null; + } + this.searchParameter = Optional.ofNullable(searchParameter); + } + + public String getSearchParameter() { + return searchParameter.orElse(null); + } + + public void setSortField(String sortField) { + if (sortField.isBlank()) { + sortField = null; + } + this.sortField = Optional.ofNullable(sortField); + } + + public String getSortField() { + return sortField.orElse(null); + } + + private void request(String url) { + request(url, Optional.empty(), Optional.empty()); + } + + private void request(String url, Optional pageSize, Optional pageNumber) { + url = updatePageAndSizeUrlParameters(url, pageSize, pageNumber, sortField, searchParameter); + try (Response response = client + .target(url) + .request(MediaType.APPLICATION_JSON) + .get()) { + if (response.getStatus() / 100 != 2) { + throw new APIException(url, "GET", response.getStatus(), "Vocabulary server error", response.readEntity(VocabularyException.class), null); + } + setCurrentPage(response.readEntity(pageClass)); + } + } + + private static String updatePageAndSizeUrlParameters(String url, Optional pageSize, Optional pageNumber, Optional sortField, Optional searchParameter) { + Map parameters = new HashMap<>(); + int questionMarkIndex = url.indexOf('?'); + if (questionMarkIndex > 0) { + String[] parts = url.substring(questionMarkIndex + 1).split("&"); + for (String part : parts) { + String[] keyValue = part.split("="); + if (keyValue.length == 2) { + parameters.put(keyValue[0], keyValue[1]); + } + } + } + pageSize.ifPresent(value -> parameters.put("size", String.valueOf(value))); + pageNumber.ifPresent(value -> parameters.put("page", String.valueOf(value))); + sortField.ifPresent(s -> parameters.put("sort", s)); + searchParameter.ifPresent(s -> parameters.put("search", s)); + if (searchParameter.isEmpty()) { + parameters.remove("search"); + } + if (questionMarkIndex < 0) { + url += "?"; + questionMarkIndex = url.length() - 1; + } + url = url.substring(0, questionMarkIndex + 1) + parameters.entrySet().stream() + .map(e -> e.getKey() + "=" + e.getValue()) + .collect(Collectors.joining("&")); + return url; + } + + @Override + public void reload() { + request(currentPage.get_links().get("self").getHref(), Optional.empty(), Optional.of(0L)); + } + + @Override + public void postLoad(T item) { + this.innerPostLoad(item); + this.rebuildTree(); + } + + private void innerPostLoad(T item) { + if (!this.treeMap.containsKey(item.getId())) { + this.insertElement(item); + } + + Node node = this.treeMap.get(item.getId()); + node.load(); + node.setVisible(true); + recursiveParentExpanding(node); + } + + private void insertElement(T item) { + Long parentId = null; + if (this.parentExtractor.isPresent()) { + parentId = this.parentExtractor.get().apply(item); + } + + Node node = new Node(); + node.setId(item.getId()); + node.setData(item); + node.prepareChildren(); + + if (parentId == null) { + this.tree.add(node); + } else { + getOrCreateParent(parentId).getChildren().add(node); + } + this.treeMap.putIfAbsent(item.getId(), node); + } + + private Node getOrCreateParent(Long parentId) { + if (!this.treeMap.containsKey(parentId)) { + T parentData = postLoader.apply(parentId); + insertElement(parentData); + } + Node result = this.treeMap.get(parentId); + result.load(); + return result; + } + + @Override + public long getCurrentPage() { + return currentPage.getPage().getNumber() + 1; + } + + @Override + public void setCurrentPage(long page) { + if (page != getCurrentPage()) { + if (page > getNumberOfPages()) { + page = getNumberOfPages(); + } + if (page < 1) { + page = 1; + } + request(currentPage.get_links().get(NAVIGATE_FIRST).getHref(), Optional.of(currentPage.getPage().getSize()), Optional.of(page - 1)); + } + } + + @Override + public List getItems() { + return this.items; + } + + @Override + public long getPageSize() { + return currentPage.getPage().getSize(); + } + + @Override + public void setPageSize(long pageSize) { + throw new NotImplementedException("to be done"); + } + + @Override + public long getTotalResults() { + return currentPage.getPage().getTotalElements(); + } + + @Override + public long getNumberOfPages() { + return currentPage.getPage().getTotalPages(); + } + + @Override + public boolean hasPreviousPage() { + return currentPage.get_links().containsKey(NAVIGATE_PREVIOUS); + } + + @Override + public boolean hasNextPage() { + return currentPage.get_links().containsKey(NAVIGATE_NEXT); + } + + @Override + public void cmdMoveFirst() { + request(currentPage.get_links().get(NAVIGATE_FIRST).getHref()); + } + + @Override + public void cmdMoveLast() { + request(currentPage.get_links().get(NAVIGATE_LAST).getHref()); + } + + @Override + public void cmdMoveNext() { + if (!hasNextPage()) { + return; + } + request(currentPage.get_links().get(NAVIGATE_NEXT).getHref()); + } + + @Override + public void cmdMovePrevious() { + if (!hasPreviousPage()) { + return; + } + request(currentPage.get_links().get(NAVIGATE_PREVIOUS).getHref()); + } +} diff --git a/src/main/java/io/goobi/workflow/api/vocabulary/hateoas/LanguagePageResult.java b/src/main/java/io/goobi/workflow/api/vocabulary/hateoas/LanguagePageResult.java new file mode 100644 index 0000000000..836eb25334 --- /dev/null +++ b/src/main/java/io/goobi/workflow/api/vocabulary/hateoas/LanguagePageResult.java @@ -0,0 +1,26 @@ +package io.goobi.workflow.api.vocabulary.hateoas; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import io.goobi.vocabulary.exchange.Language; +import lombok.Data; + +import java.util.Collections; +import java.util.List; + +@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class LanguagePageResult extends BasePageResult { + @Data + private class EmbeddedWrapper { + private List languageList; + } + + private EmbeddedWrapper _embedded; + + public List getContent() { + if (_embedded == null) { + return Collections.emptyList(); + } + return _embedded.getLanguageList(); + } +} diff --git a/src/main/java/io/goobi/workflow/api/vocabulary/hateoas/PageInformation.java b/src/main/java/io/goobi/workflow/api/vocabulary/hateoas/PageInformation.java new file mode 100644 index 0000000000..3446643295 --- /dev/null +++ b/src/main/java/io/goobi/workflow/api/vocabulary/hateoas/PageInformation.java @@ -0,0 +1,11 @@ +package io.goobi.workflow.api.vocabulary.hateoas; + +import lombok.Data; + +@Data +public class PageInformation { + private long size; + private long totalElements; + private long totalPages; + private long number; +} diff --git a/src/main/java/io/goobi/workflow/api/vocabulary/hateoas/VocabularyPageResult.java b/src/main/java/io/goobi/workflow/api/vocabulary/hateoas/VocabularyPageResult.java new file mode 100644 index 0000000000..a08736a57d --- /dev/null +++ b/src/main/java/io/goobi/workflow/api/vocabulary/hateoas/VocabularyPageResult.java @@ -0,0 +1,36 @@ +package io.goobi.workflow.api.vocabulary.hateoas; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import io.goobi.vocabulary.exchange.Vocabulary; +import io.goobi.workflow.api.vocabulary.helper.ExtendedVocabulary; +import lombok.Data; + +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class VocabularyPageResult extends BasePageResult { + @Data + private class EmbeddedWrapper { + private List vocabularyList; + } + + private List content; + + private EmbeddedWrapper _embedded; + + public List getContent() { + if (content == null) { + if (_embedded == null) { + this.content = Collections.emptyList(); + } else { + this.content = _embedded.getVocabularyList().stream() + .map(ExtendedVocabulary::new) + .collect(Collectors.toList()); + } + } + return this.content; + } +} diff --git a/src/main/java/io/goobi/workflow/api/vocabulary/hateoas/VocabularyRecordPageResult.java b/src/main/java/io/goobi/workflow/api/vocabulary/hateoas/VocabularyRecordPageResult.java new file mode 100644 index 0000000000..0e3b1b04c8 --- /dev/null +++ b/src/main/java/io/goobi/workflow/api/vocabulary/hateoas/VocabularyRecordPageResult.java @@ -0,0 +1,36 @@ +package io.goobi.workflow.api.vocabulary.hateoas; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import io.goobi.vocabulary.exchange.VocabularyRecord; +import io.goobi.workflow.api.vocabulary.helper.ExtendedVocabularyRecord; +import lombok.Data; + +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class VocabularyRecordPageResult extends BasePageResult { + @Data + private class EmbeddedWrapper { + private List vocabularyRecordList; + } + + private EmbeddedWrapper _embedded; + + private List content; + + public List getContent() { + if (content == null) { + if (_embedded == null) { + this.content = Collections.emptyList(); + } else { + this.content = _embedded.getVocabularyRecordList().stream() + .map(ExtendedVocabularyRecord::new) + .collect(Collectors.toList()); + } + } + return this.content; + } +} diff --git a/src/main/java/io/goobi/workflow/api/vocabulary/hateoas/VocabularySchemaPageResult.java b/src/main/java/io/goobi/workflow/api/vocabulary/hateoas/VocabularySchemaPageResult.java new file mode 100644 index 0000000000..5a6eb4bc37 --- /dev/null +++ b/src/main/java/io/goobi/workflow/api/vocabulary/hateoas/VocabularySchemaPageResult.java @@ -0,0 +1,26 @@ +package io.goobi.workflow.api.vocabulary.hateoas; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import io.goobi.vocabulary.exchange.VocabularySchema; +import lombok.Data; + +import java.util.Collections; +import java.util.List; + +@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class VocabularySchemaPageResult extends BasePageResult { + @Data + private class EmbeddedWrapper { + private List vocabularySchemaList; + } + + private EmbeddedWrapper _embedded; + + public List getContent() { + if (_embedded == null) { + return Collections.emptyList(); + } + return _embedded.getVocabularySchemaList(); + } +} diff --git a/src/main/java/io/goobi/workflow/api/vocabulary/helper/APIExceptionExtractor.java b/src/main/java/io/goobi/workflow/api/vocabulary/helper/APIExceptionExtractor.java new file mode 100644 index 0000000000..d1d85baed2 --- /dev/null +++ b/src/main/java/io/goobi/workflow/api/vocabulary/helper/APIExceptionExtractor.java @@ -0,0 +1,94 @@ +package io.goobi.workflow.api.vocabulary.helper; + +import de.sub.goobi.helper.Helper; +import io.goobi.vocabulary.exception.VocabularyException; +import io.goobi.workflow.api.vocabulary.APIException; +import lombok.extern.log4j.Log4j2; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +@Log4j2 +public class APIExceptionExtractor { + private final static String MESSAGE_PREFIX = "vocabularyManager_exception_"; + private final APIException exception; + + public APIExceptionExtractor(APIException exception) { + this.exception = exception; + } + + public String getLocalizedMessage(Locale locale) { + return Optional.ofNullable(exception.getVocabularyCause()) + .map(ex -> extractLocalizedVocabularyMessage(ex, locale)).orElse(exception.getMessage()); + } + + private String extractLocalizedVocabularyMessage(VocabularyException ex, Locale locale) { + String currentLevelMessage = getLocalizedMessage(ex.getErrorType(), Optional.ofNullable(ex.getParams()).orElse(Collections.emptyMap())) + .orElse(""); + List causeLevelMessages = Optional.ofNullable(ex.getCauses()) + .map(Collection::stream) + .map(s -> s.map(e -> extractLocalizedVocabularyMessage(e, locale)) + .filter(m -> !m.isBlank()) + .collect(Collectors.toList())) + .orElse(Collections.emptyList()); + String message = currentLevelMessage; + if (!causeLevelMessages.isEmpty()) { + message += (message.isBlank() ? "" : "\n") + String.join("\n", causeLevelMessages); + } + return message; + } + + private Optional getLocalizedMessage(VocabularyException.ErrorCode errorType, Map params) { + String message = null; + String messageKey = MESSAGE_PREFIX + errorType.toString(); + List orderedParameters = null; + switch (errorType) { + case DataIntegrityViolation: + orderedParameters = List.of("reason"); + break; + case EntityNotFound: + orderedParameters = List.of("type", "id"); + break; + case FieldValueIsNotUnique: + orderedParameters = List.of("definitionName", "duplicateValues"); + break; + case FieldValuesDoNotMatchSpecifiedValidationRegex: + orderedParameters = List.of("definitionName", "values", "regex"); + break; + case RecordValidationMissingRequiredFields: + orderedParameters = List.of("missingFieldNames"); + break; + case RecordImportUnsupportedExcelCellType: + orderedParameters = List.of("cellType"); + break; + case DeletionOfReferencedVocabulary: + orderedParameters = List.of("vocabularyId", "referencingVocabularyIds"); + break; + case DeletionOfReferencedVocabularyRecord: + if (params.containsKey("referencingRecordIds")) { + orderedParameters = List.of("recordId", "referencingRecordIds"); + } + break; + default: + log.warn("No translation for vocabulary exception type \"{}\" given, parameters: {}", errorType, params); + orderedParameters = List.of(errorType.toString()); + break; + } + if (orderedParameters == null) { + return Optional.empty(); + } + + String[] rawParams = new String[orderedParameters.size()]; + orderedParameters.stream() + .map(params::get) + .collect(Collectors.toList()) + .toArray(rawParams); + message = Helper.getTranslation(messageKey, rawParams); + return Optional.ofNullable(message); + } +} diff --git a/src/main/java/io/goobi/workflow/api/vocabulary/helper/CachedLookup.java b/src/main/java/io/goobi/workflow/api/vocabulary/helper/CachedLookup.java new file mode 100644 index 0000000000..84e096d1a0 --- /dev/null +++ b/src/main/java/io/goobi/workflow/api/vocabulary/helper/CachedLookup.java @@ -0,0 +1,58 @@ +package io.goobi.workflow.api.vocabulary.helper; + +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; + +public class CachedLookup { + private static final long MAX_DATA_AGE_IN_MS = 5000L; + + @Data + @AllArgsConstructor + private class AgingData { + private final long timestamp; + private final T data; + + public long getAge() { + return System.currentTimeMillis() - getTimestamp(); + } + } + + private Map cache = new HashMap<>(); + private Function lookupFunction; + + public CachedLookup(Function lookupFunction) { + this.lookupFunction = lookupFunction; + } + + public synchronized T getCached(K key) { + if (!cache.containsKey(key)) { + return insert(key); + } + AgingData agingData = cache.get(key); + if (agingData.getAge() > MAX_DATA_AGE_IN_MS) { + return insert(key); + } + return agingData.getData(); + } + + public synchronized T update(K key, T item) { + return insert(key, item); + } + + public synchronized void invalidate(K key) { + this.cache.remove(key); + } + + private T insert(K key) { + return insert(key, this.lookupFunction.apply(key)); + } + + private T insert(K key, T data) { + cache.put(key, new AgingData(System.currentTimeMillis(), data)); + return data; + } +} diff --git a/src/main/java/io/goobi/workflow/api/vocabulary/helper/ExtendedFieldInstance.java b/src/main/java/io/goobi/workflow/api/vocabulary/helper/ExtendedFieldInstance.java new file mode 100644 index 0000000000..93774b5fdb --- /dev/null +++ b/src/main/java/io/goobi/workflow/api/vocabulary/helper/ExtendedFieldInstance.java @@ -0,0 +1,206 @@ +package io.goobi.workflow.api.vocabulary.helper; + +import de.sub.goobi.helper.Helper; +import io.goobi.vocabulary.exchange.FieldDefinition; +import io.goobi.vocabulary.exchange.FieldInstance; +import io.goobi.vocabulary.exchange.FieldType; +import io.goobi.vocabulary.exchange.FieldValue; +import io.goobi.vocabulary.exchange.TranslationDefinition; +import io.goobi.vocabulary.exchange.TranslationInstance; +import io.goobi.workflow.api.vocabulary.VocabularyAPIManager; +import lombok.Getter; +import lombok.extern.log4j.Log4j2; +import org.goobi.managedbeans.FormInputMultiSelectBean; +import org.goobi.managedbeans.FormInputMultiSelectHelper; + +import javax.faces.model.SelectItem; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +import static io.goobi.workflow.api.vocabulary.helper.ExtendedTranslationInstance.transformToThreeCharacterAbbreviation; + +@Getter +@Log4j2 +public class ExtendedFieldInstance extends FieldInstance { + private Function recordResolver = VocabularyAPIManager.getInstance().vocabularyRecords()::get; + private Function> recordsResolver = this::getAllRecords; + private Function definitionResolver = VocabularyAPIManager.getInstance().vocabularySchemas()::getDefinition; + private Function typeResolver = VocabularyAPIManager.getInstance().fieldTypes()::get; + private Supplier languageSupplier = Helper.getLanguageBean().getLocale()::getLanguage; + + private FieldDefinition definition; + private FieldType type; + + private FormInputMultiSelectBean selectionBean; + private List selectableItems; + + private List getAllRecords(Long vocabularyId) { + return VocabularyAPIManager.getInstance().vocabularyRecords() + .list(vocabularyId) + .all() + .request() + .getContent(); + } + + public ExtendedFieldInstance(FieldInstance orig) { + setId(orig.getId()); + setRecordId(orig.getRecordId()); + setDefinitionId(orig.getDefinitionId()); + setValues(orig.getValues()); + + postInit(); + prepareEmpty(); + sortTranslations(); + } + + private void postInit() { + this.definition = definitionResolver.apply(getDefinitionId()); + if (this.definition.getTypeId() != null) { + this.type = typeResolver.apply(this.definition.getTypeId()); + } + if (this.type != null) { + this.selectableItems = this.type.getSelectableValues().stream() + .map(v -> new SelectItem(v, v)) + .collect(Collectors.toList()); + } else if (this.definition.getReferenceVocabularyId() != null) { + this.selectableItems = recordsResolver.apply(this.definition.getReferenceVocabularyId()).stream() + .map(r -> new SelectItem(Long.toString(r.getId()), r.getMainValue())) + .collect(Collectors.toList()); + } + this.selectionBean = new FormInputMultiSelectHelper(() -> this.selectableItems, this::getSelection, this::setSelection); + } + + private void prepareEmpty() { + if (getValues().isEmpty()) { + getValues().add(new ExtendedFieldValue(new FieldValue(), definition.getTranslationDefinitions())); + } + } + + public FormInputMultiSelectBean getSelectionBean() { + return this.selectionBean; + } + + public List getSelection() { + if (this.selectableItems.isEmpty()) { + return Collections.emptyList(); + } + + List selection = new LinkedList<>(); + for (String selectedValue : getValues().stream() + .flatMap(v -> v.getTranslations().stream()) + .map(TranslationInstance::getValue) + .filter(v -> !v.isBlank() && !v.equals("null")) + .collect(Collectors.toList())) { + // TODO: Single selects are directly bound to value translations and might set "null" + SelectItem item = this.selectableItems.stream() + .filter(i -> i.getValue().equals(selectedValue)) + .findFirst() + .orElseThrow(); + selection.add(item); + } + return selection; + } + + public void setSelection(List selection) { + List selectedValues = selection.stream() + .map(s -> (String) s.getValue()) + .collect(Collectors.toList()); + getValues().clear(); + selectedValues.forEach(v -> { + FieldValue fieldValue = addFieldValue(); + fieldValue.getTranslations().get(0).setValue(v); + }); + } + + private void sortTranslations() { + getValues().forEach(this::sortTranslations); + } + + private void sortTranslations(FieldValue value) { + Collections.sort(value.getTranslations(), Comparator.comparing(TranslationInstance::getLanguage)); + } + + public FieldValue addFieldValue() { + FieldValue value = new ExtendedFieldValue(new FieldValue(), definition.getTranslationDefinitions()); + getValues().add(value); + prepareEmpty(); + sortTranslations(value); + return value; + } + + public void deleteFieldValue(FieldValue value) { + getValues().remove(value); + } + + public String getFieldValue() { + return getFieldValue(transformToThreeCharacterAbbreviation(this.languageSupplier.get())); + } + + public String getFieldValue(String language) { + String value = extractValue(this, language); + if (!value.isBlank() && definition.getReferenceVocabularyId() != null) { + // Process multi-valued referenced fields + List ids = Arrays.stream(value.strip().split("\\|")) + .map(Long::parseLong) + .collect(Collectors.toList()); + List values = new LinkedList<>(); + for (long id : ids) { + ExtendedVocabularyRecord result = new ExtendedVocabularyRecord(recordResolver.apply(id)); + values.add(result.getMainValue()); + } + value = String.join("|", values); + } + return value; + } + + public void setFieldValue(String value) { + getValues().clear(); + FieldValue fieldValue = addFieldValue(); + fieldValue.getTranslations().forEach(t -> t.setValue(value)); + } + + private String extractValue(FieldInstance field, String language) { + return field.getValues().stream() + .map( + v -> { + Optional preferredLanguage = v.getTranslations().stream() + .filter(t -> language != null && language.equals(t.getLanguage())) + .map(TranslationInstance::getValue) + .findFirst(); + if (preferredLanguage.isPresent() && !preferredLanguage.get().isBlank()) { + return preferredLanguage.get(); + } + String fallbackLanguage = definition.getTranslationDefinitions().stream() + .filter(t -> Boolean.TRUE.equals(t.getFallback())) + .map(TranslationDefinition::getLanguage) + .findFirst() + .orElse(null); + if (fallbackLanguage == null) { + return v.getTranslations().stream() + .filter(t -> t.getLanguage() == null) + .map(TranslationInstance::getValue) + .findFirst() + .orElseThrow(); + } + return v.getTranslations().stream() + .filter(t -> fallbackLanguage.equals(t.getLanguage())) + .map(TranslationInstance::getValue) + .findFirst() + .orElseThrow(); + } + ).collect(Collectors.joining("|")); + } + + public List getExtendedValues() { + return getValues().stream() + .map(v -> new ExtendedFieldValue(v, definition.getTranslationDefinitions())) + .collect(Collectors.toList()); + } +} diff --git a/src/main/java/io/goobi/workflow/api/vocabulary/helper/ExtendedFieldValue.java b/src/main/java/io/goobi/workflow/api/vocabulary/helper/ExtendedFieldValue.java new file mode 100644 index 0000000000..306be5c668 --- /dev/null +++ b/src/main/java/io/goobi/workflow/api/vocabulary/helper/ExtendedFieldValue.java @@ -0,0 +1,97 @@ +package io.goobi.workflow.api.vocabulary.helper; + +import io.goobi.vocabulary.exchange.FieldValue; +import io.goobi.vocabulary.exchange.HateoasHref; +import io.goobi.vocabulary.exchange.TranslationDefinition; +import io.goobi.vocabulary.exchange.TranslationInstance; +import lombok.Getter; +import lombok.extern.log4j.Log4j2; + +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +@Getter +@Log4j2 +public class ExtendedFieldValue extends FieldValue { + private final FieldValue wrapped; + private List extendedTranslations; + + ExtendedFieldValue(FieldValue orig, Set definitions) { + this.wrapped = orig; + + postInit(definitions); + } + + @Override + public Long getId() { + return wrapped.getId(); + } + + @Override + public void setId(Long id) { + wrapped.setId(id); + } + + @Override + public Long getFieldId() { + return wrapped.getFieldId(); + } + + @Override + public void setFieldId(Long fieldId) { + wrapped.setFieldId(fieldId); + } + + @Override + public List getTranslations() { + return wrapped.getTranslations(); + } + + @Override + public void setTranslations(List translations) { + wrapped.setTranslations(translations); + } + + @Override + public Map get_links() { + return wrapped.get_links(); + } + + @Override + public void set_links(Map _links) { + wrapped.set_links(_links); + } + + private void postInit(Set definitions) { + prepareEmpty(definitions); + + Map lookup = definitions.stream() + .filter(d -> d.getLanguage() != null) + .collect(Collectors.toMap(TranslationDefinition::getLanguage, Function.identity())); + this.extendedTranslations = getTranslations().stream() + .map(t -> new ExtendedTranslationInstance(t, lookup.getOrDefault(t.getLanguage(), null))) + .sorted(Comparator.comparing(TranslationInstance::getLanguage)) + .collect(Collectors.toList()); + } + + private void prepareEmpty(Set definitions) { + if (!definitions.isEmpty()) { + definitions.stream() + .filter(t -> getTranslations().stream().noneMatch(t2 -> t2.getLanguage().equals(t.getLanguage()))) + .forEach(t -> { + TranslationInstance translation = new TranslationInstance(); + translation.setLanguage(t.getLanguage()); + translation.setValue(""); + getTranslations().add(translation); + }); + } else if (getTranslations().isEmpty()) { + TranslationInstance translation = new TranslationInstance(); + translation.setValue(""); + getTranslations().add(translation); + } + } +} diff --git a/src/main/java/io/goobi/workflow/api/vocabulary/helper/ExtendedTranslationInstance.java b/src/main/java/io/goobi/workflow/api/vocabulary/helper/ExtendedTranslationInstance.java new file mode 100644 index 0000000000..4bf6944db1 --- /dev/null +++ b/src/main/java/io/goobi/workflow/api/vocabulary/helper/ExtendedTranslationInstance.java @@ -0,0 +1,67 @@ +package io.goobi.workflow.api.vocabulary.helper; + +import io.goobi.vocabulary.exchange.Language; +import io.goobi.vocabulary.exchange.TranslationDefinition; +import io.goobi.vocabulary.exchange.TranslationInstance; +import io.goobi.workflow.api.vocabulary.VocabularyAPIManager; +import lombok.Getter; +import lombok.extern.log4j.Log4j2; + +import java.util.function.Function; + +@Getter +@Log4j2 +public class ExtendedTranslationInstance extends TranslationInstance { + private Function languageNameResolver = VocabularyAPIManager.getInstance().languages()::findByAbbreviation; + + private final TranslationInstance wrapped; + private TranslationDefinition definition; + private String languageName; + + ExtendedTranslationInstance(TranslationInstance orig, TranslationDefinition definition) { + this.wrapped = orig; + this.definition = definition; + + postInit(); + } + + @Override + public String getLanguage() { + return wrapped.getLanguage(); + } + + @Override + public void setLanguage(String language) { + wrapped.setLanguage(language); + } + + @Override + public String getValue() { + return wrapped.getValue(); + } + + @Override + public void setValue(String value) { + wrapped.setValue(value); + } + + private void postInit() { + if (getLanguage() != null) { + this.languageName = languageNameResolver.apply(getLanguage()).getName(); + } + } + + static String transformToThreeCharacterAbbreviation(String language) { + switch (language) { + case "en": + return "eng"; + case "de": + return "ger"; + case "fr": + return "fre"; + default: + log.warn("Unknown language \"{}\", falling back to \"eng\"", language); + return "eng"; + } + } +} diff --git a/src/main/java/io/goobi/workflow/api/vocabulary/helper/ExtendedVocabulary.java b/src/main/java/io/goobi/workflow/api/vocabulary/helper/ExtendedVocabulary.java new file mode 100644 index 0000000000..379eef4e45 --- /dev/null +++ b/src/main/java/io/goobi/workflow/api/vocabulary/helper/ExtendedVocabulary.java @@ -0,0 +1,52 @@ +package io.goobi.workflow.api.vocabulary.helper; + +import io.goobi.vocabulary.exchange.Vocabulary; +import lombok.Getter; + +import java.util.Optional; + +public class ExtendedVocabulary extends Vocabulary { + @Getter + private boolean skosExportPossible; + + public ExtendedVocabulary(Vocabulary orig) { + setId(orig.getId()); + setSchemaId(orig.getSchemaId()); + setMetadataSchemaId(orig.getMetadataSchemaId()); + setName(orig.getName()); + setDescription(orig.getDescription()); + set_links(orig.get_links()); + + postInit(); + } + + private void postInit() { + this.skosExportPossible = Optional.ofNullable(get_links()) + .map(m -> m.keySet().stream().anyMatch(link -> link.startsWith("export_rdf"))) + .orElse(false); + } + + public String getURI() { + return get_links().get("self").getHref(); + } + + public String rdfXmlExport() { + return get_links().get("export_rdf_xml").getHref(); + } + + public String rdfTurtleExport() { + return get_links().get("export_rdf_turtle").getHref(); + } + + public String jsonExport() { + return get_links().get("export_json").getHref(); + } + + public String csvExport() { + return get_links().get("export_csv").getHref(); + } + + public String excelExport() { + return get_links().get("export_excel").getHref(); + } +} diff --git a/src/main/java/io/goobi/workflow/api/vocabulary/helper/ExtendedVocabularyRecord.java b/src/main/java/io/goobi/workflow/api/vocabulary/helper/ExtendedVocabularyRecord.java new file mode 100644 index 0000000000..3061d11040 --- /dev/null +++ b/src/main/java/io/goobi/workflow/api/vocabulary/helper/ExtendedVocabularyRecord.java @@ -0,0 +1,141 @@ +package io.goobi.workflow.api.vocabulary.helper; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.goobi.vocabulary.exchange.FieldDefinition; +import io.goobi.vocabulary.exchange.FieldInstance; +import io.goobi.vocabulary.exchange.VocabularyRecord; +import io.goobi.vocabulary.exchange.VocabularySchema; +import io.goobi.workflow.api.vocabulary.VocabularyAPIManager; +import lombok.Getter; +import ugh.dl.Metadata; + +import java.util.Collections; +import java.util.Comparator; +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Collectors; + +@Getter +public class ExtendedVocabularyRecord extends VocabularyRecord { + private Function vocabularyResolver = VocabularyAPIManager.getInstance().vocabularies()::get; + private Function recordResolver = VocabularyAPIManager.getInstance().vocabularyRecords()::get; + private Function schemaResolver = VocabularyAPIManager.getInstance().vocabularySchemas()::getSchema; + private Function> metadataSchemaResolver = VocabularyAPIManager.getInstance().vocabularySchemas()::getMetadataSchema; + + private int level; + private String mainValue; + private List titleValues; + private List extendedFields; + private List parents; + + public ExtendedVocabularyRecord(VocabularyRecord orig) { + // TODO: Make generic solution for this + setId(orig.getId()); + setParentId(orig.getParentId()); + setVocabularyId(orig.getVocabularyId()); + setMetadata(orig.getMetadata()); + setFields(orig.getFields()); + setChildren(orig.getChildren()); + set_links(orig.get_links()); + + postInit(); + prepareEmpty(); + } + + // TODO: Think about recreation / updating these values in case the record changes.. + private void postInit() { + initParents(); + this.level = this.parents.size(); + this.extendedFields = getFields().stream() + .sorted(Comparator.comparingLong(FieldInstance::getDefinitionId)) + .map(ExtendedFieldInstance::new) + .collect(Collectors.toList()); + this.titleValues = this.extendedFields.stream() + .sorted(Comparator.comparingLong(FieldInstance::getDefinitionId)) + .filter(f -> Boolean.TRUE.equals(f.getDefinition().getTitleField())) + .map(ExtendedFieldInstance::getFieldValue) + .collect(Collectors.toList()); + this.mainValue = this.extendedFields.stream() + .filter(f -> Boolean.TRUE.equals(f.getDefinition().getMainEntry())) + .map(ExtendedFieldInstance::getFieldValue) + .findAny() + .orElse(""); + prepareEmpty(); + } + + @JsonIgnore + public String getURI() { + return get_links().get("self").getHref(); + } + + public Optional getFieldValueForDefinition(FieldDefinition definition) { + return getFieldForDefinition(definition) + .map(ExtendedFieldInstance::getFieldValue); + } + + public Optional getFieldValueForDefinition(FieldDefinition definition, String language) { + return getFieldForDefinition(definition) + .map(f -> f.getFieldValue(language)); + } + + public Optional getFieldValueForDefinitionName(String definitionName) { + return getFieldForDefinitionName(definitionName) + .map(ExtendedFieldInstance::getFieldValue); + } + + public Optional getFieldValueForDefinitionName(String definitionName, String language) { + return getFieldForDefinitionName(definitionName) + .map(f -> f.getFieldValue(language)); + } + + public Optional getFieldForDefinition(FieldDefinition definition) { + return getExtendedFields().stream() + .filter(f -> f.getDefinitionId().equals(definition.getId())) + .findFirst(); + } + + public Optional getFieldForDefinitionName(String definitionName) { + return getExtendedFields().stream() + .filter(f -> f.getDefinition().getName().equals(definitionName)) + .findFirst(); + } + + public void writeReferenceMetadata(Metadata meta) { + ExtendedVocabulary vocabulary = vocabularyResolver.apply(getVocabularyId()); + meta.setValue(getMainValue()); + meta.setAuthorityFile(vocabulary.getName(), vocabulary.get_links().get("self").getHref(), get_links().get("self").getHref()); + } + + private void initParents() { + if (this.getParentId() != null) { + ExtendedVocabularyRecord parent = recordResolver.apply(this.getParentId()); + this.parents = new LinkedList<>(parent.getParents()); + this.parents.add(parent); + } else { + this.parents = Collections.emptyList(); + } + } + + private void prepareEmpty() { + List existingFields = getFields().stream() + .map(FieldInstance::getDefinitionId) + .collect(Collectors.toList()); + Optional schema = Boolean.TRUE.equals(this.getMetadata()) ? metadataSchemaResolver.apply(this) : Optional.of(schemaResolver.apply(this)); + List missingFields = schema.map(s -> s.getDefinitions().stream() + .map(FieldDefinition::getId) + .filter(i -> !existingFields.contains(i)) + .collect(Collectors.toList())) + .orElse(Collections.emptyList()); + missingFields.forEach(d -> { + FieldInstance field = new FieldInstance(); + field.setRecordId(getId()); + field.setDefinitionId(d); + getFields().add(field); + }); + if (!missingFields.isEmpty()) { + postInit(); + } + } +} diff --git a/src/main/java/org/goobi/api/rest/VocabularyResource.java b/src/main/java/org/goobi/api/rest/VocabularyResource.java deleted file mode 100644 index 51276056fb..0000000000 --- a/src/main/java/org/goobi/api/rest/VocabularyResource.java +++ /dev/null @@ -1,253 +0,0 @@ -/** - * This file is part of the Goobi Application - a Workflow tool for the support of mass digitization. - * - * Visit the websites for more information. - * - https://goobi.io - * - https://www.intranda.com - * - * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Linking this library statically or dynamically with other modules is making a combined work based on this library. Thus, the terms and conditions - * of the GNU General Public License cover the whole combination. As a special exception, the copyright holders of this library give you permission to - * link this library with independent modules to produce an executable, regardless of the license terms of these independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that you also meet, for each linked independent module, the terms and - * conditions of the license of that module. An independent module is a module which is not derived from or based on this library. If you modify this - * library, you may extend this exception to your version of the library, but you are not obliged to do so. If you do not wish to do so, delete this - * exception statement from your version. - */ -package org.goobi.api.rest; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.UriInfo; - -import org.apache.commons.lang3.StringUtils; -import org.goobi.production.cli.helper.StringPair; -import org.goobi.vocabulary.Definition; -import org.goobi.vocabulary.Field; -import org.goobi.vocabulary.JskosRecord; -import org.goobi.vocabulary.JskosRecord.Fields; -import org.goobi.vocabulary.JskosRecord.Publisher; -import org.goobi.vocabulary.JskosRecord.Schema; -import org.goobi.vocabulary.VocabRecord; -import org.goobi.vocabulary.Vocabulary; - -/** - * This class represents a rest endpoint to search within a vocabulary - * - */ - -import de.sub.goobi.persistence.managers.VocabularyManager; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.tags.Tag; - -@Path("/vocabulary") -public class VocabularyResource { - - /** - * Search for a term within all fields of a vocabulary - * - * @param vocabulary - * @param searchvalue - * @return - */ - - @GET - @Path("{vocabulary}/{searchvalue}") - @Operation(summary = "Searches for a term within all fields of a vocabulary", - description = "Searches for a term within all fields of a vocabulary") - @ApiResponse(responseCode = "200", description = "OK") - @ApiResponse(responseCode = "400", description = "Bad Request") - @ApiResponse(responseCode = "500", description = "Internal error") - @Produces(MediaType.APPLICATION_JSON) - @Tag(name = "vocabulary") - public Response findRecords(@PathParam("vocabulary") String vocabulary, @PathParam("searchvalue") String searchvalue) { - List records = VocabularyManager.findRecords(vocabulary, searchvalue); - return Response.ok(records).build(); - } - - /** - * Search for a term within a field of a vocabulary - * - * @param vocabulary - * @param fieldname - * @param searchvalue - * @return - */ - - @GET - @Path("{vocabulary}/{fieldname}/{searchvalue}") - @Operation(summary = "Searches for a term within all fields of a vocabulary", - description = "Searches for a term within all fields of a vocabulary") - @ApiResponse(responseCode = "200", description = "OK") - @ApiResponse(responseCode = "400", description = "Bad Request") - @ApiResponse(responseCode = "500", description = "Internal error") - @Produces(MediaType.APPLICATION_JSON) - @Tag(name = "vocabulary") - public Response findRecords(@PathParam("vocabulary") String vocabulary, @PathParam("fieldname") String fieldname, - @PathParam("searchvalue") String searchvalue) { - List records = VocabularyManager.findRecords(vocabulary, searchvalue, fieldname); - return Response.ok(records).build(); - } - - @POST - @Path("{vocabulary}") - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - @Tag(name = "vocabulary") - public Response findRecords(@PathParam("vocabulary") String vocabulary, List data) { - List records = VocabularyManager.findRecords(vocabulary, data); - return Response.ok(records).build(); - } - - /** - * get a complete vocabulary including all records. Can be used to display drop down lists in mets editor - * - * @return - */ - @GET - @Path("{vocabulary}") - @Operation(summary = "Returns a complete vocabulary including all records", - description = "Returns a complete vocabulary including all records. Can be used to display drop down lists in mets editor.") - @ApiResponse(responseCode = "200", description = "OK") - @ApiResponse(responseCode = "400", description = "Bad Request") - @ApiResponse(responseCode = "500", description = "Internal error") - @Produces(MediaType.APPLICATION_JSON) - @Tag(name = "vocabulary") - public Response getVocabularyByName(@PathParam("vocabulary") String vocabularyName) { - Vocabulary vocabulary = VocabularyManager.getVocabularyByTitle(vocabularyName); - VocabularyManager.getAllRecords(vocabulary); - return Response.ok(vocabulary).build(); - } - - /** - * get a VocabRecord from url - * - */ - - @GET - @Path("records/{vocabulary}/{record}") - @Operation(summary = "Returns a vocabulary from URL", description = "Returns a vocabulary from URL") - @ApiResponse(responseCode = "200", description = "OK") - @ApiResponse(responseCode = "400", description = "Bad Request") - @ApiResponse(responseCode = "500", description = "Internal error") - @Produces(MediaType.APPLICATION_JSON) - @Tag(name = "vocabulary") - public Response getRecord(@PathParam("vocabulary") Integer vocabularyId, @PathParam("record") Integer recordId) { - VocabRecord recordRecord = VocabularyManager.getRecord(vocabularyId, recordId); - return Response.ok(recordRecord).build(); - } - - @GET - @Path("records/jskos/{vocabulary}/{record}") - @Operation(summary = "Returns a jskos vocabulary", description = "Returns a jskos vocabulary from URL and an ID") - @ApiResponse(responseCode = "200", description = "OK") - @ApiResponse(responseCode = "400", description = "Bad Request") - @ApiResponse(responseCode = "500", description = "Internal error") - @Produces(MediaType.APPLICATION_JSON) - @Tag(name = "vocabulary") - public Response getRecordAsJskos(@Context UriInfo uriInfo, @PathParam("vocabulary") Integer vocabularyId, @PathParam("record") Integer recordId) { - VocabRecord recordRecord = VocabularyManager.getRecord(vocabularyId, recordId); - if (recordRecord == null) { - return Response.status(404).build(); - } - Vocabulary vocabulary = VocabularyManager.getVocabularyById(vocabularyId); - - String uri = uriInfo.getBaseUri() + "vocabulary/records/jskos/" + vocabularyId + "/" + recordId; - - JskosRecord jskosRecord = new JskosRecord(); - jskosRecord.setUri(uri); - List types = new ArrayList<>(); - types.add("http://www.w3.org/2004/02/skos/core#Concept"); - jskosRecord.setType(types); - jskosRecord.setContext("https://goobi.io/"); - - Schema schema = jskosRecord.new Schema(); - schema.setUri(uriInfo.getBaseUri() + "vocabulary/" + vocabulary.getTitle()); - Map prefLabel = new HashMap<>(); - prefLabel.put("title", vocabulary.getTitle()); - prefLabel.put("description", vocabulary.getDescription()); - List schemaType = new ArrayList<>(); - schemaType.add("http://www.w3.org/2004/02/skos/core#ConceptScheme"); - schemaType.add("http://w3id.org/nkos/nkostype#list"); - schema.setType(schemaType); - Fields schemaPrefLabel = jskosRecord.new Fields(); - schemaPrefLabel.setValues(prefLabel); - schema.setPrefLabel(schemaPrefLabel); - List inScheme = new ArrayList<>(); - inScheme.add(schema); - jskosRecord.setInScheme(inScheme); - - Publisher publisher = jskosRecord.new Publisher(); - Fields publisherPrefLabel = jskosRecord.new Fields(); - publisherPrefLabel.setValue("Goobi"); - publisher.setPrefLabel(publisherPrefLabel); - publisher.setUri(uriInfo.getBaseUri().toString()); - jskosRecord.setPublisher(publisher); - - String mainFieldName = ""; - for (Definition definition : vocabulary.getStruct()) { - if (definition.isMainEntry()) { - mainFieldName = definition.getLabel(); - } - } - Map mainFields = new HashMap<>(); - List otherFields = new ArrayList<>(); - for (Field field : recordRecord.getFields()) { - if (field.getLabel().equals(mainFieldName)) { - mainFields.put(StringUtils.isBlank(field.getLanguage()) ? "-" : field.getLanguage(), field.getValue()); - } else if (!otherFields.contains(field.getLabel())) { - otherFields.add(field.getLabel()); - } - } - Fields jskosPrefLabel = jskosRecord.new Fields(); - if (StringUtils.isNotBlank(mainFields.get("-"))) { - jskosPrefLabel.setValue(mainFields.get("-")); - } else { - jskosPrefLabel.setValues(mainFields); - } - jskosRecord.setPrefLabel(jskosPrefLabel); - - Map otherFieldValues = new HashMap<>(); - for (String fieldName : otherFields) { - Map values = new HashMap<>(); - for (Field field : recordRecord.getFields()) { - if (field.getLabel().equals(fieldName)) { - values.put(StringUtils.isBlank(field.getLanguage()) ? "-" : field.getLanguage(), field.getValue()); - } - } - Fields jskosField = jskosRecord.new Fields(); - if (StringUtils.isNotBlank(values.get("-"))) { - jskosField.setValue(values.get("-")); - } else { - jskosField.setValues(values); - } - - otherFieldValues.put(fieldName, jskosField); - } - jskosRecord.setFields(otherFieldValues); - - return Response.ok(jskosRecord).build(); - } - -} diff --git a/src/main/java/org/goobi/goobiScript/GoobiScriptAddPluginToStep.java b/src/main/java/org/goobi/goobiScript/GoobiScriptAddPluginToStep.java index 3f9c1ffe2b..ee778534c3 100644 --- a/src/main/java/org/goobi/goobiScript/GoobiScriptAddPluginToStep.java +++ b/src/main/java/org/goobi/goobiScript/GoobiScriptAddPluginToStep.java @@ -118,7 +118,7 @@ public void execute(GoobiScriptResult gsr) { } } if (gsr.getResultType().equals(GoobiScriptResultType.RUNNING)) { - gsr.setResultType(GoobiScriptResultType.OK); + gsr.setResultType(GoobiScriptResultType.ERROR); gsr.setResultMessage("Step not found: " + parameters.get(STEPTITLE)); } gsr.updateTimestamp(); diff --git a/src/main/java/org/goobi/io/BackupFileManager.java b/src/main/java/org/goobi/io/BackupFileManager.java index 972920e061..62a5824061 100644 --- a/src/main/java/org/goobi/io/BackupFileManager.java +++ b/src/main/java/org/goobi/io/BackupFileManager.java @@ -35,6 +35,7 @@ import java.util.Collections; import java.util.List; +import de.sub.goobi.config.ConfigurationHelper; import de.sub.goobi.helper.Helper; import de.sub.goobi.helper.StorageProvider; import lombok.extern.log4j.Log4j2; @@ -49,6 +50,10 @@ public abstract class BackupFileManager { private static final String TIMESTAMP_REGEX = "\\d{4}-\\d{2}-\\d{2}-\\d{9}"; private static final int TIMESTAMP_LENGTH = BackupFileManager.TIMESTAMP_FORMAT.length(); + public static String createBackup(String path, String fileName, boolean createFrontendMessage) throws IOException { + return BackupFileManager.createBackup(path, path, fileName, ConfigurationHelper.getInstance().getNumberOfBackups(), createFrontendMessage); + } + /** * Creates a backup. The difference to the other method is that this one uses the same path for original files and backup files. * @@ -78,18 +83,18 @@ public static String createBackup(String path, String fileName, int limit, boole * * @param path The path of the original file * @param backupPath The path of the backup file (may be the same as the path) - * @param fileName The name of the original file (without directory) + * @param name The name of the original file (without directory) * @param limit The maximum number of backup files before the oldest one gets deleted. * @param createFrontendMessage Must be true to generate frontend help messages (Helper.setMeldung() or Helper.setFehlerMeldung()) * @return The name of the created backup file or null in case of an error * @throws IOException if there was an error while reading the original file or writing backup files */ - public static String createBackup(String path, String backupPath, String fileName, int limit, boolean createFrontendMessage) throws IOException { - String backupFileName = null; + public static String createBackup(String path, String backupPath, String name, int limit, boolean createFrontendMessage) throws IOException { + String backupFileOrDirectoryName = null; try { if (limit > 0) { - backupFileName = BackupFileManager.createBackupFile(path, backupPath, fileName); - log.trace("The backup file {} was created successfully.", backupPath + backupFileName); + backupFileOrDirectoryName = BackupFileManager.createBackup(path, backupPath, name); + log.trace("The backup file {} was created successfully.", backupPath + backupFileOrDirectoryName); } } catch (Exception exception) { if (createFrontendMessage) { @@ -100,7 +105,7 @@ public static String createBackup(String path, String backupPath, String fileNam } try { - BackupFileManager.removeTooOldBackupFiles(backupPath, fileName, limit); + BackupFileManager.removeTooOldBackupFiles(backupPath, name, limit); } catch (Exception exception) { log.warn("Old backup files could not be deleted. Please make sure that the required access rights are set."); if (createFrontendMessage) { @@ -111,7 +116,7 @@ public static String createBackup(String path, String backupPath, String fileNam // Code that calls this method should not get confused with this thrown exception in case of success... //throw new IOException(messageFail); (NOSONAR) } - return backupFileName; + return backupFileOrDirectoryName; } /** @@ -124,12 +129,12 @@ public static String createBackup(String path, String backupPath, String fileNam * @return The name of the created backup file or null in case of an error * @throws IOException if there was an error while creating the backup file */ - private static String createBackupFile(String sourcePath, String backupPath, String fileName) throws IOException { - Path existingFile = Paths.get(sourcePath + fileName); - String backupFileName = fileName + "." + BackupFileManager.getCurrentTimestamp(); - Path backupFile = Paths.get(backupPath + backupFileName); + private static String createBackup(String sourcePath, String backupPath, String fileName) throws IOException { + Path existingFileOrDirectory = Paths.get(sourcePath, fileName); + String backupName = fileName + "." + BackupFileManager.getCurrentTimestamp(); + Path backupFileOrDirectory = Paths.get(backupPath, backupName); - if (!StorageProvider.getInstance().isFileExists(existingFile)) { + if (!StorageProvider.getInstance().isFileExists(existingFileOrDirectory) && !StorageProvider.getInstance().isDirectory(existingFileOrDirectory)) { return null; } @@ -137,7 +142,7 @@ private static String createBackupFile(String sourcePath, String backupPath, Str if (!StorageProvider.getInstance().isFileExists(backupPathObject)) { try { StorageProvider.getInstance().createDirectories(backupPathObject); - log.debug("Created backup directory " + backupPath + backupFileName); + log.debug("Created backup directory " + backupPath + backupName); } catch (IOException ioException) { log.error("Error while creating backup directory " + backupPath); throw ioException; @@ -145,11 +150,15 @@ private static String createBackupFile(String sourcePath, String backupPath, Str } try { - StorageProvider.getInstance().copyFile(existingFile, backupFile); - log.debug("Created backup file " + backupPath + backupFileName); - return backupFileName; + if (StorageProvider.getInstance().isDirectory(existingFileOrDirectory)) { + StorageProvider.getInstance().copyDirectory(existingFileOrDirectory, backupFileOrDirectory, true); + } else { + StorageProvider.getInstance().copyFile(existingFileOrDirectory, backupFileOrDirectory); + } + log.debug("Created backup file " + backupPath + backupName); + return backupName; } catch (IOException ioException) { - log.error("Error while creating backup file " + backupPath + backupFileName); + log.error("Error while creating backup file " + backupPath + backupName); throw ioException; } } diff --git a/src/main/java/org/goobi/managedbeans/BatchBean.java b/src/main/java/org/goobi/managedbeans/BatchBean.java index 787525f070..0f6688eb79 100644 --- a/src/main/java/org/goobi/managedbeans/BatchBean.java +++ b/src/main/java/org/goobi/managedbeans/BatchBean.java @@ -72,8 +72,7 @@ public class BatchBean extends BasicBean implements Serializable { private static final long serialVersionUID = 8234897225425856549L; private static final String NO_BATCH_SELECTED = "noBatchSelected"; - // TODO: Rename this key so that it does not use an 'Ḿ' with accent - private static final String TOO_MANY_BATCHES_SELECTED = "tooḾanyBatchesSelected"; + private static final String TOO_MANY_BATCHES_SELECTED = "tooManyBatchesSelected"; private static final String DEFAULT_BATCH_NAME = "-batch-"; diff --git a/src/main/java/org/goobi/managedbeans/DatabasePaginator.java b/src/main/java/org/goobi/managedbeans/DatabasePaginator.java index c433173f9b..cbf7349516 100644 --- a/src/main/java/org/goobi/managedbeans/DatabasePaginator.java +++ b/src/main/java/org/goobi/managedbeans/DatabasePaginator.java @@ -128,13 +128,21 @@ public boolean isLastPage() { } public boolean hasNextPage() { - return this.results.size() > this.pageSize; + return !isLastPage(); } public boolean hasPreviousPage() { return this.page > 0; } + public String getHasPreviousPage() { + return hasPreviousPage() ? null : "disabled"; + } + + public String getHasNextPage() { + return hasNextPage() ? null : "disabled"; + } + public Long getPageNumberCurrent() { return Long.valueOf(this.page + 1l); } diff --git a/src/main/java/org/goobi/managedbeans/FormInputMultiSelectBean.java b/src/main/java/org/goobi/managedbeans/FormInputMultiSelectBean.java new file mode 100644 index 0000000000..f19e70f2b7 --- /dev/null +++ b/src/main/java/org/goobi/managedbeans/FormInputMultiSelectBean.java @@ -0,0 +1,13 @@ +package org.goobi.managedbeans; + +import javax.faces.model.SelectItem; +import java.util.List; + +public interface FormInputMultiSelectBean { + List getCurrentlySelectableItems(); + List getSelection(); + void setSelection(List selection); + String getCurrentSelection(); + void setCurrentSelection(String item); + void removeSelection(SelectItem selection); +} diff --git a/src/main/java/org/goobi/managedbeans/FormInputMultiSelectHelper.java b/src/main/java/org/goobi/managedbeans/FormInputMultiSelectHelper.java new file mode 100644 index 0000000000..b66ef20314 --- /dev/null +++ b/src/main/java/org/goobi/managedbeans/FormInputMultiSelectHelper.java @@ -0,0 +1,69 @@ +package org.goobi.managedbeans; + +import javax.faces.model.SelectItem; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.function.Consumer; +import java.util.function.Supplier; + +public class FormInputMultiSelectHelper implements FormInputMultiSelectBean { + private Supplier> all; + private Supplier> getter; + private Consumer> setter; + + public FormInputMultiSelectHelper(Supplier> all, Supplier> getter, Consumer> setter) { + this.all = all; + this.getter = getter; + this.setter = setter; + } + + @Override + public List getCurrentlySelectableItems() { + List currentlySelectable = new ArrayList<>(all.get()); + getSelection().forEach(selected -> currentlySelectable.removeIf(i -> i.getValue().equals(selected.getValue()))); + return currentlySelectable; + } + + @Override + public List getSelection() { + return this.getter.get(); + } + + @Override + public void setSelection(List selection) { + this.setter.accept(selection); + } + + @Override + public String getCurrentSelection() { + return null; + } + + @Override + public void setCurrentSelection(String item) { + if (item == null || item.isBlank()) { + return; + } + + Optional selectedItem = this.all.get().stream() + .filter(s -> s.getValue().equals(item)) + .findFirst(); + + if (selectedItem.isEmpty()) { + System.err.println("Unable to find selected item: " + item); + return; + } + + List selectedItems = getSelection(); + selectedItems.add(selectedItem.get()); + setSelection(selectedItems); + } + + @Override + public void removeSelection(SelectItem selection) { + List selectedItems = getSelection(); + selectedItems.removeIf(i -> i.getValue().equals(selection.getValue())); + setSelection(selectedItems); + } +} diff --git a/src/main/java/org/goobi/managedbeans/Paginator.java b/src/main/java/org/goobi/managedbeans/Paginator.java new file mode 100644 index 0000000000..13f1d449fa --- /dev/null +++ b/src/main/java/org/goobi/managedbeans/Paginator.java @@ -0,0 +1,43 @@ +package org.goobi.managedbeans; + +import java.util.List; + +public interface Paginator { + void reload(); + + void postLoad(T item); + + List getItems(); + + long getPageSize(); + + void setPageSize(long pageSize); + + long getCurrentPage(); + + void setCurrentPage(long currentPage); + + long getNumberOfPages(); + + long getTotalResults(); + + boolean hasPreviousPage(); + + boolean hasNextPage(); + + default String getHasPreviousPage() { + return hasPreviousPage() ? null : "disabled"; + } + + default String getHasNextPage() { + return hasNextPage() ? null : "disabled"; + } + + void cmdMoveFirst(); + + void cmdMoveLast(); + + void cmdMoveNext(); + + void cmdMovePrevious(); +} diff --git a/src/main/java/org/goobi/managedbeans/VocabularyBean.java b/src/main/java/org/goobi/managedbeans/VocabularyBean.java index db50146d7a..95310700fa 100644 --- a/src/main/java/org/goobi/managedbeans/VocabularyBean.java +++ b/src/main/java/org/goobi/managedbeans/VocabularyBean.java @@ -1,20 +1,20 @@ /** * This file is part of the Goobi Application - a Workflow tool for the support of mass digitization. - * + *

* Visit the websites for more information. - * - https://goobi.io - * - https://www.intranda.com - * - https://github.com/intranda/goobi-workflow - * + * - https://goobi.io + * - https://www.intranda.com + * - https://github.com/intranda/goobi-workflow + *

* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) any later version. - * + *

* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * + *

* You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 * Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + *

* Linking this library statically or dynamically with other modules is making a combined work based on this library. Thus, the terms and conditions * of the GNU General Public License cover the whole combination. As a special exception, the copyright holders of this library give you permission to * link this library with independent modules to produce an executable, regardless of the license terms of these independent modules, and to copy and @@ -25,939 +25,51 @@ */ package org.goobi.managedbeans; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.Serializable; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -import javax.faces.application.FacesMessage; -import javax.faces.component.UIComponent; -import javax.faces.context.FacesContext; -import javax.faces.event.ComponentSystemEvent; -import javax.faces.model.SelectItem; -import javax.faces.validator.ValidatorException; -import javax.inject.Named; -import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.csv.CSVFormat; -import org.apache.commons.csv.CSVPrinter; -import org.apache.commons.io.ByteOrderMark; -import org.apache.commons.io.input.BOMInputStream; -import org.apache.commons.lang3.StringUtils; -import org.apache.deltaspike.core.api.scope.WindowScoped; -import org.apache.poi.ss.usermodel.Cell; -import org.apache.poi.ss.usermodel.DataFormatter; -import org.apache.poi.ss.usermodel.Row; -import org.apache.poi.ss.usermodel.Sheet; -import org.apache.poi.ss.usermodel.Workbook; -import org.apache.poi.ss.usermodel.WorkbookFactory; -import org.apache.poi.ss.util.CellReference; -import org.apache.poi.xssf.usermodel.XSSFWorkbook; -import org.goobi.vocabulary.Definition; -import org.goobi.vocabulary.Field; -import org.goobi.vocabulary.VocabRecord; -import org.goobi.vocabulary.Vocabulary; -import org.goobi.vocabulary.VocabularyFieldValidator; -import org.goobi.vocabulary.VocabularyUploader; -import org.goobi.vocabulary.helper.ImportJsonVocabulary; -import org.primefaces.event.FileUploadEvent; -import org.primefaces.model.file.UploadedFile; - -import de.sub.goobi.helper.FacesContextHelper; import de.sub.goobi.helper.Helper; -import de.sub.goobi.persistence.managers.VocabularyManager; -import lombok.Data; +import io.goobi.workflow.api.vocabulary.APIException; +import io.goobi.workflow.api.vocabulary.VocabularyAPIManager; +import io.goobi.workflow.api.vocabulary.hateoas.HATEOASPaginator; +import io.goobi.workflow.api.vocabulary.hateoas.VocabularyPageResult; +import io.goobi.workflow.api.vocabulary.helper.APIExceptionExtractor; +import io.goobi.workflow.api.vocabulary.helper.ExtendedVocabulary; import lombok.Getter; -import lombok.NonNull; -import lombok.RequiredArgsConstructor; -import lombok.Setter; import lombok.extern.log4j.Log4j2; +import org.apache.deltaspike.core.api.scope.WindowScoped; + +import javax.inject.Named; +import java.io.Serializable; +import java.util.Optional; @Named @WindowScoped @Log4j2 -public class VocabularyBean extends BasicBean implements Serializable { - - private static final long serialVersionUID = -4591427229251805665L; - - private static final String RETURN_PAGE_ALL = "vocabulary_all"; - private static final String RETURN_PAGE_EDIT = "vocabulary_edit"; - private static final String RETURN_PAGE_RECORDS = "vocabulary_records"; - private static final String RETURN_PAGE_UPLOAD = "vocabulary_upload"; - - private static final String IMPORT_TYPE_MERGE = "merge"; - private static final String IMPORT_TYPE_ADD = "add"; - private static final String IMPORT_TYPE_REMOVE = "remove"; - - @Getter - @Setter - private Vocabulary currentVocabulary; - - @Getter - @Setter - private Definition currentDefinition; - - @Getter - private VocabRecord currentVocabRecord; - - //details up or down - @Getter - @Setter - private String uiStatus; - - @Getter - private String[] possibleDefinitionTypes = { "input", "textarea", "select", "select1", "html" }; +public class VocabularyBean implements Serializable { + private static final long serialVersionUID = 5672948572345L; - @Getter - @Setter - private transient Path importFile; - @Getter - private String filename; - - @Getter - private List headerOrder; - - @Getter - @Setter - private MatchingField selectedMatchingField; + private static final String RETURN_PAGE_OVERVIEW = "vocabulary_all"; - @Getter - private List allDefinitionNames; - - private transient List rowsToImport; + private static final VocabularyAPIManager api = VocabularyAPIManager.getInstance(); @Getter - @Setter - private String importType = IMPORT_TYPE_MERGE; - - private boolean resetResultsOnNextValidation = false; - - private List removedDefinitions = null; - private transient DataFormatter dataFormatter = new DataFormatter(); - - /** - * Constructor for class - */ - public VocabularyBean() { - uiStatus = "down"; - sortField = "title"; - } - - /** - * main method to start searching the records - * - * @return path to list records - */ - public String FilterKein() { - VocabularyManager vm = new VocabularyManager(); - paginator = new DatabasePaginator(sortField, filter, vm, RETURN_PAGE_ALL); - return RETURN_PAGE_ALL; - } - - /** - * method to go to the vocabulary edition area - * - * @return path to vocabulary edition area - */ - public String editVocabulary() { - removedDefinitions = new ArrayList<>(); - return RETURN_PAGE_EDIT; - } - - /** - * method to start editing the records - * - * @return path to list and edit records - */ - public String editRecords() { - // load records of selected vocabulary - // initial first page - VocabularyManager.getAllRecords(currentVocabulary); - currentVocabulary.runFilter(); - currentVocabulary.setTotalNumberOfRecords(currentVocabulary.getRecords().size()); - if (!currentVocabulary.getRecords().isEmpty()) { - currentVocabRecord = currentVocabulary.getRecords().get(0); - } else { - addRecord(); - } - return RETURN_PAGE_RECORDS; - } - - public String uploadToServerRecords() { - VocabularyManager.getAllRecords(currentVocabulary); - Boolean boOK = VocabularyUploader.upload(currentVocabulary); - if (Boolean.TRUE.equals(boOK)) { - Helper.setMeldung(Helper.getTranslation("ExportFinished")); - return RETURN_PAGE_ALL; - } else { - Helper.setFehlerMeldung(Helper.getTranslation("ExportError")); - return ""; - } - } - - /** - * start the edition of a new vocabulary - * - * @return path to vocabulary edition area - */ - public String newVocabulary() { - currentVocabulary = new Vocabulary(); - return editVocabulary(); - } - - /** - * method to save the vocabulary definitions - * - * @return path to the vocabulary listing - */ - public String saveVocabulary() { - int numberOfMainEntries = 0; - for (Definition def : currentVocabulary.getStruct()) { - if (def.isMainEntry()) { - numberOfMainEntries++; - } - } - - // check if one field is marked as main entry - if (numberOfMainEntries == 0) { - Helper.setFehlerMeldung(Helper.getTranslation("vocabularyManager_noMainEntry")); - return ""; - } else if (numberOfMainEntries > 1) { - Helper.setFehlerMeldung(Helper.getTranslation("vocabularyManager_wrongNumberOfMainEntries")); - return ""; - } - // check if title is unique - if (VocabularyManager.isTitleUnique(currentVocabulary)) { - VocabularyManager.saveVocabulary(currentVocabulary); - } else { - Helper.setFehlerMeldung(Helper.getTranslation("vocabularyManager_titleNotUnique")); - return ""; - } - for (Definition def : removedDefinitions) { - VocabularyManager.deleteDefinition(def); - } - - return cancelEdition(); - } - - /** - * method to to delete an existing vocabulary - * - * @return path to the vocabulary listing - */ - public String deleteVocabulary() { - if (currentVocabulary.getId() != null) { - VocabularyManager.deleteVocabulary(currentVocabulary); - } - return cancelEdition(); - } - - /** - * some cleanup and then go to overview page again - * - * @return path to vocabulary listing - */ - public String cancelEdition() { - if (removedDefinitions != null) { - removedDefinitions.clear(); - } - return FilterKein(); - } - - public void deleteDefinition() { - if (currentDefinition != null && currentVocabulary != null) { - currentVocabulary.getStruct().remove(currentDefinition); - removedDefinitions.add(currentDefinition); - } - } - - public void addDefinition() { - currentVocabulary.getStruct().add(new Definition()); - } - - public void addRecord() { - VocabRecord rec = new VocabRecord(); - List fieldList = new ArrayList<>(); - for (Definition definition : currentVocabulary.getStruct()) { - Field field = new Field(definition.getLabel(), definition.getLanguage(), "", definition); - fieldList.add(field); - } - rec.setFields(fieldList); - currentVocabulary.getRecords().add(rec); - currentVocabRecord = rec; - } - - public void deleteRecord() { - currentVocabulary.getRecords().remove(currentVocabRecord); - VocabularyManager.deleteRecord(currentVocabRecord); - editRecords(); - } - - public String cancelRecordEdition() { - return cancelEdition(); - } - - /** - * Stores the current vocabulary record in the database. The validation is done when the setters of the field values are called by JSF. The - * validation is not necessary here anymore. - */ - public void saveRecordEdition() { - - VocabularyManager.saveRecord(this.currentVocabulary.getId(), this.currentVocabRecord); - - // editRecords() reloads the list in the left vocabulary record menu. The id must be stored to keep the current record selected because the - // object reference gets lost during the reload - int id = this.currentVocabRecord.getId(); - this.editRecords(); - this.setCurrentVocabRecord(this.getVocabRecordById(id)); - } - - /** - * probably unneeded reload method to stay on the same page - */ - public void Reload() { - - } - - /** - * create an excel result and send it to the response output stream - */ - public void downloadRecords() { - VocabularyManager.getAllRecords(currentVocabulary); - String title = currentVocabulary.getTitle(); - List definitionList = currentVocabulary.getStruct(); - List recordList = currentVocabulary.getRecords(); - - List headers = new ArrayList<>(); - - for (Definition definition : definitionList) { - headers.add(StringUtils.isNotBlank(definition.getLanguage()) ? definition.getLabel() + " (" + definition.getLanguage() + ")" - : definition.getLabel()); - } - StringBuilder sw = new StringBuilder(); - CSVFormat csvFormat = CSVFormat.DEFAULT.builder().setHeader(headers.toArray(new String[headers.size()])).build(); - try (final CSVPrinter printer = new CSVPrinter(sw, csvFormat)) { - for (VocabRecord vocabRecord : recordList) { - List values = new ArrayList<>(); - for (Definition definition : definitionList) { - values.add(vocabRecord.getFieldValue(definition)); - } - printer.printRecord(values.toArray()); - - } - } catch (IOException e1) { - log.error(e1); - } - - // write result into output stream - FacesContext facesContext = FacesContextHelper.getCurrentFacesContext(); - - HttpServletResponse response = (HttpServletResponse) facesContext.getExternalContext().getResponse(); - OutputStream out; - try { - out = response.getOutputStream(); - response.setContentType("text/csv"); - response.setHeader("Content-Disposition", "attachment;filename=\"" + title + ".csv\""); - - out.write(sw.toString().getBytes(StandardCharsets.UTF_8)); - - out.flush(); + private transient Paginator paginator; - facesContext.responseComplete(); - } catch (IOException e) { - log.error(e); - } - } - - public void downloadRecordsExcel() { - VocabularyManager.getAllRecords(currentVocabulary); - String title = currentVocabulary.getTitle(); - String description = currentVocabulary.getDescription(); - List definitionList = currentVocabulary.getStruct(); - List recordList = currentVocabulary.getRecords(); - - Workbook wb = new XSSFWorkbook(); - Sheet sheet = wb.createSheet((StringUtils.isBlank(description) ? title : title + " - " + description).replace("/", "")); - - // create header - Row headerRow = sheet.createRow(0); - int columnCounter = 0; - for (Definition definition : definitionList) { - headerRow.createCell(columnCounter) - .setCellValue(StringUtils.isNotBlank(definition.getLanguage()) ? definition.getLabel() + " (" + definition.getLanguage() + ")" - : definition.getLabel()); - columnCounter = columnCounter + 1; - } - - int rowCounter = 1; - // add records - for (VocabRecord rec : recordList) { - Row resultRow = sheet.createRow(rowCounter); - columnCounter = 0; - for (Definition definition : definitionList) { - resultRow.createCell(columnCounter).setCellValue(rec.getFieldValue(definition)); - columnCounter = columnCounter + 1; - } - rowCounter = rowCounter + 1; - } - - // write result into output stream - FacesContext facesContext = FacesContextHelper.getCurrentFacesContext(); - - HttpServletResponse response = (HttpServletResponse) facesContext.getExternalContext().getResponse(); - OutputStream out; - try { - out = response.getOutputStream(); - response.setContentType("application/vnd.ms-excel"); - response.setHeader("Content-Disposition", "attachment;filename=\"" + title + ".xlsx\""); - wb.write(out); - out.flush(); - - facesContext.responseComplete(); - } catch (IOException e) { - log.error(e); - } - try { - wb.close(); - } catch (IOException e) { - log.error(e); - } - } - - /** - * allow file upload for vocabulary records - * - * @param event - */ - public void handleFileUpload(FileUploadEvent event) { - try { - UploadedFile upload = event.getFile(); - copyFile(upload.getFileName(), upload.getInputStream()); - loadUploadedFile(); - } catch (IOException e) { - log.error("Error while uploading files", e); - } - } - - /** - * internal method to manage the file upload for vocabulary records - */ - private void loadUploadedFile() { - InputStream file = null; - - if (importFile.getFileName().toString().endsWith(".json")) { - - List records = ImportJsonVocabulary.convertJsonVocabulary(currentVocabulary, importFile); - VocabularyManager.saveVocabulary(currentVocabulary); - VocabularyManager.insertNewRecords(records, currentVocabulary.getId()); - - Helper.setMeldung("Imported records: " + records.size()); - - } else { - - try { - log.debug("Importing file {}", importFile.toString()); - try (BOMInputStream in = BOMInputStream.builder() - .setPath(importFile) - .setByteOrderMarks(ByteOrderMark.UTF_8) - .setInclude(false) - .get(); - Workbook wb = WorkbookFactory.create(in)) { - - Sheet sheet = wb.getSheetAt(0); - Iterator rowIterator = sheet.rowIterator(); - Row headerRow = rowIterator.next(); - int numberOfCells = headerRow.getLastCellNum(); - headerOrder = new ArrayList<>(numberOfCells); - log.debug("Found {} cell(s)", numberOfCells); - - rowsToImport = new LinkedList<>(); - for (int i = 0; i < numberOfCells; i++) { - Cell cell = headerRow.getCell(i); - if (cell != null) { - String value = dataFormatter.formatCellValue(cell).trim(); - headerOrder.add(new MatchingField(value, i, CellReference.convertNumToColString(i), this)); - } - } - log.debug("read header"); - while (rowIterator.hasNext()) { - Row row = rowIterator.next(); - rowsToImport.add(row); - } - log.debug("Found {} rows to import", rowsToImport.size()); - for (MatchingField mf : headerOrder) { - String excelTitle = mf.getColumnHeader(); - if (excelTitle.matches(".*\\(.{3}\\)")) { - String titlePart = excelTitle.substring(0, excelTitle.lastIndexOf("(")).trim(); - String languagePart = excelTitle.substring(excelTitle.lastIndexOf("(") + 1, excelTitle.lastIndexOf(")")).trim(); - for (Definition def : currentVocabulary.getStruct()) { - if (def.getLabel().equals(titlePart) && def.getLanguage().equals(languagePart)) { - mf.setAssignedField(def); - } - } - } else { - String titlePart = excelTitle.trim(); - for (Definition def : currentVocabulary.getStruct()) { - if (def.getLabel().equals(titlePart) && StringUtils.isBlank(def.getLanguage())) { - mf.setAssignedField(def); - } - } - } - } - } - } catch (Exception e) { - Helper.setFehlerMeldung("file not readable", e); - log.error(e); - } finally { - if (file != null) { - try { - file.close(); - } catch (IOException e) { - log.error(e); - } - } - } - } - } - - public void copyFile(String fileName, InputStream in) { - OutputStream out = null; + public String load() { try { - String extension = fileName.substring(fileName.indexOf(".")); - importFile = Files.createTempFile(fileName, extension); // NOSONAR, temp file is save to use - out = new FileOutputStream(importFile.toFile()); - int read = 0; - byte[] bytes = new byte[1024]; - while ((read = in.read(bytes)) != -1) { - out.write(bytes, 0, read); - } - out.flush(); - } catch (IOException e) { - log.error(e); - } finally { - if (in != null) { - try { - in.close(); - } catch (IOException e) { - log.error(e); - } - } - if (out != null) { - try { - out.close(); - } catch (IOException e) { - log.error(e); - } - } - } - } - - /** - * navigate to the excel upload area - * - * @return path to the excel upload area - */ - public String uploadRecords() { - VocabularyManager.getAllRecords(currentVocabulary); - allDefinitionNames = new ArrayList<>(); - allDefinitionNames.add(new SelectItem("", "-")); - for (Definition definition : currentVocabulary.getStruct()) { - String definitionName; - if (StringUtils.isNotBlank(definition.getLanguage())) { - definitionName = definition.getLabel() + " (" + definition.getLanguage() + ")"; - } else { - definitionName = definition.getLabel(); - } - allDefinitionNames.add(new SelectItem(definitionName, definitionName)); + paginator = new HATEOASPaginator<>( + VocabularyPageResult.class, + api.vocabularies().list( + Optional.of(Helper.getLoginBean().getMyBenutzer().getTabellengroesse()), + Optional.empty() + ), + null, + null, + api.vocabularies()::get + ); + return RETURN_PAGE_OVERVIEW; + } catch (APIException e) { + APIExceptionExtractor extractor = new APIExceptionExtractor(e); + Helper.setFehlerMeldung(extractor.getLocalizedMessage(Helper.getSessionLocale())); + return "index"; } - - headerOrder = null; - filename = null; - importFile = null; - return RETURN_PAGE_UPLOAD; - } - - /** - * Checks if the assigned field is used in a different {@link MatchingField}. If this is the case, the other assignment is removed - * - * @param currentField - */ - private void updateFieldList(MatchingField currentField) { - for (MatchingField other : headerOrder) { - if (!other.equals(currentField) && other.getAssignedField() != null - && other.getCurrentDefinition().equals(currentField.getCurrentDefinition())) { - other.setAssignedField(null); - } - } - } - - /** - * Import the records from the excel file. First all old records are deleted, then for each row a new record is created. The fields are filled - * based on the configured {@link MatchingField}s - * - * @return - */ - public String importRecords() { - if (IMPORT_TYPE_REMOVE.equals(importType)) { - // if selected, remove existing entries of this vocabulary - VocabularyManager.deleteAllRecords(currentVocabulary); - currentVocabulary.setRecords(new ArrayList<>()); - } - if (IMPORT_TYPE_REMOVE.equals(importType) || IMPORT_TYPE_ADD.equals(importType)) { - List recordsToAdd = new ArrayList<>(rowsToImport.size()); - for (Row row : rowsToImport) { - VocabRecord vocabRecord = new VocabRecord(); - List fieldList = new ArrayList<>(); - for (MatchingField mf : headerOrder) { - if (mf.getAssignedField() != null) { - String cellValue = getCellValue(row.getCell(mf.getColumnOrderNumber())); - if (StringUtils.isNotBlank(cellValue)) { - Field field = new Field(mf.getAssignedField().getLabel(), mf.getAssignedField().getLanguage(), cellValue, - mf.getAssignedField()); - fieldList.add(field); - } - } - } - if (!fieldList.isEmpty()) { - recordsToAdd.add(vocabRecord); - log.debug("Created record"); - addFieldToRecord(vocabRecord, fieldList); - } - } - VocabularyManager.insertNewRecords(recordsToAdd, currentVocabulary.getId()); - String message = String.format("Stored %s new records", recordsToAdd.size()); - log.debug(message); - Helper.setMeldung(message); - } - - if (IMPORT_TYPE_MERGE.equals(importType)) { - List newRecords = new ArrayList<>(); - List updateRecords = new ArrayList<>(); - // get main entry row - Integer mainEntryColumnNumber = null; - Integer mainEntryDefinitionId = null; - for (MatchingField mf : headerOrder) { - if (mf.getAssignedField() != null && mf.getAssignedField().isMainEntry()) { - mainEntryColumnNumber = mf.getColumnOrderNumber(); - mainEntryDefinitionId = mf.getAssignedField().getId(); - } - } - - if (mainEntryColumnNumber != null) { - Map existingRecords = new HashMap<>(); - for (VocabRecord vr : currentVocabulary.getRecords()) { - for (Field f : vr.getFields()) { - if (f.getDefinitionId().equals(mainEntryDefinitionId)) { - existingRecords.put(f.getValue(), vr); - - break; - } - } - } - - for (Row row : rowsToImport) { - // search for existing records based on the value of the main entry - - String uniqueIdentifierEntry = getCellValue(row.getCell(mainEntryColumnNumber)); - if (StringUtils.isNotBlank(uniqueIdentifierEntry)) { - VocabRecord recordToUpdate = existingRecords.get(uniqueIdentifierEntry); - if (recordToUpdate != null) { - boolean updated = false; - // existing record, change it - log.debug("merged row with existing record"); - // update existing record - for (MatchingField mf : headerOrder) { - if (mf.getAssignedField() != null) { - Field fieldToUpdate = null; - for (Field field : recordToUpdate.getFields()) { - if (field.getDefinition() != null && mf.getAssignedField().equals(field.getDefinition())) { - fieldToUpdate = field; - break; - } - } - String cellValue = getCellValue(row.getCell(mf.getColumnOrderNumber())); - if (fieldToUpdate == null) { - fieldToUpdate = new Field(mf.getAssignedField().getLabel(), mf.getAssignedField().getLanguage(), cellValue, - mf.getAssignedField()); - recordToUpdate.getFields().add(fieldToUpdate); - updated = true; - } else if (!fieldToUpdate.getValue().equals(cellValue)) { - fieldToUpdate.setValue(cellValue); - updated = true; - } - } - } - if (updated) { - updateRecords.add(recordToUpdate); - } - } else { - // create new record - log.debug("create new record."); - VocabRecord vocabRecord = new VocabRecord(); - List fieldList = new ArrayList<>(); - for (MatchingField mf : headerOrder) { - if (mf.getAssignedField() != null) { - String cellValue = getCellValue(row.getCell(mf.getColumnOrderNumber())); - if (StringUtils.isNotBlank(cellValue)) { - Field field = new Field(mf.getAssignedField().getLabel(), mf.getAssignedField().getLanguage(), cellValue, - mf.getAssignedField()); - fieldList.add(field); - } - - } - } - if (!fieldList.isEmpty()) { - addFieldToRecord(vocabRecord, fieldList); - newRecords.add(vocabRecord); - } - } - } - } - } - - if (!newRecords.isEmpty()) { - String message = String.format("Created %s new record(s)", newRecords.size()); - log.debug(message); - Helper.setMeldung(message); - VocabularyManager.insertNewRecords(newRecords, currentVocabulary.getId()); - } - if (!updateRecords.isEmpty()) { - String message = String.format("Updated %s record(s)", updateRecords.size()); - log.debug(message); - Helper.setMeldung(message); - VocabularyManager.batchUpdateRecords(updateRecords, currentVocabulary.getId()); - } - } - return editRecords(); - } - - /** - * method to add a field to the existing record - * - * @param vocabRecord Record to use - * @param fieldList List of fields to add to the record - */ - private void addFieldToRecord(VocabRecord vocabRecord, List fieldList) { - for (Definition def : currentVocabulary.getStruct()) { - boolean fieldExists = false; - for (Field f : fieldList) { - if (def.getId().equals(f.getDefinition().getId())) { - fieldExists = true; - break; - } - } - if (!fieldExists) { - Field emptyField = new Field(def.getLabel(), def.getLanguage(), "", def); - fieldList.add(emptyField); - } - } - vocabRecord.setFields(fieldList); - currentVocabulary.getRecords().add(vocabRecord); - } - - /** - * If true, allow uploading of the vocabularies - * - * @return - */ - public Boolean useAuthorityServer() { - return VocabularyUploader.isActive(); - } - - /** - * returns the value of the current cell as string - */ - private String getCellValue(Cell cell) { - String value = ""; - if (cell != null) { - value = dataFormatter.formatCellValue(cell).trim(); - } - return value; - } - - /** - * This class is used to match the excel columns and the vocabulary fields - */ - @Data - @RequiredArgsConstructor - public class MatchingField implements Serializable { - - private static final long serialVersionUID = 7037009721345445066L; - - /** - * Name of the header of the current column within the excel file - */ - @NonNull - private String columnHeader; - - /** - * Internal order number of the current column within the excel file - */ - @NonNull - private Integer columnOrderNumber; - - /** - * Displayed label the current column within the excel file (1=A, 2=B, 3=C, ...) - */ - @NonNull - private String columnLetter; - - /** - * Reference to the managed bean - */ - @NonNull - private VocabularyBean bean; - - /** - * field in which the current data is imported - */ - private Definition assignedField; - - /** - * Creates a label to identify the assigned field - * - * @return - */ - public String getCurrentDefinition() { - if (assignedField == null) { - return "-"; - } - String definitionName; - if (StringUtils.isNotBlank(assignedField.getLanguage())) { - definitionName = assignedField.getLabel() + " (" + assignedField.getLanguage() + ")"; - } else { - definitionName = assignedField.getLabel(); - } - return definitionName; - } - - /** - * Set the assigned field based on the selected label. If a new field is set, all other fields are checked if the current field was already - * selected. If this is the case, the selection is removed from the other field - * - * @param value - */ - public void setCurrentDefinition(String value) { - - if (StringUtils.isNotBlank(value) && !"-".equals(value)) { - if (value.matches(".*\\(.*\\)")) { //NOSONAR, regex is not vulnerable to backtracking - String titlePart = value.substring(0, value.lastIndexOf("(")).trim(); - String languagePart = value.substring(value.lastIndexOf("(") + 1, value.lastIndexOf(")")).trim(); - for (Definition def : currentVocabulary.getStruct()) { - if (def.getLabel().equals(titlePart) && def.getLanguage().equals(languagePart)) { - assignedField = def; - break; - } - } - } else { - for (Definition def : currentVocabulary.getStruct()) { - if (def.getLabel().equals(value) && StringUtils.isBlank(def.getLanguage())) { - assignedField = def; - } - } - } - bean.updateFieldList(this); - } else { - assignedField = null; - } - } - } - - /** - * method to set the current record to use - * - * @param currentVocabRecord the record to use - */ - public void setCurrentVocabRecord(VocabRecord currentVocabRecord) { - - // Set records to valid because validation errors are discarded - for (VocabRecord vocabRecord : this.currentVocabulary.getRecords()) { - vocabRecord.setValid(true); - } - - this.currentVocabRecord = currentVocabRecord; - } - - /** - * Returns the vocabulary record from the current vocabulary list with the given id. The advantage of this method in contrast to the one of the - * mysql-helper is that this method returns the same object and not an equal object. If the object can be found, the vocabulary record with that - * id is returned. Otherwise, null is returned. - * - * @param id The id of the required vocabulary record - * @return The vocabulary record or null if it could not be found - */ - private VocabRecord getVocabRecordById(int id) { - for (VocabRecord vocabulary : this.currentVocabulary.getRecords()) { - if (vocabulary.getId() == id) { - return vocabulary; - } - } - return null; - } - - public void validateFieldValue(FacesContext context, UIComponent component, Object value) throws ValidatorException { - - synchronized (this) { - // This boolean flag is set to true when the page (and the input form) is reloaded. This makes it possible - // to reset the validation results on the first executed validation of the current submit-trial - if (this.resetResultsOnNextValidation) { - // Only the invalid records should be set to 'valid=false' later - for (VocabRecord currentRecord : this.currentVocabulary.getRecords()) { - currentRecord.setValid(true); - } - this.resetResultsOnNextValidation = false; - } - } - - // Collect some data about the current state of the frontend: - // Get information about the field that should be set: - java.util.Map map = component.getAttributes(); - - String label = (String) (map.get("idForValidator")); - Field field = this.currentVocabRecord.getFieldByLabel(label); - - String type = field.getDefinition().getType(); - String valueThatShouldBeSet; - if (value == null || "null".equals(value)) { - valueThatShouldBeSet = ""; - } else // This is multiselect -> requires a string array - if ("select".equals(type)) { - String[] array = (String[]) (value); - valueThatShouldBeSet = String.join("|", array); - } else { - valueThatShouldBeSet = value.toString().trim(); - } - - // Validate the currently set record: - boolean success = - VocabularyFieldValidator.validateFieldInRecords(this.currentVocabulary, this.currentVocabRecord, field, valueThatShouldBeSet); - if (!success) { - String errorMessageKey = field.getValidationMessage(); - String translation = Helper.getTranslation(errorMessageKey); - FacesMessage message = new FacesMessage(translation, translation); - message.setSeverity(FacesMessage.SEVERITY_ERROR); - throw new ValidatorException(message); - } - } - - /** - * This method is called when the vocabulary record edit-fields are displayed. This function resets the validation results when the table is - * reloaded. After that, the validation of all different vocabulary-record-fields can be executed independently and the union set of all results - * (errors) can be cached without getting cached errors of the previous validation. - * - * @param event The event object - */ - public void resetValidationResults(ComponentSystemEvent event) { - this.resetResultsOnNextValidation = true; } } diff --git a/src/main/java/org/goobi/managedbeans/VocabularyEditBean.java b/src/main/java/org/goobi/managedbeans/VocabularyEditBean.java new file mode 100644 index 0000000000..d59979beaa --- /dev/null +++ b/src/main/java/org/goobi/managedbeans/VocabularyEditBean.java @@ -0,0 +1,117 @@ +/** + * This file is part of the Goobi Application - a Workflow tool for the support of mass digitization. + *

+ * Visit the websites for more information. + * - https://goobi.io + * - https://www.intranda.com + * - https://github.com/intranda/goobi-workflow + *

+ * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + *

+ * Linking this library statically or dynamically with other modules is making a combined work based on this library. Thus, the terms and conditions + * of the GNU General Public License cover the whole combination. As a special exception, the copyright holders of this library give you permission to + * link this library with independent modules to produce an executable, regardless of the license terms of these independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that you also meet, for each linked independent module, the terms and + * conditions of the license of that module. An independent module is a module which is not derived from or based on this library. If you modify this + * library, you may extend this exception to your version of the library, but you are not obliged to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ +package org.goobi.managedbeans; + +import de.sub.goobi.helper.Helper; +import io.goobi.vocabulary.exchange.Vocabulary; +import io.goobi.vocabulary.exchange.VocabularySchema; +import io.goobi.workflow.api.vocabulary.APIException; +import io.goobi.workflow.api.vocabulary.VocabularyAPIManager; +import io.goobi.workflow.api.vocabulary.helper.APIExceptionExtractor; +import io.goobi.workflow.api.vocabulary.helper.ExtendedVocabularyRecord; +import lombok.Getter; +import lombok.extern.log4j.Log4j2; +import org.apache.deltaspike.core.api.scope.WindowScoped; + +import javax.inject.Inject; +import javax.inject.Named; +import java.io.Serializable; +import java.util.Locale; + +@Named +@WindowScoped +@Log4j2 +public class VocabularyEditBean implements Serializable { + private static final long serialVersionUID = 5672948572345L; + + private static final String RETURN_PAGE_EDIT = "vocabulary_edit"; + + private static final VocabularyAPIManager api = VocabularyAPIManager.getInstance(); + + @Getter + private Vocabulary vocabulary; + @Getter + private VocabularySchema metadataSchema; + @Getter + private ExtendedVocabularyRecord metadataRecord; + + @Inject + private VocabularyBean vocabularyBean; + + + public String load(Vocabulary vocabulary) { + this.vocabulary = vocabulary; + + loadMetadata(); + + return RETURN_PAGE_EDIT; + } + + private void loadMetadata() { + if (vocabulary.getMetadataSchemaId() == null) { + this.metadataSchema = null; + this.metadataRecord = null; + return; + } + + this.metadataSchema = api.vocabularySchemas().get(vocabulary.getMetadataSchemaId()); + this.metadataRecord = api.vocabularyRecords().getMetadata(vocabulary.getId()); + } + + public String saveVocabulary() { + api.vocabularies().change(vocabulary); + if (metadataRecord != null) { + Long recordId = metadataRecord.getId(); + try { + api.vocabularyRecords().save(metadataRecord); + } catch (APIException e) { + APIExceptionExtractor extractor = new APIExceptionExtractor(e); + Helper.setFehlerMeldung(extractor.getLocalizedMessage(Helper.getSessionLocale())); + metadataRecord.setId(recordId); + metadataRecord.setVocabularyId(vocabulary.getId()); + metadataRecord.setMetadata(true); + metadataRecord = new ExtendedVocabularyRecord(metadataRecord); + return ""; + } + } + return cancel(); + } + + public String deleteVocabulary() { + try { + api.vocabularies().delete(vocabulary); + } catch (APIException e) { + APIExceptionExtractor extractor = new APIExceptionExtractor(e); + Helper.setFehlerMeldung(extractor.getLocalizedMessage(Helper.getSessionLocale())); + return ""; + } + return cancel(); + } + + public String cancel() { + return vocabularyBean.load(); + } +} diff --git a/src/main/java/org/goobi/managedbeans/VocabularyRecordsBean.java b/src/main/java/org/goobi/managedbeans/VocabularyRecordsBean.java new file mode 100644 index 0000000000..0f48b38315 --- /dev/null +++ b/src/main/java/org/goobi/managedbeans/VocabularyRecordsBean.java @@ -0,0 +1,215 @@ +/** + * This file is part of the Goobi Application - a Workflow tool for the support of mass digitization. + *

+ * Visit the websites for more information. + * - https://goobi.io + * - https://www.intranda.com + * - https://github.com/intranda/goobi-workflow + *

+ * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + *

+ * Linking this library statically or dynamically with other modules is making a combined work based on this library. Thus, the terms and conditions + * of the GNU General Public License cover the whole combination. As a special exception, the copyright holders of this library give you permission to + * link this library with independent modules to produce an executable, regardless of the license terms of these independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that you also meet, for each linked independent module, the terms and + * conditions of the license of that module. An independent module is a module which is not derived from or based on this library. If you modify this + * library, you may extend this exception to your version of the library, but you are not obliged to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ +package org.goobi.managedbeans; + +import de.sub.goobi.helper.Helper; +import io.goobi.vocabulary.exchange.FieldDefinition; +import io.goobi.vocabulary.exchange.VocabularyRecord; +import io.goobi.vocabulary.exchange.VocabularySchema; +import io.goobi.workflow.api.vocabulary.APIException; +import io.goobi.workflow.api.vocabulary.VocabularyAPIManager; +import io.goobi.workflow.api.vocabulary.hateoas.HATEOASPaginator; +import io.goobi.workflow.api.vocabulary.hateoas.VocabularyRecordPageResult; +import io.goobi.workflow.api.vocabulary.helper.APIExceptionExtractor; +import io.goobi.workflow.api.vocabulary.helper.ExtendedVocabulary; +import io.goobi.workflow.api.vocabulary.helper.ExtendedVocabularyRecord; +import lombok.Getter; +import lombok.Setter; +import lombok.extern.log4j.Log4j2; +import org.apache.deltaspike.core.api.scope.WindowScoped; + +import javax.inject.Named; +import javax.servlet.http.Part; +import java.io.Serializable; +import java.util.Comparator; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +@Named +@WindowScoped +@Log4j2 +public class VocabularyRecordsBean implements Serializable { + private static final long serialVersionUID = 5672948572345L; + + private static final String RETURN_PAGE_OVERVIEW = "vocabulary_records"; + private static final String RETURN_PAGE_UPLOAD = "vocabulary_upload"; + + private static final VocabularyAPIManager api = VocabularyAPIManager.getInstance(); + + @Getter + private transient HATEOASPaginator paginator; + @Getter + private transient ExtendedVocabulary vocabulary; + private transient VocabularySchema schema; + @Getter + private transient ExtendedVocabularyRecord currentRecord; + @Getter + private transient List titleFields; + @Getter + @Setter + private Part uploadedFile; + @Getter + @Setter + private boolean clearBeforeImport; + + public String load(ExtendedVocabulary vocabulary) { + this.vocabulary = vocabulary; + + loadSchema(); + loadPaginator(); + loadFirstRecord(); + + return RETURN_PAGE_OVERVIEW; + } + + private void loadPaginator() { + // TODO: Unclean to have static Helper access to user here.. + this.paginator = new HATEOASPaginator<>( + VocabularyRecordPageResult.class, + api.vocabularyRecords() + .list(this.vocabulary.getId()) + .pageSize(Optional.of(Helper.getLoginBean().getMyBenutzer().getTabellengroesse())) + .request(), + ExtendedVocabularyRecord::getChildren, + ExtendedVocabularyRecord::getParentId, + api.vocabularyRecords()::get + ); + } + + private void loadSchema() { + this.schema = api.vocabularySchemas().get(this.vocabulary.getSchemaId()); + this.titleFields = this.schema.getDefinitions().stream() + .filter(d -> Boolean.TRUE.equals(d.getTitleField())) + .sorted(Comparator.comparing(FieldDefinition::getId)) + .collect(Collectors.toList()); + } + + private void loadFirstRecord() { + // TODO: Fix if empty + if (!this.paginator.getItems().isEmpty()) { + edit(this.paginator.getItems().get(0)); + } else { + createEmpty(null); + } + } + + public void reload() { + paginator.reload(); + loadFirstRecord(); + } + + public void edit(ExtendedVocabularyRecord record) { + this.currentRecord = record; + paginator.postLoad(record); + } + + public void createEmpty(Long parentId) { + this.currentRecord = api.vocabularyRecords().createEmptyRecord(this.vocabulary.getId(), parentId, false); + } + + public void deleteRecord(VocabularyRecord rec) { + try { + api.vocabularyRecords().delete(rec); + paginator.reload(); + loadFirstRecord(); + } catch (APIException e) { + APIExceptionExtractor extractor = new APIExceptionExtractor(e); + Helper.setFehlerMeldung(extractor.getLocalizedMessage(Helper.getSessionLocale())); + } + } + + public void saveRecord(VocabularyRecord rec) { + long vocabularyId = rec.getVocabularyId(); + try { + ExtendedVocabularyRecord newRecord = api.vocabularyRecords().save(rec); + paginator.reload(); + ExtendedVocabularyRecord newExtendedRecord = paginator.getItems().stream() + .filter(r -> r.getId().equals(newRecord.getId())) + .findFirst() + .orElse(newRecord); + paginator.postLoad(newExtendedRecord); + edit(newExtendedRecord); + } catch (APIException e) { + APIExceptionExtractor extractor = new APIExceptionExtractor(e); + Helper.setFehlerMeldung(extractor.getLocalizedMessage(Helper.getSessionLocale())); + // Reset vocabulary id (got cleared during save) + rec.setVocabularyId(vocabularyId); + this.currentRecord = new ExtendedVocabularyRecord(rec); + } + } + + public String uploadRecords() { + return RETURN_PAGE_UPLOAD; + } + + public String importRecords() { + if (uploadedFile == null) { + return ""; + } + String fileExtension = uploadedFile.getSubmittedFileName().substring(uploadedFile.getSubmittedFileName().lastIndexOf(".")); + switch (fileExtension) { + case ".csv": + if (clearBeforeImport) { + api.vocabularies().cleanImportCsv(this.vocabulary.getId(), uploadedFile); + } else { + api.vocabularies().importCsv(this.vocabulary.getId(), uploadedFile); + } + break; + case ".xlsx": + if (clearBeforeImport) { + api.vocabularies().cleanImportExcel(this.vocabulary.getId(), uploadedFile); + } else { + api.vocabularies().importExcel(this.vocabulary.getId(), uploadedFile); + } + break; + default: + throw new IllegalArgumentException("Unrecognized file type: \"" + fileExtension + "\""); + } + + return load(this.vocabulary); + } + + public void expandRecord(ExtendedVocabularyRecord record) { + this.paginator.expand(record); + } + + public void collapseRecord(ExtendedVocabularyRecord record) { + this.paginator.collapse(record); + } + + public boolean isExpanded(ExtendedVocabularyRecord record) { + return this.paginator.isExpanded(record); + } + + public boolean isHierarchical() { + return Boolean.TRUE.equals(this.schema.getHierarchicalRecords()); + } + + public boolean isRootRecordCreationPossible() { + return Boolean.FALSE.equals(this.schema.getSingleRootElement()) || this.paginator.getTotalResults() == 0L; + } +} diff --git a/src/main/java/org/goobi/production/flow/helper/SearchResultHelper.java b/src/main/java/org/goobi/production/flow/helper/SearchResultHelper.java index 73d72bd31d..b72a2fe18d 100644 --- a/src/main/java/org/goobi/production/flow/helper/SearchResultHelper.java +++ b/src/main/java/org/goobi/production/flow/helper/SearchResultHelper.java @@ -87,6 +87,9 @@ public SearchResultHelper() { String processSortHelperMetadata = "prozesse.sortHelperMetadata"; possibleColumns.add(new SelectItem(processSortHelperMetadata, Helper.getTranslation(processSortHelperMetadata))); + String processSortHelperDocstructs = "prozesse.sortHelperDocstructs"; + possibleColumns.add(new SelectItem(processSortHelperDocstructs, Helper.getTranslation(processSortHelperDocstructs))); + String projectTitle = "projekte.Titel"; possibleColumns.add(new SelectItem(projectTitle, Helper.getTranslation(projectTitle))); diff --git a/src/main/java/org/goobi/production/properties/IProperty.java b/src/main/java/org/goobi/production/properties/IProperty.java index 98989fe664..c48ea5fc0f 100644 --- a/src/main/java/org/goobi/production/properties/IProperty.java +++ b/src/main/java/org/goobi/production/properties/IProperty.java @@ -72,6 +72,10 @@ public interface IProperty { public Date getDateValue(); + public abstract String getPattern(); + + public abstract void setPattern(String pattern); + public abstract IProperty getClone(int containerNumber); public abstract void transfer(); diff --git a/src/main/java/org/goobi/production/properties/ImportProperty.java b/src/main/java/org/goobi/production/properties/ImportProperty.java index 9b30f665ce..5351da5434 100644 --- a/src/main/java/org/goobi/production/properties/ImportProperty.java +++ b/src/main/java/org/goobi/production/properties/ImportProperty.java @@ -63,6 +63,9 @@ public class ImportProperty implements IProperty { @Getter @Setter private boolean required = false; + @Getter + @Setter + private String pattern = "dd.MM.yyyy"; public ImportProperty() { this.possibleValues = new ArrayList<>(); @@ -127,7 +130,7 @@ public void setValueList(List valueList) { } public boolean getBooleanValue() { - return this.value.equalsIgnoreCase("true"); + return "true".equalsIgnoreCase(this.value); } public void setBooleanValue(boolean val) { @@ -140,13 +143,13 @@ public void setBooleanValue(boolean val) { @Override public void setDateValue(Date inDate) { - SimpleDateFormat format = new SimpleDateFormat("dd.MM.yyyy"); + SimpleDateFormat format = new SimpleDateFormat(pattern); value = format.format(inDate); } @Override public Date getDateValue() { - SimpleDateFormat format = new SimpleDateFormat("dd.MM.yyyy"); + SimpleDateFormat format = new SimpleDateFormat(pattern); try { Calendar cal = Calendar.getInstance(); cal.setTime(format.parse(value)); diff --git a/src/main/java/org/goobi/production/properties/ProcessProperty.java b/src/main/java/org/goobi/production/properties/ProcessProperty.java index 0df8005cba..1ec5325375 100644 --- a/src/main/java/org/goobi/production/properties/ProcessProperty.java +++ b/src/main/java/org/goobi/production/properties/ProcessProperty.java @@ -88,6 +88,9 @@ public class ProcessProperty implements IProperty, Serializable { @Getter @Setter private boolean duplicationAllowed = false; + @Getter + @Setter + private String pattern = "dd.MM.yyyy"; public ProcessProperty() { this.possibleValues = new ArrayList<>(); @@ -109,14 +112,14 @@ public void setValue(String value) { @Override public void setDateValue(Date inDate) { - SimpleDateFormat format = new SimpleDateFormat("dd.MM.yyyy"); + SimpleDateFormat format = new SimpleDateFormat(pattern); value = format.format(inDate); this.readValue = value; } @Override public Date getDateValue() { - SimpleDateFormat format = new SimpleDateFormat("dd.MM.yyyy"); + SimpleDateFormat format = new SimpleDateFormat(pattern); try { Calendar cal = Calendar.getInstance(); cal.setTime(format.parse(value)); @@ -165,6 +168,7 @@ public ProcessProperty getClone(int containerNumber) { p.setName(this.name); p.setValidation(this.validation); p.setType(this.type); + p.setPattern(this.pattern); p.setValue(this.value); p.setShowProcessGroupAccessCondition(this.showProcessGroupAccessCondition); p.setDuplicationAllowed(this.isDuplicationAllowed()); @@ -205,7 +209,7 @@ public void setValueList(List valueList) { } public boolean getBooleanValue() { - return this.value != null && this.value.equalsIgnoreCase("true"); + return this.value != null && "true".equalsIgnoreCase(this.value); } public void setBooleanValue(boolean val) { diff --git a/src/main/java/org/goobi/production/properties/PropertyParser.java b/src/main/java/org/goobi/production/properties/PropertyParser.java index 8259283af6..881708ed7b 100644 --- a/src/main/java/org/goobi/production/properties/PropertyParser.java +++ b/src/main/java/org/goobi/production/properties/PropertyParser.java @@ -250,6 +250,8 @@ public List getPropertiesForStep(Step mySchritt) { pp.setValidation(config.getString(property + "/validation")); // type pp.setType(Type.getTypeByName(config.getString(property + "/type"))); + // pattern + pp.setPattern(config.getString(property + "/pattern", "dd.MM.yyyy")); // (default) value String defaultValue = config.getString(property + "/defaultvalue"); if (Type.METADATA.equals(pp.getType())) { @@ -378,6 +380,8 @@ public List getPropertiesForProcess(Process process) { pp.setValidation(config.getString(property + "/validation")); // type pp.setType(Type.getTypeByName(config.getString(property + "/type"))); + // pattern + pp.setPattern(config.getString(property + "/pattern", "dd.MM.yyyy")); // (default) value String defaultValue = config.getString(property + "/defaultvalue"); if (Type.METADATA.equals(pp.getType())) { @@ -498,6 +502,8 @@ public List getProcessCreationProperties(Process process, Strin pp.setValidation(prop.getString("/validation")); // type pp.setType(Type.getTypeByName(prop.getString("/type"))); + // pattern + pp.setPattern(prop.getString("/pattern", "dd.MM.yyyy")); // (default) value String defaultValue = prop.getString("/defaultvalue"); if (Type.METADATA.equals(pp.getType())) { diff --git a/src/main/java/org/goobi/vocabulary/Definition.java b/src/main/java/org/goobi/vocabulary/Definition.java deleted file mode 100644 index 1087a93908..0000000000 --- a/src/main/java/org/goobi/vocabulary/Definition.java +++ /dev/null @@ -1,141 +0,0 @@ -/** - * This file is part of the Goobi Application - a Workflow tool for the support of mass digitization. - * - * Visit the websites for more information. - * - https://goobi.io - * - https://www.intranda.com - * - https://github.com/intranda/goobi-workflow - * - * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Linking this library statically or dynamically with other modules is making a combined work based on this library. Thus, the terms and conditions - * of the GNU General Public License cover the whole combination. As a special exception, the copyright holders of this library give you permission to - * link this library with independent modules to produce an executable, regardless of the license terms of these independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that you also meet, for each linked independent module, the terms and - * conditions of the license of that module. An independent module is a module which is not derived from or based on this library. If you modify this - * library, you may extend this exception to your version of the library, but you are not obliged to do so. If you do not wish to do so, delete this - * exception statement from your version. - */ -package org.goobi.vocabulary; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import javax.faces.model.SelectItem; -import javax.xml.bind.annotation.XmlRootElement; - -import org.apache.commons.lang3.StringUtils; - -import com.fasterxml.jackson.annotation.JsonIgnore; - -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.NonNull; - -@Data -@XmlRootElement -@NoArgsConstructor -public class Definition implements Serializable { - - private static final long serialVersionUID = 4869232901046909915L; - - private Integer id; - - // e.g. 'title' - @NonNull - private String label; - - // e.g. 'eng', 'ger' - @NonNull - private String language; - - // field type: "input", "textarea", "select", "select1", "html" - @NonNull - private String type; - - // regular expression - @NonNull - private String validation; - - // define if the field is required - - private boolean required; - - // define if the field is the main entry - - private boolean mainEntry; - - // define if the field value must be unique within the vocabulary - - private boolean distinctive; - - private boolean titleField; - - // possible values to select - private List selecteableValues; - - public Definition(String label, String language, String type, String validation, boolean required, boolean mainEntry, boolean distinctive, - boolean titleField) { - this.label = label; - this.language = language; - this.type = type; - this.validation = validation; - this.required = required; - this.mainEntry = mainEntry; - this.distinctive = distinctive; - this.titleField = titleField; - - } - - @JsonIgnore - public String getSelection() { - StringBuilder sb = new StringBuilder(); - if (selecteableValues != null && !selecteableValues.isEmpty()) { - for (String string : selecteableValues) { - if (sb.length() > 0) { - sb.append("|"); - } - sb.append(string); - } - } - return sb.toString(); - - } - - @JsonIgnore - public void setSelection(String value) { - if (StringUtils.isNotBlank(value)) { - selecteableValues = Arrays.asList(value.split("\\|")); - } else { - selecteableValues = null; - } - - } - - @JsonIgnore - public List getSelectList() { - List list = new ArrayList<>(); - for (String s : selecteableValues) { - list.add(new SelectItem(s, s, null)); - } - return list; - } - - @JsonIgnore - public String getIdAsString() { - if (id == null) { - return ""; - } - return String.valueOf(id); - } - -} diff --git a/src/main/java/org/goobi/vocabulary/Field.java b/src/main/java/org/goobi/vocabulary/Field.java deleted file mode 100644 index 55d2ed8e85..0000000000 --- a/src/main/java/org/goobi/vocabulary/Field.java +++ /dev/null @@ -1,115 +0,0 @@ -/** - * This file is part of the Goobi Application - a Workflow tool for the support of mass digitization. - * - * Visit the websites for more information. - * - https://goobi.io - * - https://www.intranda.com - * - https://github.com/intranda/goobi-workflow - * - * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Linking this library statically or dynamically with other modules is making a combined work based on this library. Thus, the terms and conditions - * of the GNU General Public License cover the whole combination. As a special exception, the copyright holders of this library give you permission to - * link this library with independent modules to produce an executable, regardless of the license terms of these independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that you also meet, for each linked independent module, the terms and - * conditions of the license of that module. An independent module is a module which is not derived from or based on this library. If you modify this - * library, you may extend this exception to your version of the library, but you are not obliged to do so. If you do not wish to do so, delete this - * exception statement from your version. - */ -package org.goobi.vocabulary; - -import java.io.Serializable; - -import javax.xml.bind.annotation.XmlRootElement; - -import org.apache.commons.lang3.StringUtils; - -import com.fasterxml.jackson.annotation.JsonIgnore; - -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@XmlRootElement -@NoArgsConstructor -public class Field implements Serializable { - - private static final long serialVersionUID = 4731164844446907463L; - - private Integer id; - - private String label; - - private String language; - - private String value; - - private Integer definitionId; - - private transient Definition definition; - - public Field(String label, String language, String value, Definition definition) { - this.label = label; - this.language = language; - this.value = value; - this.definition = definition; - } - - @JsonIgnore - private transient String validationMessage; - - public void setValue(String value) { - if (this.definition != null) { - String type = this.definition.getType(); - if (type.equals("input") || type.equals("textarea") || type.equals("html")) { - this.value = value.trim(); - return; - } - } - this.value = value; - } - - /** - * Simple getter to allow reading the current value as multi select field - * - * @return - */ - @JsonIgnore - public String[] getValueMultiSelect() { - return value.split("\\|"); - } - - /** - * simple setter to allow writing information as multi select field - * - * @param data - */ - @JsonIgnore - public void setValueMultiSelect(String[] data) { - StringBuilder sb = new StringBuilder(); - if (data != null && data.length > 0) { - for (int i = 0; i < data.length; i++) { - if (sb.length() > 0) { - sb.append("|"); - } - sb.append(data[i]); - } - } - value = sb.toString(); - } - - @JsonIgnore - public String getDisplayLanguageKey() { - if (StringUtils.isBlank(language)) { - return ""; - } - return "vocabularyManager_language_abbreviation_" + language; - } -} diff --git a/src/main/java/org/goobi/vocabulary/JskosRecord.java b/src/main/java/org/goobi/vocabulary/JskosRecord.java deleted file mode 100644 index dedb04b8f3..0000000000 --- a/src/main/java/org/goobi/vocabulary/JskosRecord.java +++ /dev/null @@ -1,103 +0,0 @@ -/** - * This file is part of the Goobi Application - a Workflow tool for the support of mass digitization. - * - * Visit the websites for more information. - * - https://goobi.io - * - https://www.intranda.com - * - https://github.com/intranda/goobi-workflow - * - * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Linking this library statically or dynamically with other modules is making a combined work based on this library. Thus, the terms and conditions - * of the GNU General Public License cover the whole combination. As a special exception, the copyright holders of this library give you permission to - * link this library with independent modules to produce an executable, regardless of the license terms of these independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that you also meet, for each linked independent module, the terms and - * conditions of the license of that module. An independent module is a module which is not derived from or based on this library. If you modify this - * library, you may extend this exception to your version of the library, but you are not obliged to do so. If you do not wish to do so, delete this - * exception statement from your version. - */ -package org.goobi.vocabulary; - -import java.util.List; -import java.util.Map; - -import javax.xml.bind.annotation.XmlRootElement; - -import org.apache.commons.lang3.StringUtils; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonInclude.Include; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import com.fasterxml.jackson.annotation.JsonValue; - -import lombok.Data; - -@Data -@XmlRootElement -@JsonPropertyOrder({ "uri", "type", "@context", "inScheme", "publisher", "prefLabel", "fields" }) -@JsonInclude(Include.NON_NULL) -public class JskosRecord { - - private String uri; - - private List type; - - @JsonProperty("@context") - private String context; - - private List inScheme; - - private Publisher publisher; - - private Fields prefLabel; - - // fieldname, - Map fields; - - @Data - @XmlRootElement - @JsonInclude(Include.NON_NULL) - public class Schema { - private String uri; - private Fields prefLabel; - private List type; - } - - @Data - @XmlRootElement - @JsonInclude(Include.NON_NULL) - public class Publisher { - private String uri; - private Fields prefLabel; - private List type; - } - - @Data - @XmlRootElement - @JsonInclude(Include.NON_NULL) - public class Fields { - @JsonIgnore - private Map values; - @JsonIgnore - private String value; - - @JsonValue - public Object getJsonValue() { - if (StringUtils.isNotBlank(value)) { - return value; - } else { - return values; - } - } - - } -} diff --git a/src/main/java/org/goobi/vocabulary/UploadVocabJob.java b/src/main/java/org/goobi/vocabulary/UploadVocabJob.java deleted file mode 100644 index c4e56f76ff..0000000000 --- a/src/main/java/org/goobi/vocabulary/UploadVocabJob.java +++ /dev/null @@ -1,82 +0,0 @@ -/** - * This file is part of the Goobi Application - a Workflow tool for the support of mass digitization. - * - * Visit the websites for more information. - * - https://goobi.io - * - https://www.intranda.com - * - https://github.com/intranda/goobi-workflow - * - * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Linking this library statically or dynamically with other modules is making a combined work based on this library. Thus, the terms and conditions - * of the GNU General Public License cover the whole combination. As a special exception, the copyright holders of this library give you permission to - * link this library with independent modules to produce an executable, regardless of the license terms of these independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that you also meet, for each linked independent module, the terms and - * conditions of the license of that module. An independent module is a module which is not derived from or based on this library. If you modify this - * library, you may extend this exception to your version of the library, but you are not obliged to do so. If you do not wish to do so, delete this - * exception statement from your version. - */ -package org.goobi.vocabulary; - -import java.util.List; - -import org.goobi.beans.DatabaseObject; -import org.goobi.production.flow.jobs.AbstractGoobiJob; - -import de.sub.goobi.helper.exceptions.DAOException; -import de.sub.goobi.persistence.managers.VocabularyManager; -import lombok.extern.log4j.Log4j2; - -@Log4j2 -public class UploadVocabJob extends AbstractGoobiJob { - - /* - * (non-Javadoc) - * - * @see org.goobi.production.flow.jobs.SimpleGoobiJob#initialize() - */ - @Override - public String getJobName() { - return "dailyVocabJob"; - } - - @Override - public void execute() { - - VocabularyManager vocabMan = new VocabularyManager(); - - try { - - //get list of vocabularies - List lstVocabs = vocabMan.getList("title", null, 0, 1000, null); - - for (DatabaseObject dbObject : lstVocabs) { - - Vocabulary vocab = (Vocabulary) dbObject; - //for each, check if altered since last save - if (VocabularyManager.getVocabularyLastUploaded(vocab).after(VocabularyManager.getVocabularyLastAltered(vocab))) { - continue; - } - - //if so, update authority server - VocabularyManager.getAllRecords(vocab); - VocabularyUploader.upload(vocab); - - log.debug(String.format("Vocabulary Uploader: %s uploaded.", vocab.getTitle())); - } - - } catch (DAOException e) { - log.error(e); - } - - log.debug("Vocabulary Uploader completed"); - } - -} diff --git a/src/main/java/org/goobi/vocabulary/VocabRecord.java b/src/main/java/org/goobi/vocabulary/VocabRecord.java deleted file mode 100644 index ada0035704..0000000000 --- a/src/main/java/org/goobi/vocabulary/VocabRecord.java +++ /dev/null @@ -1,110 +0,0 @@ -/** - * This file is part of the Goobi Application - a Workflow tool for the support of mass digitization. - * - * Visit the websites for more information. - * - https://goobi.io - * - https://www.intranda.com - * - https://github.com/intranda/goobi-workflow - * - * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Linking this library statically or dynamically with other modules is making a combined work based on this library. Thus, the terms and conditions - * of the GNU General Public License cover the whole combination. As a special exception, the copyright holders of this library give you permission to - * link this library with independent modules to produce an executable, regardless of the license terms of these independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that you also meet, for each linked independent module, the terms and - * conditions of the license of that module. An independent module is a module which is not derived from or based on this library. If you modify this - * library, you may extend this exception to your version of the library, but you are not obliged to do so. If you do not wish to do so, delete this - * exception statement from your version. - */ -package org.goobi.vocabulary; - -import java.util.ArrayList; -import java.util.List; - -import javax.xml.bind.annotation.XmlRootElement; - -import org.goobi.beans.DatabaseObject; - -import com.fasterxml.jackson.annotation.JsonIgnore; - -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data - -@NoArgsConstructor -@XmlRootElement -public class VocabRecord implements DatabaseObject, Comparable { - - private static final long serialVersionUID = -1363358845851354446L; - - private Integer id; - private Integer vocabularyId; - private List fields = new ArrayList<>(); - - @JsonIgnore - private boolean valid = true; - - public VocabRecord(Integer id, Integer vocabularyId, List fields) { - this.id = id; - this.vocabularyId = vocabularyId; - this.fields = fields; - } - - @JsonIgnore - public String getTitle() { - for (Field field : fields) { - if (field.getDefinition() != null && field.getDefinition().isMainEntry()) { - if (field.getValue() != null) { - return field.getValue(); - } - } - } - return ""; - } - - @Override - public void lazyLoad() { - } - - public List getMainFields() { - List answer = new ArrayList<>(); - for (Field field : fields) { - if (field.getDefinition() != null && field.getDefinition().isTitleField()) { - answer.add(field); - } - } - return answer; - } - - public String getFieldValue(Definition definition) { - for (Field field : fields) { - if (field.getDefinition() != null && field.getDefinition().equals(definition)) { - return field.getValue(); - } - } - return ""; - } - - public Field getFieldByLabel(String label) { - for (Field field : this.fields) { - if (field.getLabel().equals(label)) { - return field; - } - } - return null; - } - - @Override - public int compareTo(VocabRecord o) { - return getTitle().compareToIgnoreCase(o.getTitle()); - } - -} diff --git a/src/main/java/org/goobi/vocabulary/Vocabulary.java b/src/main/java/org/goobi/vocabulary/Vocabulary.java deleted file mode 100644 index 50986449b0..0000000000 --- a/src/main/java/org/goobi/vocabulary/Vocabulary.java +++ /dev/null @@ -1,289 +0,0 @@ -/** - * This file is part of the Goobi Application - a Workflow tool for the support of mass digitization. - * - * Visit the websites for more information. - * - https://goobi.io - * - https://www.intranda.com - * - https://github.com/intranda/goobi-workflow - * - * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Linking this library statically or dynamically with other modules is making a combined work based on this library. Thus, the terms and conditions - * of the GNU General Public License cover the whole combination. As a special exception, the copyright holders of this library give you permission to - * link this library with independent modules to produce an executable, regardless of the license terms of these independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that you also meet, for each linked independent module, the terms and - * conditions of the license of that module. An independent module is a module which is not derived from or based on this library. If you modify this - * library, you may extend this exception to your version of the library, but you are not obliged to do so. If you do not wish to do so, delete this - * exception statement from your version. - */ -package org.goobi.vocabulary; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - -import javax.xml.bind.annotation.XmlRootElement; - -import org.apache.commons.lang3.StringUtils; -import org.goobi.beans.DatabaseObject; - -import com.fasterxml.jackson.annotation.JsonIgnore; - -import de.sub.goobi.helper.Helper; -import lombok.Data; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -@Data -@NoArgsConstructor -@XmlRootElement -public class Vocabulary implements Serializable, DatabaseObject { - - private static final long serialVersionUID = -86569570995051824L; - - private Integer id; - private String title; - private String description; - private List records = new ArrayList<>(); - private List struct = new ArrayList<>(); - transient List subList = null; - - @JsonIgnore - private List filteredRecords = new ArrayList<>(); - - @JsonIgnore - private String url; - - @Override - public void lazyLoad() { - } - - /** - * @deprecated This field is not used anymore - */ - @Deprecated(since = "23.05", forRemoval = true) - @JsonIgnore - private String mainFieldName; - - /** - * @deprecated This field is not used anymore - */ - @Deprecated(since = "23.05", forRemoval = true) - @JsonIgnore - private String searchField; - - /** - * @deprecated This field is not used anymore - */ - @Deprecated(since = "23.05", forRemoval = true) - @JsonIgnore - private String order; // blank, ASC, DESC - - @JsonIgnore - private int totalNumberOfRecords; - - // paginator for records list - @JsonIgnore - private int numberOfRecordsPerPage = Helper.getCurrentUser() != null ? Helper.getCurrentUser().getTabellengroesse() : 20; - @JsonIgnore - @Getter - @Setter - private int pageNo = 0; - - @JsonIgnore - private String sortfield = "idAsc"; - @JsonIgnore - private boolean sortOrder; - @JsonIgnore - private Integer internalSortField; - - @JsonIgnore - private String searchValue; - - public int getLastPageNumber() { - int ret = filteredRecords.size() / numberOfRecordsPerPage; - if (filteredRecords.size() % numberOfRecordsPerPage == 0) { - ret--; - } - return ret; - } - - public boolean isFirstPage() { - return this.pageNo == 0; - } - - public boolean isLastPage() { - return this.pageNo >= getLastPageNumber(); - } - - public boolean hasNextPage() { - return filteredRecords.size() > numberOfRecordsPerPage; - } - - public boolean hasPreviousPage() { - return this.pageNo > 0; - } - - public Long getPageNumberCurrent() { - return Long.valueOf(this.pageNo + 1l); - } - - public Long getPageNumberLast() { - return Long.valueOf(getLastPageNumber() + 1l); - } - - public int getSizeOfList() { - return filteredRecords.size(); - } - - public List getPaginatorList() { - return subList; - } - - public void runFilter() { - filteredRecords.clear(); - if (StringUtils.isNotBlank(searchValue)) { - for (VocabRecord rec : records) { - for (Field f : rec.getMainFields()) { - if (StringUtils.isNotBlank(f.getValue()) && f.getValue().toLowerCase().contains(searchValue.toLowerCase())) { - filteredRecords.add(rec); - break; - } - } - } - } else { - filteredRecords = new ArrayList<>(records); - } - - if (filteredRecords.size() > (pageNo * numberOfRecordsPerPage) + numberOfRecordsPerPage) { - subList = filteredRecords.subList(pageNo * numberOfRecordsPerPage, (pageNo * numberOfRecordsPerPage) + numberOfRecordsPerPage); - } else { - subList = filteredRecords.subList(pageNo * numberOfRecordsPerPage, filteredRecords.size()); - } - } - - public String cmdMoveFirst() { - - if (this.pageNo != 0) { - this.pageNo = 0; - getPaginatorList(); - } - - return ""; - } - - public String cmdMovePrevious() { - - if (!isFirstPage()) { - this.pageNo--; - runFilter(); - } - - return ""; - } - - public String cmdMoveNext() { - - if (!isLastPage()) { - this.pageNo++; - runFilter(); - } - - return ""; - } - - public String cmdMoveLast() { - if (this.pageNo != getLastPageNumber()) { - this.pageNo = getLastPageNumber(); - runFilter(); - } - return ""; - } - - public void setTxtMoveTo(Integer neueSeite) { - if (neueSeite != null && (this.pageNo != neueSeite - 1) && neueSeite > 0 && neueSeite <= getLastPageNumber() + 1) { - this.pageNo = neueSeite - 1; - runFilter(); - } - } - - public Integer getTxtMoveTo() { - return null; - } - - public List getMainFields() { - List answer = new ArrayList<>(); - for (Definition def : struct) { - if (def.isTitleField()) { - answer.add(def); - } - } - return answer; - } - - public void changeOrder() { - String field = null; - if (sortfield.endsWith("Asc")) { - field = sortfield.replace("Asc", ""); - sortOrder = true; - } else { - field = sortfield.replace("Desc", ""); - sortOrder = false; - } - - if (field.equals("id")) { - internalSortField = null; - } else { - internalSortField = Integer.parseInt(field); - } - Collections.sort(records, recordComparator); - runFilter(); - } - - private transient Comparator recordComparator = (vocabRecord1, vocabRecord2) -> { - if (internalSortField == null) { - if (sortOrder) { - return vocabRecord1.getId().compareTo(vocabRecord2.getId()); - } else { - return vocabRecord2.getId().compareTo(vocabRecord1.getId()); - } - } - String value1 = ""; - String value2 = ""; - - for (Field f : vocabRecord1.getFields()) { - if (f.getDefinition().getId().intValue() == internalSortField.intValue()) { - value1 = f.getValue().toLowerCase(); - } - } - for (Field f : vocabRecord2.getFields()) { - if (f.getDefinition().getId().intValue() == internalSortField.intValue()) { - value2 = f.getValue().toLowerCase(); - } - } - if (sortOrder) { - return value1.compareTo(value2); - } else { - return value2.compareTo(value1); - } - }; - - public void setSearchValue(String searchValue) { - if (this.searchValue == null || !this.searchValue.equals(searchValue)) { - pageNo = 0; - this.searchValue = searchValue; - } - - } - -} diff --git a/src/main/java/org/goobi/vocabulary/VocabularyFieldValidator.java b/src/main/java/org/goobi/vocabulary/VocabularyFieldValidator.java deleted file mode 100644 index 6aca3ee733..0000000000 --- a/src/main/java/org/goobi/vocabulary/VocabularyFieldValidator.java +++ /dev/null @@ -1,78 +0,0 @@ -/** - * This file is part of the Goobi Application - a Workflow tool for the support of mass digitization. - * - * Visit the websites for more information. - * - https://goobi.io - * - https://www.intranda.com - * - https://github.com/intranda/goobi-workflow - * - * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Linking this library statically or dynamically with other modules is making a combined work based on this library. Thus, the terms and conditions - * of the GNU General Public License cover the whole combination. As a special exception, the copyright holders of this library give you permission to - * link this library with independent modules to produce an executable, regardless of the license terms of these independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that you also meet, for each linked independent module, the terms and - * conditions of the license of that module. An independent module is a module which is not derived from or based on this library. If you modify this - * library, you may extend this exception to your version of the library, but you are not obliged to do so. If you do not wish to do so, delete this - * exception statement from your version. - */ -package org.goobi.vocabulary; - -import org.apache.commons.lang3.StringUtils; - -public class VocabularyFieldValidator { - - /** - * This method validates a field of the currently edited vocabulary record. If fields are required, but are empty, the currentVocabRecord is set - * to 'invalid=false'. If there are data fields that have to be distinctive and are equal to the contents of fields of other vocabulary records, - * all of them are set to invalid too. If the currentVocabRecord is invalid, false is returned. If it is valid and can be stored in the database, - * true is returned. The given field and the value to set are the data that should be set in the frontend and must be validated. The - * validationMessage of all invalid fields is set to the key that can be translated (to get a readable validation error message). Otherwise, the - * validation message is set to an empty string. - * - * @param vocabulary The current vocabulary to validate - * @param vocabRecord The current vocabulary record to validate - * @param field The field to validate - * @param fieldValue The value that should be set to that field - * @return true If currentVocabRecord is valid and its fields are valid or false if they are invalid or distinctive fields have the same content - * as fields of other vocabulary records - */ - public static boolean validateFieldInRecords(Vocabulary vocabulary, VocabRecord vocabRecord, Field field, String fieldValue) { - - // If field is required and empty, it gets marked as invalid - if (field.getDefinition().isRequired() && StringUtils.isBlank(fieldValue)) { - field.setValidationMessage("vocabularyManager_validation_fieldIsRequired"); - vocabRecord.setValid(false); - return false; - } - - field.setValidationMessage(""); - boolean valid = true; - - if (field.getDefinition().isDistinctive() && StringUtils.isNotBlank(fieldValue)) { - for (VocabRecord other : vocabulary.getRecords()) { - - if (vocabRecord.equals(other)) { - continue; - } - - String otherFieldValue = other.getFieldValue(field.getDefinition()); - if (fieldValue.equals(otherFieldValue)) { - field.setValidationMessage("vocabularyManager_validation_fieldIsNotUnique"); - other.setValid(false); - vocabRecord.setValid(false); - valid = false; - } - } - } - return valid; - } - -} diff --git a/src/main/java/org/goobi/vocabulary/VocabularyUploader.java b/src/main/java/org/goobi/vocabulary/VocabularyUploader.java deleted file mode 100644 index df84194398..0000000000 --- a/src/main/java/org/goobi/vocabulary/VocabularyUploader.java +++ /dev/null @@ -1,215 +0,0 @@ -/** - * This file is part of the Goobi Application - a Workflow tool for the support of mass digitization. - * - * Visit the websites for more information. - * - https://goobi.io - * - https://www.intranda.com - * - https://github.com/intranda/goobi-workflow - * - * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Linking this library statically or dynamically with other modules is making a combined work based on this library. Thus, the terms and conditions - * of the GNU General Public License cover the whole combination. As a special exception, the copyright holders of this library give you permission to - * link this library with independent modules to produce an executable, regardless of the license terms of these independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that you also meet, for each linked independent module, the terms and - * conditions of the license of that module. An independent module is a module which is not derived from or based on this library. If you modify this - * library, you may extend this exception to your version of the library, but you are not obliged to do so. If you do not wish to do so, delete this - * exception statement from your version. - */ -package org.goobi.vocabulary; - -import java.io.IOException; -import java.net.URISyntaxException; -import java.time.Duration; -import java.util.ArrayList; -import java.util.Base64; -import java.util.List; - -import javax.jms.JMSException; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.ClientBuilder; -import javax.ws.rs.client.Entity; -import javax.ws.rs.client.WebTarget; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; - -import org.glassfish.jersey.client.ClientConfig; -import org.json.JSONArray; -import org.json.JSONObject; - -import de.sub.goobi.config.ConfigurationHelper; -import de.sub.goobi.helper.RetryUtils; -import de.sub.goobi.persistence.managers.VocabularyManager; -import lombok.extern.log4j.Log4j2; - -@Log4j2 -public class VocabularyUploader { - - static String vocabTable = "vocabularies"; - - static String strURL = ConfigurationHelper.getInstance().getGoobiAuthorityServerUrl(); - - /** - * The uploader is active if there is a URL specified for the GoobiAuthorityServer, and a username - * - * @return - */ - public static Boolean isActive() { - - String strUsername = ConfigurationHelper.getInstance().getGoobiAuthorityServerUser(); - return strURL != null && !strURL.isEmpty() && strUsername != null && !strUsername.isEmpty(); - } - - /** - * Upload the vocabulary to the authority server. If it is new, create a new vocab on the server, otherwise update an already existing one. - * - * Updates the "lastUploaded" field in the vocabularies table. - * - * @param vocab - */ - public static Boolean upload(Vocabulary vocab) { - - Boolean boOk = true; - - try { - //does the vocab already exist? - String strUsername = ConfigurationHelper.getInstance().getGoobiAuthorityServerUser(); - - if (getVocabulary(strUsername, vocab.getId()) != null) { - - boOk = updateVocabulary(vocab); - - } else { - - boOk = createNewVocabulary(vocab); - } - - //set the lastUploaded time: - VocabularyManager.setVocabularyLastUploaded(vocab); - - } catch (Exception e) { - log.error(e); - boOk = false; - } - - return boOk; - } - - private static Vocabulary getVocabulary(String strUsername, Integer vocabId) throws URISyntaxException, JMSException { - - String strVocabId = String.valueOf(vocabId); - - ClientConfig config = new ClientConfig(); - Client client = ClientBuilder.newClient(config); - - WebTarget target = client.target(strURL).path(strUsername).path(vocabTable).path(strVocabId); - - String message = "failed to connect to goobi_authority_server while requesting vocabulary"; - JMSException exception = new JMSException(message); - Duration oneSecond = Duration.ofSeconds(1); - Response response = RetryUtils.retry(exception, oneSecond, 5, () -> target.request().accept(MediaType.APPLICATION_JSON).get(Response.class)); - - return vocabFromResponse(response); - } - - private static Boolean updateVocabulary(Vocabulary vocab) throws IOException, URISyntaxException, JMSException { - - String strVocabId = String.valueOf(vocab.getId()); - String strUsername = ConfigurationHelper.getInstance().getGoobiAuthorityServerUser(); - String strAuthorization = getAuthorizationHeader(); - - ClientConfig config = new ClientConfig(); - Client client = ClientBuilder.newClient(config); - - WebTarget target = client.target(strURL).path(strUsername).path(vocabTable).path(strVocabId); - - String message = "failed to connect to goobi_authority_server while updating vocabulary"; - JMSException exception = new JMSException(message); - Duration oneSecond = Duration.ofSeconds(1); - Response response = RetryUtils.retry(exception, oneSecond, 5, - () -> target.request().header(HttpHeaders.AUTHORIZATION, strAuthorization).put(Entity.json(vocab))); - - return response.getStatus() == Response.Status.OK.getStatusCode(); - } - - private static String getAuthorizationHeader() { - - String strPW = ConfigurationHelper.getInstance().getGoobiAuthorityServerPassword(); - return "Basic " + Base64.getEncoder().encodeToString(strPW.getBytes()); - } - - private static Boolean createNewVocabulary(Vocabulary vocab) throws IOException, URISyntaxException, JMSException { - - String strUsername = ConfigurationHelper.getInstance().getGoobiAuthorityServerUser(); - String strAuthorization = getAuthorizationHeader(); - - ClientConfig config = new ClientConfig(); - Client client = ClientBuilder.newClient(config); - - WebTarget target = client.target(strURL).path(strUsername).path(vocabTable); - - String message = "failed to connect to goobi_authority_server while creating new vocabulary"; - JMSException exception = new JMSException(message); - Duration oneSecond = Duration.ofSeconds(1); - Response response = RetryUtils.retry(exception, oneSecond, 5, - () -> target.request().header(HttpHeaders.AUTHORIZATION, strAuthorization).post(Entity.json(vocab))); - - return response.getStatus() == Response.Status.OK.getStatusCode(); - } - - private static Vocabulary vocabFromResponse(Response response) { - - Vocabulary vocab = null; - - try { - - if (response.getStatus() != Response.Status.OK.getStatusCode()) { - return null; - } - - if (response.getEntity() != null) { - - vocab = new Vocabulary(); - - String json = response.readEntity(String.class); - - JSONObject object = new JSONObject(json); - vocab.setId(object.getInt("id")); - vocab.setTitle(object.getString("title")); - vocab.setDescription(object.getString("description")); - - vocab.setStruct(getStruct(object.getJSONArray("struct"))); - vocab.setRecords(getRecords(object.getJSONArray("records"))); - - } else { - return null; - } - - return vocab; - } catch (Exception e) { - - log.error(e); - return null; - } - } - - //TODO - private static List getRecords(JSONArray jsonArray) { - - return new ArrayList<>(); - } - - //TODO - private static List getStruct(JSONArray jsonArray) { - - return new ArrayList<>(); - } -} diff --git a/src/main/java/org/goobi/vocabulary/helper/ImportJsonVocabulary.java b/src/main/java/org/goobi/vocabulary/helper/ImportJsonVocabulary.java deleted file mode 100644 index 13ce0d8e58..0000000000 --- a/src/main/java/org/goobi/vocabulary/helper/ImportJsonVocabulary.java +++ /dev/null @@ -1,119 +0,0 @@ -/** - * This file is part of the Goobi Application - a Workflow tool for the support of mass digitization. - * - * Visit the websites for more information. - * - https://goobi.io - * - https://www.intranda.com - * - https://github.com/intranda/goobi-workflow - * - * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Linking this library statically or dynamically with other modules is making a combined work based on this library. Thus, the terms and conditions - * of the GNU General Public License cover the whole combination. As a special exception, the copyright holders of this library give you permission to - * link this library with independent modules to produce an executable, regardless of the license terms of these independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that you also meet, for each linked independent module, the terms and - * conditions of the license of that module. An independent module is a module which is not derived from or based on this library. If you modify this - * library, you may extend this exception to your version of the library, but you are not obliged to do so. If you do not wish to do so, delete this - * exception statement from your version. - */ -package org.goobi.vocabulary.helper; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; - -import org.goobi.vocabulary.Definition; -import org.goobi.vocabulary.Field; -import org.goobi.vocabulary.VocabRecord; -import org.goobi.vocabulary.Vocabulary; - -import com.jayway.jsonpath.Configuration; -import com.jayway.jsonpath.JsonPath; - -import lombok.extern.log4j.Log4j2; - -@Log4j2 -public class ImportJsonVocabulary { - - public static List convertJsonVocabulary(Vocabulary vocabulary, Path jsonFile) { - List recordList = null; - InputStream in = null; - try { - in = Files.newInputStream(jsonFile); - Object oldVocabulary = Configuration.defaultConfiguration().jsonProvider().parse(in, "UTF-8"); - - // run through all records and create new ones - List records = JsonPath.read(oldVocabulary, "records"); - recordList = new ArrayList<>(records.size()); - - for (Object recordObject : records) { - VocabRecord rec = new VocabRecord(); - List fieldList = new ArrayList<>(); - for (Definition definition : vocabulary.getStruct()) { - Field field = new Field(definition.getLabel(), definition.getLanguage(), "", definition); - fieldList.add(field); - } - rec.setFields(fieldList); - vocabulary.getRecords().add(rec); - recordList.add(rec); - - List fields = JsonPath.read(recordObject, "fields"); - - for (Object field : fields) { - String label = JsonPath.read(field, "label"); - String value = JsonPath.read(field, "value"); - // check if field was defined before - boolean found = false; - for (Definition definition : vocabulary.getStruct()) { - if (definition.getLabel().equals(label)) { - found = true; - } - } - if (!found) { - // define it - Definition definition = new Definition(); - definition.setLabel(label); - definition.setMainEntry(vocabulary.getStruct().isEmpty()); - definition.setLanguage(""); - definition.setValidation(""); - definition.setType("input"); - vocabulary.getStruct().add(definition); - Field f = new Field(definition.getLabel(), definition.getLanguage(), "", definition); - fieldList.add(f); - } - - for (Field f : fieldList) { - if (f.getLabel().equals(label)) { - f.setValue(value); - } - } - - } - - } - - } catch (IOException e) { - log.error(e); - } finally { - if (in != null) { - try { - in.close(); - } catch (IOException e) { - log.error(e); - } - } - } - return recordList; - } - -} diff --git a/src/main/resources/messages_de.properties b/src/main/resources/messages_de.properties index 6df2c3d4e7..f9e43ec508 100644 --- a/src/main/resources/messages_de.properties +++ b/src/main/resources/messages_de.properties @@ -460,6 +460,8 @@ couldNotCreateImageFolder=Das Verzeichnis f\u00FCr die Bilder konnte nicht angel count=Anzahl countImages=Anzahl der Bilder countMetadata=Anzahl der Metadaten +counterFormat=Format des Z\u00E4hlers +counterStartValue=Startwert createDoc=Datei im Format Microsoft Word erzeugen createExcel=Datei im Format Microsoft Excel erzeugen createNewBatchFromSelectedProcesses=Neuen Batch aus den gew\u00E4hlten Vorg\u00E4ngen erzeugen @@ -698,6 +700,7 @@ exportMetsParameter=Export METS-Parameter exportPdf=PDF-Datei in Benutzerverzeichnis speichern exportRus=Export Rus exportValidation=Export-Validierung +export_verb=Exportieren failure=Fehler farbschema=Farbschema fehler=Fehler @@ -1256,7 +1259,7 @@ institution_shortName=K\u00FCrzel institutions=Einrichtungen internesSpeicherformat=Internes Speicherformat intranda_admin_data_poller=intranda Data Poller -intranda_administration_archive_management=Archivmanagement +intranda_administration_archive_management=Archivbest\u00E4nde intranda_administration_config_file_editor=Editor f\u00FCr Konfigurationsdateien intranda_administration_copymasteranchor=Kopieren von Master-Anchor Daten intranda_administration_create_repository=Repository hinzuf\u00FCgen @@ -1330,10 +1333,11 @@ intranda_workflow_crop=LayoutWizzard workflow plugin intranda_workflow_excelimport=Yerusha Upload Plugin intranda_workflow_fileUploadProcessCreation=Dateiupload zur Vorgangserzeugung intranda_workflow_hu_importer=Import f\u00FCr das Sammlungsportal +intranda_workflow_import_json=JSON Importer intranda_workflow_khm_importer=KHM Importer -intranda_workflow_liechtenstein_volksblatt_importer=Zeitungsimport Liechtensteiner Volksblatt intranda_workflow_massupload=Massenupload Plugin intranda_workflow_metadata-enrichment=Aktualisierung von Vokabularverlinkungen +intranda_workflow_newspaper_pages_importer=Zeitungsimport f\u00FCr Einzelseiten intranda_workflow_oepma_importer=\u00D6PMA Importer intranda_workflow_projectexport=Projektexport invalidCharacter=Der Name enth\u00E4lt ung\u00FCltige Zeichen @@ -1408,6 +1412,9 @@ kw=KW label__named_entity=Entit\u00E4t zzz label__named_entity_type=Typ zzz langLaufendeAufgaben=Lang laufende Aufgaben +lang_eng=Englisch +lang_fre=Franz\u00F6sisch +lang_ger=Deutsch language=Sprache lastImage=Letztes Bild lastPage=Letzte Seite @@ -1846,6 +1853,7 @@ mets_duplicateMetadataGroup=Diese Metadatengruppe duplizieren mets_easyPagination="Letzte Seite" als "Erste Seite" wieder verwenden mets_editOcrForCurrentImage=OCR Ergebnisse editieren mets_error_configuredVocabularyInvalid=Fehler bei der Initialisierung von '{0}'\: Das Vokabular '{1}' kann nicht geladen werden. +mets_error_configuredVocabularyListHierarchical=Fehler bei der Initialisierung von '{0}'\: Das Vokabular '{1}' ist hierarchisch und kann nicht in eine einfache Liste geladen werden. mets_generation_error=Regelsatzfehler, f\u00FCr das ausgew\u00E4hlte Strukturelement kann kein MODS-Dokument erzeugt werden mets_geoname_account_inactive=Die Suche in der GeoNames Datenbank konnte nicht durchgef\u00FChrt werden, da keine g\u00FCltigen Accountinformationen hinterlegt wurden. mets_hideHiddenFields=Blende versteckte Felder aus @@ -2282,6 +2290,12 @@ plugin_admin_vocabulary_noVocabularyLoaded=Es ist kein Vokabular geladen. Bitte plugin_admin_vocabulary_select=Ausw\u00E4hlbare Werte plugin_admin_vocabulary_type=Typ plugin_admin_vocabulary_validation=Validierungsausdruck +plugin_administration_archive_AcquisitionAgent=Akquisiteur +plugin_administration_archive_AcquisitionMethod=Erwerbsmethode +plugin_administration_archive_AcquisitionNotes=Anmerkungen zum Erwerb +plugin_administration_archive_ArchivistNote=Information des Bearbeiters +plugin_administration_archive_Conventions=Konventionen +plugin_administration_archive_DescriptionDates=Datum oder Zeitraum der Verzeichnung plugin_administration_archive_Number=Archiv Nummer plugin_administration_archive_Shelfmark=Signatur(en) plugin_administration_archive_accessrestrict=Zugangsbestimmungen @@ -2289,6 +2303,8 @@ plugin_administration_archive_accruals=Neuzug\u00E4nge plugin_administration_archive_accruals_head=\u00DCberschrift plugin_administration_archive_accruals_p=Beschreibung plugin_administration_archive_acqinfo=Abgebende Stelle +plugin_administration_archive_addMultipleNodes=Mehrere Unterknoten an dieser Stelle einf\u00FCgen +plugin_administration_archive_addNodes=Knoten erstellen plugin_administration_archive_advancedSearch=Erweiterte Suche plugin_administration_archive_agencycode=Agency code plugin_administration_archive_altformavail=Kopien bzw. Reproduktionen @@ -2307,11 +2323,15 @@ plugin_administration_archive_bibliography=Ver\u00F6ffentlichungen plugin_administration_archive_bioghist=Verwaltungsgeschichte | Biografische Angaben plugin_administration_archive_c=Die Datenbankdatei kann nicht geladen werden. plugin_administration_archive_clear=Eingaben l\u00F6schen +plugin_administration_archive_confirmReplacement=Es existiert bereits ein Archivbestand mit diesem Namen. Soll er ersetzt werden? plugin_administration_archive_conventiondeclaration=Verzeichnungsgrunds\u00E4tze -plugin_administration_archive_createNewArchive=Neuen Archivbestand erstellen -plugin_administration_archive_createProcesses=F\u00FCr alle Unterknoten noch fehlende Vorg\u00E4nge erstellen -plugin_administration_archive_creationHeading=Neuer Archivbestand -plugin_administration_archive_creation_filename=Bitte geben Sie einen Namen f\u00FCr Archivbestand an. +plugin_administration_archive_counter=Z\u00E4hler +plugin_administration_archive_createNewArchive=Archivbestand hinzuf\u00FCgen +plugin_administration_archive_createNodesModal=Neue Knoten erstellen +plugin_administration_archive_createNodesModalDesciption=Hier k\u00F6nnen mehrere Knoten auf einmal erstellt werden. Dabei k\u00F6nnen auch einzelne Metadaten definiert werden, die in allen Knoten erstellt werden sollen. Bei jedem Metadatum kann festgelegt werden, ob es ein automatisch generierter Identifier, ein statischer Text oder ein Text samt Z\u00E4hler gebildet werden soll. +plugin_administration_archive_createProcesses=F\u00FCr alle Unterknoten fehlende Vorg\u00E4nge hinzuf\u00FCgen +plugin_administration_archive_creationHeading=Archivbestand erstellen +plugin_administration_archive_creation_filename=Bitte geben Sie einen Namen f\u00FCr den Archivbestand an plugin_administration_archive_creation_noRecordGroupSelected=Es wurde kein Bestand zur Bearbeitung ausgew\u00E4hlt. plugin_administration_archive_creation_selectDatabase=Bitte w\u00E4hlen Sie die Datenbank aus, in der der Archivbestand gespeichert werden soll. plugin_administration_archive_creation_uploadFile=Datei ausw\u00E4hlen @@ -2321,26 +2341,39 @@ plugin_administration_archive_databaseFileMustBeCreated=Eine Datenbankdatei muss plugin_administration_archive_databaseLocked=Diese Datei ist gerade durch einen anderen Nutzer in Bearbeitung. plugin_administration_archive_databaseMustBeCreated=Die Datenbank muss zun\u00E4chst innerhalb der BaseX-Instanz angelegt werden. plugin_administration_archive_deleteNode=Knoten l\u00F6schen +plugin_administration_archive_deleteSelectedArchive=Archivbestand l\u00F6schen plugin_administration_archive_descriptionLevel=Verzeichnungsstufe plugin_administration_archive_didnote=Allgemeine Anmerkungen -plugin_administration_archive_download=Download als EAD-Datei -plugin_administration_archive_duplicateEadFile=Kopie des Bestands erstellen +plugin_administration_archive_download=zzz +plugin_administration_archive_download_l=Download +plugin_administration_archive_download_s=Bestand als EAD-Datei herunterladen +plugin_administration_archive_duplicateEadFile=Archivbestand duplizieren plugin_administration_archive_duplicateNode=Knoten duplizieren +plugin_administration_archive_eadExport=Bestand als EAD in den in der Plugin-Konfiguration angegebenen Ordner exportieren +plugin_administration_archive_eadExportNotConfigured=Export ist nicht konfiguriert plugin_administration_archive_eadid=EAD ID plugin_administration_archive_editorName=Bearbeiter +plugin_administration_archive_exit=Zur\u00FCck zur \u00DCbersicht plugin_administration_archive_extref=Beschreibung des Links plugin_administration_archive_extrefhref=Link zum Repository plugin_administration_archive_font=Schrift +plugin_administration_archive_generated=Generiert plugin_administration_archive_langmaterial=Sprache | Schrift -plugin_administration_archive_loadDatabase=Bearbeitung beginnen +plugin_administration_archive_linkNodeModal=Knoten verlinken +plugin_administration_archive_loadDatabase=Bearbeiten plugin_administration_archive_materialspec=Materialspezifische Angaben plugin_administration_archive_missing_Data=Unvollst\u00E4ndige Daten, bitte Datenbank ausw\u00E4hlen und EAD Datei hochladen plugin_administration_archive_moveHierarchyDown=In der Hierarchie nach unten bewegen plugin_administration_archive_moveHierarchyUp=In der Hierarchie nach oben bewegen plugin_administration_archive_moveNode=Knoten an andere Stelle bewegen plugin_administration_archive_moveNodeDown=Nach unten bewegen +plugin_administration_archive_moveNodeHere=Ausgew\u00E4hlten Knoten als letzten Knoten einf\u00FCgen +plugin_administration_archive_moveNodeText=Der hervorgehobene Knoten wird als letztes Element in den ausgew\u00E4hlten Knoten eingef\u00FCgt. +plugin_administration_archive_moveNodeThis=Dies ist der aktuell ausgew\u00E4hlte Knoten plugin_administration_archive_moveNodeUp=Nach oben bewegen plugin_administration_archive_newNode=Neuen Knoten einf\u00FCgen +plugin_administration_archive_noArchiveSelected=Es wurde kein Bestand ausgew\u00E4hlt +plugin_administration_archive_noArchivesAvailable=Keine Archivbest\u00E4nde verf\u00FCgbar. Bitte legen Sie zun\u00E4chst einen Archivbestand an oder importieren eine vorhandene EAD-Datei plugin_administration_archive_noConnectionToDatabase=Es besteht keine Verbindung zur BaseX-Datenbank. Bitte \u00FCberpr\u00FCfen Sie die Installation und stellen Sie sicher, dass die BaseX-Datenbank gestartet wurde. plugin_administration_archive_noElementSelectedHeading=Es ist derzeit kein Element ausgew\u00E4hlt. plugin_administration_archive_noElementSelectedText=Bitte w\u00E4hlen Sie zun\u00E4chst im linken Bereich einen Knoten aus, den Sie bearbeiten m\u00F6chten. @@ -2352,6 +2385,7 @@ plugin_administration_archive_nodeType_image=Bild plugin_administration_archive_nodeType_other=Anderes Dokument plugin_administration_archive_nodeType_video=Videodokument plugin_administration_archive_nodelink=Verkn\u00FCpfung zu anderen Knoten +plugin_administration_archive_numberOfNodes=Anzahl Knoten plugin_administration_archive_oddnote=Weitere Anmerkungen plugin_administration_archive_originalsloc=Aufbewahrungsort der Originale plugin_administration_archive_originalsloc_head=\u00DCberschrift @@ -2377,11 +2411,13 @@ plugin_administration_archive_repositoryaddressline=Adresse plugin_administration_archive_role=Rolle plugin_administration_archive_saveAndExit=Archivbestand speichern und verlassen plugin_administration_archive_scopecontent=Form und Inhalt -plugin_administration_archive_selectionHeading=Auswahl des Archivbestands +plugin_administration_archive_selectionHeading=Archivbest\u00E4nde plugin_administration_archive_selectionText=Bitte w\u00E4hlen Sie zun\u00E4chst den Archivbestand aus, mit dem Sie arbeiten m\u00F6chten\: plugin_administration_archive_separatedmaterial=Verwandte Verzeichnungseinheiten +plugin_administration_archive_showAllFields=Alle Felder anzeigen plugin_administration_archive_show_details=Details einblenden plugin_administration_archive_suffix=Suffix +plugin_administration_archive_text=Freitext plugin_administration_archive_titleproper=Titel des Findbuches plugin_administration_archive_unitdate=Entstehungszeitraum plugin_administration_archive_unitdatestructured=Strukturiertes Datum der Einheit @@ -2390,7 +2426,7 @@ plugin_administration_archive_unittitle=Titel plugin_administration_archive_updateProcessIds=Alle Verweise auf Goobi-Vorg\u00E4nge in Unterknoten aktualisieren plugin_administration_archive_uploadDatabase=Datei hochladen plugin_administration_archive_uploadEadFile=EAD Datei hochladen -plugin_administration_archive_uploadHeading=Neue EAD Datei hochladen +plugin_administration_archive_uploadHeading=EAD Datei hochladen plugin_administration_archive_userestrict=Reproduktionsbestimmungen plugin_administration_archive_validate=Validierung ausf\u00FChren plugin_administration_config_file_editor_backup_not_writable_check_permissions=zzz @@ -2552,6 +2588,7 @@ plugin_administration_licences_name=Name plugin_administration_licences_ordernumber=Bestellnummer plugin_administration_licences_type=Typ plugin_administration_licences_usage=Verbrauch +plugin_administration_linkNodeModalDesciption=W\u00E4hlen Sie den Knoten aus, zu dem eine Verkn\u00FCpfung erstellt werden soll. plugin_administration_missingPermission=Um diese Seite anzuzeigen, ben\u00F6tigen Sie die folgende Berechtigung\: plugin_administration_nli_daily_press_cancelMessageMultipleImport=Der Import von mehreren Datens\u00E4tzen wurde abgebrochen. plugin_administration_nli_daily_press_cancelMessageSingleImport=Der Import eines einzelnen Datensatzes wurde abgebrochen. @@ -2785,6 +2822,8 @@ plugin_intranda_step_imageQA_renameDescription=Bitte vergeben Sie hier einen Nam plugin_intranda_step_imageQA_renameLabel=Namensteil plugin_intranda_step_imageQA_renameSelection=Ausgew\u00E4hlte Bilder umbenennen plugin_intranda_step_imageQA_renameTitle=Dateien umbenennen +plugin_intranda_step_imageQA_reorder_previous=Tausche Bild mit vorherigem Bild +plugin_intranda_step_imageQA_reorder_next=Tausche Bild mit n\u00E4chstem Bild plugin_intranda_step_imageQA_rotateLeft=Rotiere Bild nach links\: plugin_intranda_step_imageQA_rotateLefteSelection=Ausgew\u00E4hlte Bilder nach links rotieren plugin_intranda_step_imageQA_rotateRight=Rotiere Bild nach rechts\: @@ -3228,6 +3267,7 @@ prozesse=Vorg\u00E4nge prozesse.ProzesseID=Vorgang-ID prozesse.Titel=Vorgangstitel prozesse.erstellungsdatum=Erstellungsdatum +prozesse.sortHelperDocstructs=Anzahl Strukturelemente prozesse.sortHelperImages=Anzahl der Bilder prozesse.sortHelperMetadata=Anzahl der Metadaten prozesseBearbeiten=Vorg\u00E4nge bearbeiten @@ -3621,10 +3661,17 @@ vocabularyManager_addNewVocabulary=Vokabular hinzuf\u00FCgen vocabularyManager_addRecord=Eintrag hinzuf\u00FCgen vocabularyManager_backToVocabularies=Zur\u00FCck zur Liste der Vokabulare vocabularyManager_definition=Felddefinitionen +vocabularyManager_deleteChildRecordsPrompt=Dieser Eintrag enth\uFFFDlt Kinder. Wenn Sie die L\uFFFDschung best\uFFFDtigen, werden auch alle Kindeintr\uFFFDge entfernt. Dies kann nicht r\uFFFDckg\uFFFDngig gemacht werden. vocabularyManager_deleteDefinition=Diese Definition l\u00F6schen vocabularyManager_deleteRecord=Eintrag l\u00F6schen vocabularyManager_description=Beschreibung vocabularyManager_downloadRecords=Eintr\u00E4ge herunterladen +vocabularyManager_downloadRecordsAsCsv=Eintr\u00E4ge als CSV herunterladen +vocabularyManager_downloadRecordsAsExcel=Eintr\u00E4ge als Excel herunterladen +vocabularyManager_downloadRecordsAsJson=Eintr\u00E4ge als JSON herunterladen +vocabularyManager_downloadRecordsAsRdfTurtle=Eintr\u00E4ge als RDF/Turtle herunterladen +vocabularyManager_downloadRecordsAsRdfXml=Eintr\u00E4ge als RDF/XML herunterladen +vocabularyManager_editRecord=Datensatz bearbeiten vocabularyManager_editRecords=Datens\u00E4tze bearbeiten vocabularyManager_editVocabulary=Vokabular verwalten vocabularyManager_excelImport_addNew=Alle Eintr\u00E4ge hinzuf\u00FCgen @@ -3636,6 +3683,54 @@ vocabularyManager_excelImport_info=Bereits bestehende Eintr\u00E4ge werden aktua vocabularyManager_excelImport_mergeExisting=Vorhandene Eintr\u00E4ge zusammenf\u00FChren vocabularyManager_excelImport_removeExisting=Alle vorhandenen Eintr\u00E4ge l\u00F6schen vocabularyManager_excelImport_vocabularyField=Vokabularfeld +vocabularyManager_exception_DataIntegrityViolation=Es gab einen Fehler bei der Datenintegrit\u00E4t\: {0} +vocabularyManager_exception_DeletionOfReferencedVocabulary=Das Vokabular mit ID "{0}" kann nicht gel\u00F6scht werden, da es noch von folgenden Vokabularen referenziert wird\: "{1}" +vocabularyManager_exception_DeletionOfReferencedVocabularyRecord=Der Vokabulareintrag mit ID "{0}" kann nicht gel\u00F6scht werden, da er noch von folgenden Vokabulareintr\u00E4gen referenziert wird\: "{1}" +vocabularyManager_exception_EntityNotFound=Das Vokabularelement "{0}" mit ID "{1}" konnte nicht gefunden werden +vocabularyManager_exception_FieldDefinitionFallbackNotRequired=Vocabulary manager error {0} zzz +vocabularyManager_exception_FieldDefinitionNeitherReferenceVocabularyNorTypeNotPossible=Vocabulary manager error {0} zzz +vocabularyManager_exception_FieldDefinitionNonUniqueFallbackLanguageSpecified=Vocabulary manager error {0} zzz +vocabularyManager_exception_FieldDefinitionReferenceVocabularyAndTypeNotPossible=Vocabulary manager error {0} zzz +vocabularyManager_exception_FieldInstanceBelongsToWrongSchema=Vocabulary manager error {0} zzz +vocabularyManager_exception_FieldInstanceIsEmpty=Vocabulary manager error {0} zzz +vocabularyManager_exception_FieldInstanceIssues=Es sind Fehler w\u00E4hrend der Validierung der Felder aufgetreten +vocabularyManager_exception_FieldInstanceMultipleValuesNotAllowed=Vocabulary manager error {0} zzz +vocabularyManager_exception_FieldInstanceValueIssues=Es sind Fehler w\u00E4hrend der Validierung der Feldwerte aufgetreten +vocabularyManager_exception_FieldTypeInvalidRegexSyntax=Vocabulary manager error {0} zzz +vocabularyManager_exception_FieldTypeSelectableValuesDoNotMatchSpecifiedValidationRegex=Vocabulary manager error {0} zzz +vocabularyManager_exception_FieldValueContainsNonTranslatedValue=Vocabulary manager error {0} zzz +vocabularyManager_exception_FieldValueHasNonAllowedTranslations=Vocabulary manager error {0} zzz +vocabularyManager_exception_FieldValueIsBlank=Vocabulary manager error {0} zzz +vocabularyManager_exception_FieldValueIsNotUnique=Die Werte "{1}" des Feldes "{0}" sind nicht eindeutig +vocabularyManager_exception_FieldValueMissingRequiredTranslations=Vocabulary manager error {0} zzz +vocabularyManager_exception_FieldValueReferencedRecordBelongsToWrongVocabulary=Vocabulary manager error {0} zzz +vocabularyManager_exception_FieldValueReferencedRecordIssues=Vocabulary manager error {0} zzz +vocabularyManager_exception_FieldValueUnspecifiedTranslations=Vocabulary manager error {0} zzz +vocabularyManager_exception_FieldValuesAreNonSelectableValues=Vocabulary manager error {0} zzz +vocabularyManager_exception_FieldValuesDoNotMatchSpecifiedValidationRegex=Die Werte "{1}" des Feldes "{0}" erf\u00FCllen nicht den regul\u00E4ren Validierungsausdruck "{2}" +vocabularyManager_exception_GenericValidation=Es sind Fehler w\u00E4hrend der Validierungsphase aufgetreten +vocabularyManager_exception_IllegalAttributeProvided=Vocabulary manager error {0} zzz +vocabularyManager_exception_InsertingNonExistingItem=Vocabulary manager error {0} zzz +vocabularyManager_exception_Mapping=Vocabulary manager error {0} zzz +vocabularyManager_exception_MissingRequiredAttribute=Vocabulary manager error {0} zzz +vocabularyManager_exception_RecordImport=Vocabulary manager error {0} zzz +vocabularyManager_exception_RecordImportUnsupportedExcelCellType=Es ist ein Fehler beim Excel Import aufgetreten\: Unbekannter Zellentyp "{0}" +vocabularyManager_exception_RecordValidation=Vocabulary manager error {0} zzz +vocabularyManager_exception_RecordValidationChildrenReferencesNotAllowed=Vocabulary manager error {0} zzz +vocabularyManager_exception_RecordValidationHierarchyIssues=Vocabulary manager error {0} zzz +vocabularyManager_exception_RecordValidationMissingRequiredFields=Die folgenden verpflichtenden Felder fehlen\: {0} +vocabularyManager_exception_RecordValidationParentReferenceNotAllowed=Vocabulary manager error {0} zzz +vocabularyManager_exception_RecordValidationSingleRootElementVocabularyAlreadyContainsRecord=Vocabulary manager error {0} zzz +vocabularyManager_exception_RecordValidationUndefinedFieldsGiven=Vocabulary manager error {0} zzz +vocabularyManager_exception_SchemaValidationDefinitionIssues=Vocabulary manager error {0} zzz +vocabularyManager_exception_SchemaValidationMainFieldIsNotRequired=Vocabulary manager error {0} zzz +vocabularyManager_exception_SchemaValidationMissingMainField=Vocabulary manager error {0} zzz +vocabularyManager_exception_SchemaValidationNoDefinitions=Vocabulary manager error {0} zzz +vocabularyManager_exception_SchemaValidationTitleFieldsAreNotRequired=Vocabulary manager error {0} zzz +vocabularyManager_exception_SchemaValidationTooManyMainFields=Vocabulary manager error {0} zzz +vocabularyManager_exception_VocabularyValidationMetadataSchemaIsHierarchical=Vocabulary manager error {0} zzz +vocabularyManager_exception_VocabularyValidationMetadataSchemaIsNotSetToSingleRootElement=Vocabulary manager error {0} zzz +vocabularyManager_exception_VocabularyValidationMetadataSchemaIssues=Vocabulary manager error {0} zzz vocabularyManager_fieldDefinitions=Felddefinitionen vocabularyManager_label=Bezeichnung vocabularyManager_languageSelection=Sprache diff --git a/src/main/resources/messages_en.properties b/src/main/resources/messages_en.properties index 8281cfcc6d..5fcd45d302 100644 --- a/src/main/resources/messages_en.properties +++ b/src/main/resources/messages_en.properties @@ -460,6 +460,8 @@ couldNotCreateImageFolder=The directory for the images could not be created. count=Count countImages=Number of images countMetadata=Number of metadata +counterFormat=Counter format +counterStartValue=Start value createDoc=Generate Microsoft Word file createExcel=Generate Microsoft Excel file createNewBatchFromSelectedProcesses=Create new batch from selected processes @@ -698,6 +700,7 @@ exportMetsParameter=Export METS parameters exportPdf=Save PDF file in user directory exportRus=Export Rus exportValidation=Export validation +export_verb=zzz failure=Error farbschema=Colour scheme fehler=Error @@ -1256,7 +1259,7 @@ institution_shortName=Short name institutions=Institutions internesSpeicherformat=Internal file format intranda_admin_data_poller=intranda Data Poller -intranda_administration_archive_management=Archive management +intranda_administration_archive_management=Archive records intranda_administration_config_file_editor=Editor for configuration files intranda_administration_copymasteranchor=Copy Master-Anchor data intranda_administration_create_repository=Add repositoryzzz @@ -1330,10 +1333,11 @@ intranda_workflow_crop=LayoutWizzard workflow plugin intranda_workflow_excelimport=Yerusha Upload Plugin intranda_workflow_fileUploadProcessCreation=File upload for process creation intranda_workflow_hu_importer=Import for the collection portal +intranda_workflow_import_json=JSON Importer intranda_workflow_khm_importer=KHM Importer -intranda_workflow_liechtenstein_volksblatt_importer=Zeitungsimport Liechtensteiner Volksblatt zzz intranda_workflow_massupload=Mass upload plugin intranda_workflow_metadata-enrichment=Updating vocabulary links zzz +intranda_workflow_newspaper_pages_importer=Newspaper import for single pages zzz intranda_workflow_oepma_importer=\u00D6PMA Importer intranda_workflow_projectexport=Project export invalidCharacter=The name contains invalid characters @@ -1408,6 +1412,9 @@ kw=W label__named_entity=Named entity zzz label__named_entity_type=Named entity type zzz langLaufendeAufgaben=Long-running tasks +lang_eng=English +lang_fre=French +lang_ger=German language=Language lastImage=Last image lastPage=Last page @@ -1846,6 +1853,7 @@ mets_duplicateMetadataGroup=Duplicate this metadata group mets_easyPagination=Reuse "Last Page" again as "First Page" mets_editOcrForCurrentImage=Edit ocr results zzz mets_error_configuredVocabularyInvalid=Error during initialization of '{0}'\: The vocabulary '{1}' cannot be loaded. +mets_error_configuredVocabularyListHierarchical=Error during initialization of '{0}'\: The vocabulary '{1}' is hierarchical and cannot be loaded into a flat list. mets_generation_error=Ruleset error, unable to generate MODS document for the selected docstruct mets_geoname_account_inactive=The search in the GeoNames database could not be carried out because no valid account information was stored. mets_hideHiddenFields=Don't show hidden fields @@ -2282,6 +2290,12 @@ plugin_admin_vocabulary_noVocabularyLoaded=Currently, there is no vocabulary loa plugin_admin_vocabulary_select=Selectable values plugin_admin_vocabulary_type=Type plugin_admin_vocabulary_validation=Validation expression +plugin_administration_archive_AcquisitionAgent=Acquisition agentzzz +plugin_administration_archive_AcquisitionMethod=Acquisition methodzzz +plugin_administration_archive_AcquisitionNotes=Notes on the acquisitionzzz +plugin_administration_archive_ArchivistNote=Archivist's notezzz +plugin_administration_archive_Conventions=Conventionszzz +plugin_administration_archive_DescriptionDates=Date(s) of descriptionszzz plugin_administration_archive_Number=Archive Number plugin_administration_archive_Shelfmark=Reference code(s) plugin_administration_archive_accessrestrict=Conditions governing access @@ -2289,6 +2303,8 @@ plugin_administration_archive_accruals=Accruals plugin_administration_archive_accruals_head=Headingzzz plugin_administration_archive_accruals_p=Descriptionzzz plugin_administration_archive_acqinfo=Immediate source of acquisition or transfer +plugin_administration_archive_addMultipleNodes=Insert multiple subnodes at this positionzzz +plugin_administration_archive_addNodes=Create nodeszzz plugin_administration_archive_advancedSearch=Advanced searchzzz plugin_administration_archive_agencycode=Agency code plugin_administration_archive_altformavail=Existence and location of copies @@ -2307,8 +2323,12 @@ plugin_administration_archive_bibliography=Publication note plugin_administration_archive_bioghist=Administrative | Biographical history plugin_administration_archive_c=The database file cannot be loaded. plugin_administration_archive_clear=Clear inputszzz +plugin_administration_archive_confirmReplacement=A record group with this name already exists. Should it be replaced?zzz plugin_administration_archive_conventiondeclaration=Rules or Conventions +plugin_administration_archive_counter=Counter plugin_administration_archive_createNewArchive=Create new record group +plugin_administration_archive_createNodesModal=Create new nodeszzz +plugin_administration_archive_createNodesModalDesciption=Several nodes can be created at once here. You can also define individual metadata to be created in all nodes. For each metadata field, you can specify whether it should be an automatically generated identifier, a static text or a text with a counter.zzz plugin_administration_archive_createProcesses=Create missing processes for all lowest level subnodes plugin_administration_archive_creationHeading=New record group plugin_administration_archive_creation_filename=Please enter a name for the record group. @@ -2321,26 +2341,39 @@ plugin_administration_archive_databaseFileMustBeCreated=A database file must fir plugin_administration_archive_databaseLocked=The file is currently being edited by another user. plugin_administration_archive_databaseMustBeCreated=The database must first be created within the BaseX instance. plugin_administration_archive_deleteNode=Delete node +plugin_administration_archive_deleteSelectedArchive=Delete inventoryzzz plugin_administration_archive_descriptionLevel=Level of description plugin_administration_archive_didnote=Note -plugin_administration_archive_download=Download as EAD file -plugin_administration_archive_duplicateEadFile=Create a copy of the filezzz +plugin_administration_archive_download=zzz +plugin_administration_archive_download_l=Download +plugin_administration_archive_download_s=Download record group as EAD file +plugin_administration_archive_duplicateEadFile=Duplicate record group zzz plugin_administration_archive_duplicateNode=Duplicate nodezzz +plugin_administration_archive_eadExport=Export record group to the folder listed in the plugin configuration zzz +plugin_administration_archive_eadExportNotConfigured=Export is not configuredzzz plugin_administration_archive_eadid=EAD ID plugin_administration_archive_editorName=Editor zzz +plugin_administration_archive_exit=zzz plugin_administration_archive_extref=Link descriptionzzz plugin_administration_archive_extrefhref=Repository linkzzz plugin_administration_archive_font=Font +plugin_administration_archive_generated=Generatedzzz plugin_administration_archive_langmaterial=Language | Scripts of material -plugin_administration_archive_loadDatabase=Start editing +plugin_administration_archive_linkNodeModal=Link nodezzz +plugin_administration_archive_loadDatabase=Edit plugin_administration_archive_materialspec=Material Specific Details plugin_administration_archive_missing_Data=Incomplete data, please select database and upload EAD file zzz plugin_administration_archive_moveHierarchyDown=Move down the hierarchy plugin_administration_archive_moveHierarchyUp=Move up the hierarchy plugin_administration_archive_moveNode=Move node to another location plugin_administration_archive_moveNodeDown=Move down +plugin_administration_archive_moveNodeHere=Insert selected node as last child +plugin_administration_archive_moveNodeText=Der highlighted node will be inserted as the last child of the selected node. +plugin_administration_archive_moveNodeThis=The currently selected node plugin_administration_archive_moveNodeUp=Move up plugin_administration_archive_newNode=Insert new node +plugin_administration_archive_noArchiveSelected=No inventory was selectedzzz +plugin_administration_archive_noArchivesAvailable=No record groups available. Please first create a record group or import an existing EAD file\: plugin_administration_archive_noConnectionToDatabase=There is no connection to the BaseX database. Please check the installation and make sure that the BaseX database has been started. plugin_administration_archive_noElementSelectedHeading=No element is currently selected. plugin_administration_archive_noElementSelectedText=Please first select a node in the left-hand area that you would like to edit. @@ -2352,6 +2385,7 @@ plugin_administration_archive_nodeType_image=Image plugin_administration_archive_nodeType_other=Other document plugin_administration_archive_nodeType_video=Video document plugin_administration_archive_nodelink=Link to other nodeszzz +plugin_administration_archive_numberOfNodes=Number of nodeszzz plugin_administration_archive_oddnote=Odd notes plugin_administration_archive_originalsloc=Existence and location of originals plugin_administration_archive_originalsloc_head=Headingzzz @@ -2377,11 +2411,13 @@ plugin_administration_archive_repositoryaddressline=Address plugin_administration_archive_role=Role plugin_administration_archive_saveAndExit=Save and exit record group plugin_administration_archive_scopecontent=Scope and content -plugin_administration_archive_selectionHeading=Selection of the record group +plugin_administration_archive_selectionHeading=Archive records plugin_administration_archive_selectionText=Please first select the record group you would like to work with\: plugin_administration_archive_separatedmaterial=Related units of description +plugin_administration_archive_showAllFields=Show all fieldszzz plugin_administration_archive_show_details=Show details plugin_administration_archive_suffix=Suffixzzz +plugin_administration_archive_text=Free text plugin_administration_archive_titleproper=Title of the Finding Aidzzz plugin_administration_archive_unitdate=Date(s) plugin_administration_archive_unitdatestructured=Structured Date of the Unit @@ -2552,6 +2588,7 @@ plugin_administration_licences_name=Name plugin_administration_licences_ordernumber=Order number plugin_administration_licences_type=Type plugin_administration_licences_usage=Usage +plugin_administration_linkNodeModalDesciption=Select the node to which a reference is to be created.zzz plugin_administration_missingPermission=To view this page, you need the following permission\: plugin_administration_nli_daily_press_cancelMessageMultipleImport=The import of multiple records was cancelled. plugin_administration_nli_daily_press_cancelMessageSingleImport=The import of a single record was cancelled. @@ -2785,6 +2822,8 @@ plugin_intranda_step_imageQA_renameDescription=Please define a name part to be u plugin_intranda_step_imageQA_renameLabel=Name part plugin_intranda_step_imageQA_renameSelection=Rename selected images plugin_intranda_step_imageQA_renameTitle=Rename files +plugin_intranda_step_imageQA_reorder_previous=Swap image with previous image +plugin_intranda_step_imageQA_reorder_next=Swap image with next image plugin_intranda_step_imageQA_rotateLeft=Rotate image to the left\: plugin_intranda_step_imageQA_rotateLefteSelection=Rotate selected images to the left plugin_intranda_step_imageQA_rotateRight=Rotate image to the right\: @@ -3228,6 +3267,7 @@ prozesse=Processes prozesse.ProzesseID=Process ID prozesse.Titel=Process title prozesse.erstellungsdatum=Creation date +prozesse.sortHelperDocstructs=Number of docstructszzz prozesse.sortHelperImages=Number of images prozesse.sortHelperMetadata=Number of metadata prozesseBearbeiten=Edit processes @@ -3621,10 +3661,17 @@ vocabularyManager_addNewVocabulary=Add vocabulary zzz vocabularyManager_addRecord=Add new record vocabularyManager_backToVocabularies=Back to the list of vocabularies vocabularyManager_definition=Field definitions +vocabularyManager_deleteChildRecordsPrompt=This record contains child records. If you confirm to delete this record, all child records will be deleted as well. This can not be undone. vocabularyManager_deleteDefinition=Delete this definition vocabularyManager_deleteRecord=Delete record vocabularyManager_description=Description vocabularyManager_downloadRecords=Download records +vocabularyManager_downloadRecordsAsCsv=Download records as CSV +vocabularyManager_downloadRecordsAsExcel=Download records as Excel +vocabularyManager_downloadRecordsAsJson=Download records as JSON +vocabularyManager_downloadRecordsAsRdfTurtle=Download records as RDF/Turtle +vocabularyManager_downloadRecordsAsRdfXml=Download records as RDF/XML +vocabularyManager_editRecord=Edit record vocabularyManager_editRecords=Edit records vocabularyManager_editVocabulary=Manage vocabulary vocabularyManager_excelImport_addNew=Add all records @@ -3636,6 +3683,54 @@ vocabularyManager_excelImport_info=Existing records are updated and new records vocabularyManager_excelImport_mergeExisting=Merge existing records vocabularyManager_excelImport_removeExisting=Delete all existing records vocabularyManager_excelImport_vocabularyField=Vocabulary field +vocabularyManager_exception_DataIntegrityViolation=A data integrity violation has occurred\: {0} +vocabularyManager_exception_DeletionOfReferencedVocabulary=The vocabulary with ID "{0}" cannot be deleted because it is referenced by the following vocabularies\: "{1}" +vocabularyManager_exception_DeletionOfReferencedVocabularyRecord=The vocabulary record with ID "{0}" cannot be deleted because it is referenced by the following records\: "{1}" +vocabularyManager_exception_EntityNotFound=Could not find vocabulary "{0}" with ID "{1}" +vocabularyManager_exception_FieldDefinitionFallbackNotRequired=Vocabulary manager error {0} zzz +vocabularyManager_exception_FieldDefinitionNeitherReferenceVocabularyNorTypeNotPossible=Vocabulary manager error {0} zzz +vocabularyManager_exception_FieldDefinitionNonUniqueFallbackLanguageSpecified=Vocabulary manager error {0} zzz +vocabularyManager_exception_FieldDefinitionReferenceVocabularyAndTypeNotPossible=Vocabulary manager error {0} zzz +vocabularyManager_exception_FieldInstanceBelongsToWrongSchema=Vocabulary manager error {0} zzz +vocabularyManager_exception_FieldInstanceIsEmpty=Vocabulary manager error {0} zzz +vocabularyManager_exception_FieldInstanceIssues=There are issues validating some field(s) +vocabularyManager_exception_FieldInstanceMultipleValuesNotAllowed=Vocabulary manager error {0} zzz +vocabularyManager_exception_FieldInstanceValueIssues=There are issues validating some field values(s) +vocabularyManager_exception_FieldTypeInvalidRegexSyntax=Vocabulary manager error {0} zzz +vocabularyManager_exception_FieldTypeSelectableValuesDoNotMatchSpecifiedValidationRegex=Vocabulary manager error {0} zzz +vocabularyManager_exception_FieldValueContainsNonTranslatedValue=Vocabulary manager error {0} zzz +vocabularyManager_exception_FieldValueHasNonAllowedTranslations=Vocabulary manager error {0} zzz +vocabularyManager_exception_FieldValueIsBlank=Vocabulary manager error {0} zzz +vocabularyManager_exception_FieldValueIsNotUnique=The "{0}" field value(s) "{1}" are not unique +vocabularyManager_exception_FieldValueMissingRequiredTranslations=Vocabulary manager error {0} zzz +vocabularyManager_exception_FieldValueReferencedRecordBelongsToWrongVocabulary=Vocabulary manager error {0} zzz +vocabularyManager_exception_FieldValueReferencedRecordIssues=Vocabulary manager error {0} zzz +vocabularyManager_exception_FieldValueUnspecifiedTranslations=Vocabulary manager error {0} zzz +vocabularyManager_exception_FieldValuesAreNonSelectableValues=Vocabulary manager error {0} zzz +vocabularyManager_exception_FieldValuesDoNotMatchSpecifiedValidationRegex=The "{0}" field value(s) "{1}" do(es) not match the specified validation regex "{2}" +vocabularyManager_exception_GenericValidation=Some issues occurred during the validation phase +vocabularyManager_exception_IllegalAttributeProvided=Vocabulary manager error {0} zzz +vocabularyManager_exception_InsertingNonExistingItem=Vocabulary manager error {0} zzz +vocabularyManager_exception_Mapping=Vocabulary manager error {0} zzz +vocabularyManager_exception_MissingRequiredAttribute=Vocabulary manager error {0} zzz +vocabularyManager_exception_RecordImport=Vocabulary manager error {0} zzz +vocabularyManager_exception_RecordImportUnsupportedExcelCellType=Error during Excel import\: Unknown cell type "{0}" +vocabularyManager_exception_RecordValidation=Vocabulary manager error {0} zzz +vocabularyManager_exception_RecordValidationChildrenReferencesNotAllowed=Vocabulary manager error {0} zzz +vocabularyManager_exception_RecordValidationHierarchyIssues=Vocabulary manager error {0} zzz +vocabularyManager_exception_RecordValidationMissingRequiredFields=The following required fields were not provided\: {0} +vocabularyManager_exception_RecordValidationParentReferenceNotAllowed=Vocabulary manager error {0} zzz +vocabularyManager_exception_RecordValidationSingleRootElementVocabularyAlreadyContainsRecord=Vocabulary manager error {0} zzz +vocabularyManager_exception_RecordValidationUndefinedFieldsGiven=Vocabulary manager error {0} zzz +vocabularyManager_exception_SchemaValidationDefinitionIssues=Vocabulary manager error {0} zzz +vocabularyManager_exception_SchemaValidationMainFieldIsNotRequired=Vocabulary manager error {0} zzz +vocabularyManager_exception_SchemaValidationMissingMainField=Vocabulary manager error {0} zzz +vocabularyManager_exception_SchemaValidationNoDefinitions=Vocabulary manager error {0} zzz +vocabularyManager_exception_SchemaValidationTitleFieldsAreNotRequired=Vocabulary manager error {0} zzz +vocabularyManager_exception_SchemaValidationTooManyMainFields=Vocabulary manager error {0} zzz +vocabularyManager_exception_VocabularyValidationMetadataSchemaIsHierarchical=Vocabulary manager error {0} zzz +vocabularyManager_exception_VocabularyValidationMetadataSchemaIsNotSetToSingleRootElement=Vocabulary manager error {0} zzz +vocabularyManager_exception_VocabularyValidationMetadataSchemaIssues=Vocabulary manager error {0} zzz vocabularyManager_fieldDefinitions=Field definitions vocabularyManager_label=Label vocabularyManager_languageSelection=Language diff --git a/src/main/resources/messages_es.properties b/src/main/resources/messages_es.properties index 34c9f908d0..d54ca50c58 100644 --- a/src/main/resources/messages_es.properties +++ b/src/main/resources/messages_es.properties @@ -460,6 +460,8 @@ couldNotCreateImageFolder=No se ha podido crear la carpeta de im\u00E1genes. count=N\u00FAmero countImages=N\u00FAmero de imagenes countMetadata=N\u00FAmero de metadatos +counterFormat=zzz +counterStartValue=zzz createDoc=Generar archivo en formato Microsoft Word createExcel=Generar archivo en formato Microsoft Excel createNewBatchFromSelectedProcesses=Generar nuevo lote a partir de los procesos seleccionados @@ -698,6 +700,7 @@ exportMetsParameter=Exportar par\u00E1metros METS exportPdf=Guardar archivo PDF en el directorio del usuario zzz exportRus=Exportar Rus exportValidation=Export validation zzz +export_verb=zzz failure=Error farbschema=Esquema de colores fehler=Error @@ -1330,10 +1333,11 @@ intranda_workflow_crop=LayoutWizzard workflow plugin zzz intranda_workflow_excelimport=Yerusha Upload Plugin intranda_workflow_fileUploadProcessCreation=Carga de archivos para la generaci\u00F3n de operaciones zzz intranda_workflow_hu_importer=Importaci\u00F3n para el portal de recogida zzz +intranda_workflow_import_json=Importador JSON zzz intranda_workflow_khm_importer=KHM Importer -intranda_workflow_liechtenstein_volksblatt_importer=Zeitungsimport Liechtensteiner Volksblatt zzz intranda_workflow_massupload=Plugin para carga de archivos en masa intranda_workflow_metadata-enrichment=Actualizaci\u00F3n de enlaces de vocabulario zzz +intranda_workflow_newspaper_pages_importer=Importaci\u00F3n de peri\u00F3dicos de una sola p\u00E1gina zzz intranda_workflow_oepma_importer=\u00D6PMA Importer intranda_workflow_projectexport=Project export zzz invalidCharacter=El nombre contiene caracteres no v\u00E1lidos @@ -1408,6 +1412,9 @@ kw=SC label__named_entity=Named entity zzz label__named_entity_type=Named entity type zzz langLaufendeAufgaben=Tareas de larga duraci\u00F3n +lang_eng=zzz +lang_fre=zzz +lang_ger=zzz language=Idioma lastImage=\u00DAltima imagen zzz lastPage=\u00DAltima p\u00E1gina zzz @@ -1846,6 +1853,7 @@ mets_duplicateMetadataGroup=Duplicate this metadata group zzz mets_easyPagination=Reuse "Last Page" again as "First Page" zzz mets_editOcrForCurrentImage=Edit ocr results zzz mets_error_configuredVocabularyInvalid=Error during initialization of '{0}'\: The vocabulary '{1}' cannot be loaded.zzz +mets_error_configuredVocabularyListHierarchical=zzz mets_generation_error=zzz mets_geoname_account_inactive=La b\u00FAsqueda en la base de datos de GeoNames no pudo realizarse porque no se almacen\u00F3 ninguna informaci\u00F3n de cuenta v\u00E1lida. zzz mets_hideHiddenFields=Esconder los campos ocultos de zzz @@ -2282,6 +2290,12 @@ plugin_admin_vocabulary_noVocabularyLoaded=No hay vocabulario cargado. Por favor plugin_admin_vocabulary_select=Valores seleccionables zzz plugin_admin_vocabulary_type=Tipo zzz plugin_admin_vocabulary_validation=Expresi\u00F3n de validaci\u00F3n zzz +plugin_administration_archive_AcquisitionAgent=zzz +plugin_administration_archive_AcquisitionMethod=zzz +plugin_administration_archive_AcquisitionNotes=zzz +plugin_administration_archive_ArchivistNote=zzz +plugin_administration_archive_Conventions=zzz +plugin_administration_archive_DescriptionDates=zzz plugin_administration_archive_Number=N\u00FAmero de archivo zzz plugin_administration_archive_Shelfmark=Firma(s) zzz plugin_administration_archive_accessrestrict=Normas de acceso zzz @@ -2289,6 +2303,8 @@ plugin_administration_archive_accruals=Nuevos ingresos zzz plugin_administration_archive_accruals_head=zzz plugin_administration_archive_accruals_p=zzz plugin_administration_archive_acqinfo=Oficina de expedici\u00F3n zzz +plugin_administration_archive_addMultipleNodes=zzz +plugin_administration_archive_addNodes=zzz plugin_administration_archive_advancedSearch=zzz plugin_administration_archive_agencycode=C\u00F3digo de la agencia zzz plugin_administration_archive_altformavail=Copias o reproducciones zzz @@ -2307,8 +2323,12 @@ plugin_administration_archive_bibliography=Publicaciones zzz plugin_administration_archive_bioghist=Administrative | Biographical history zzz plugin_administration_archive_c=No se puede cargar el archivo de la base de datos. zzz plugin_administration_archive_clear=zzz +plugin_administration_archive_confirmReplacement=zzz plugin_administration_archive_conventiondeclaration=Principios de distorsi\u00F3n zzz +plugin_administration_archive_counter=zzz plugin_administration_archive_createNewArchive=Crear nuevos fondos de archivo zzz +plugin_administration_archive_createNodesModal=zzz +plugin_administration_archive_createNodesModalDesciption=zzz plugin_administration_archive_createProcesses=Crear las operaciones que faltan para todos los subnodos zzz plugin_administration_archive_creationHeading=Nuevos fondos de archivo zzz plugin_administration_archive_creation_filename=Por favor, introduzca un nombre para los fondos del archivo. zzz @@ -2321,17 +2341,25 @@ plugin_administration_archive_databaseFileMustBeCreated=Primero hay que crear un plugin_administration_archive_databaseLocked=Este archivo est\u00E1 siendo editado por otro usuario. zzz plugin_administration_archive_databaseMustBeCreated=La base de datos debe crearse primero dentro de la instancia de BaseX. zzz plugin_administration_archive_deleteNode=Eliminar el nodo zzz +plugin_administration_archive_deleteSelectedArchive=zzz plugin_administration_archive_descriptionLevel=Nivel de distorsi\u00F3n zzz plugin_administration_archive_didnote=Observaciones generales zzz plugin_administration_archive_download=Descargar como archivo EAD zzz +plugin_administration_archive_download_l=zzz +plugin_administration_archive_download_s=zzz plugin_administration_archive_duplicateEadFile=zzz plugin_administration_archive_duplicateNode=zzz +plugin_administration_archive_eadExport=zzz +plugin_administration_archive_eadExportNotConfigured=zzz plugin_administration_archive_eadid=EAD ID zzz plugin_administration_archive_editorName=Editor zzz +plugin_administration_archive_exit=zzz plugin_administration_archive_extref=zzz plugin_administration_archive_extrefhref=zzz plugin_administration_archive_font=Fuente zzz +plugin_administration_archive_generated=zzz plugin_administration_archive_langmaterial=Language | Scripts of material zzz +plugin_administration_archive_linkNodeModal=zzz plugin_administration_archive_loadDatabase=Empezar a editar zzz plugin_administration_archive_materialspec=Datos espec\u00EDficos del material zzz plugin_administration_archive_missing_Data=Incomplete data, please select database and upload EAD file zzz @@ -2339,8 +2367,13 @@ plugin_administration_archive_moveHierarchyDown=Desplazarse hacia abajo en la je plugin_administration_archive_moveHierarchyUp=Move up the hierarchy zzz plugin_administration_archive_moveNode=Mover el nodo a otro lugar zzz plugin_administration_archive_moveNodeDown=Bajar zzz +plugin_administration_archive_moveNodeHere=zzz +plugin_administration_archive_moveNodeText=zzz +plugin_administration_archive_moveNodeThis=zzz plugin_administration_archive_moveNodeUp=Subir zzz plugin_administration_archive_newNode=Insertar nuevo nodo zzz +plugin_administration_archive_noArchiveSelected=zzz +plugin_administration_archive_noArchivesAvailable=zzz plugin_administration_archive_noConnectionToDatabase=No hay conexi\u00F3n con la base de datos BaseX. Por favor, compruebe la instalaci\u00F3n y aseg\u00FArese de que la base de datos BaseX se ha iniciado. zzz plugin_administration_archive_noElementSelectedHeading=No hay ning\u00FAn elemento seleccionado. zzz plugin_administration_archive_noElementSelectedText=Por favor, seleccione primero un nodo en el \u00E1rea de la izquierda que le gustar\u00EDa editar. zzz @@ -2352,6 +2385,7 @@ plugin_administration_archive_nodeType_image=Imagen zzz plugin_administration_archive_nodeType_other=Otro documento zzz plugin_administration_archive_nodeType_video=Documento de v\u00EDdeo zzz plugin_administration_archive_nodelink=zzz +plugin_administration_archive_numberOfNodes=zzz plugin_administration_archive_oddnote=Otras observaciones zzz plugin_administration_archive_originalsloc=Lugar de almacenamiento de los originales zzz plugin_administration_archive_originalsloc_head=zzz @@ -2380,8 +2414,10 @@ plugin_administration_archive_scopecontent=Forma y contenido zzz plugin_administration_archive_selectionHeading=Selecci\u00F3n de los fondos de los archivos zzz plugin_administration_archive_selectionText=Seleccione primero los fondos de archivo con los que desea trabajar\: zzz plugin_administration_archive_separatedmaterial=Unidades de distorsi\u00F3n relacionadas zzz +plugin_administration_archive_showAllFields=zzz plugin_administration_archive_show_details=Mostrar detalles zzz plugin_administration_archive_suffix=zzz +plugin_administration_archive_text=zzz plugin_administration_archive_titleproper=zzz plugin_administration_archive_unitdate=Per\u00EDodo de origen zzz plugin_administration_archive_unitdatestructured=Fecha estructurada de la unidad zzz @@ -2552,6 +2588,7 @@ plugin_administration_licences_name=Nombre zzz plugin_administration_licences_ordernumber=N\u00FAmero de pedido zzz plugin_administration_licences_type=Tipo zzz plugin_administration_licences_usage=Consumo zzz +plugin_administration_linkNodeModalDesciption=zzz plugin_administration_missingPermission=Para ver esta p\u00E1gina, necesita el siguiente permiso\: zzz plugin_administration_nli_daily_press_cancelMessageMultipleImport=La importaci\u00F3n de m\u00FAltiples registros fue cancelada. zzz plugin_administration_nli_daily_press_cancelMessageSingleImport=Se abort\u00F3 la importaci\u00F3n de un solo registro. zzz @@ -3228,6 +3265,7 @@ prozesse=Procesos prozesse.ProzesseID=Indentificador del proceso prozesse.Titel=T\u00EDtulo del proceso prozesse.erstellungsdatum=Fecha de creaci\u00F3n +prozesse.sortHelperDocstructs=zzz prozesse.sortHelperImages=N\u00FAmero de im\u00E1genes prozesse.sortHelperMetadata=N\u00FAmero de metadatos prozesseBearbeiten=Editar procesos @@ -3621,10 +3659,17 @@ vocabularyManager_addNewVocabulary=Add new vocabulary zzz vocabularyManager_addRecord=Add new record zzz vocabularyManager_backToVocabularies=Back to the list of vocabularies zzz vocabularyManager_definition=Field definitions zzz +vocabularyManager_deleteChildRecordsPrompt=zzz vocabularyManager_deleteDefinition=Delete this definition zzz vocabularyManager_deleteRecord=Delete record zzz vocabularyManager_description=Description zzz vocabularyManager_downloadRecords=Download records zzz +vocabularyManager_downloadRecordsAsCsv=zzz +vocabularyManager_downloadRecordsAsExcel=zzz +vocabularyManager_downloadRecordsAsJson=zzz +vocabularyManager_downloadRecordsAsRdfTurtle=zzz +vocabularyManager_downloadRecordsAsRdfXml=zzz +vocabularyManager_editRecord=zzz vocabularyManager_editRecords=Edit records zzz vocabularyManager_editVocabulary=Manage vocabulary zzz vocabularyManager_excelImport_addNew=Add all records zzz @@ -3636,6 +3681,54 @@ vocabularyManager_excelImport_info=Existing records are updated and new records vocabularyManager_excelImport_mergeExisting=Merge existing records zzz vocabularyManager_excelImport_removeExisting=Delete all existing records zzz vocabularyManager_excelImport_vocabularyField=Vocabulary field zzz +vocabularyManager_exception_DataIntegrityViolation=zzz +vocabularyManager_exception_DeletionOfReferencedVocabulary=zzz +vocabularyManager_exception_DeletionOfReferencedVocabularyRecord=zzz +vocabularyManager_exception_EntityNotFound=zzz +vocabularyManager_exception_FieldDefinitionFallbackNotRequired=zzz +vocabularyManager_exception_FieldDefinitionNeitherReferenceVocabularyNorTypeNotPossible=zzz +vocabularyManager_exception_FieldDefinitionNonUniqueFallbackLanguageSpecified=zzz +vocabularyManager_exception_FieldDefinitionReferenceVocabularyAndTypeNotPossible=zzz +vocabularyManager_exception_FieldInstanceBelongsToWrongSchema=zzz +vocabularyManager_exception_FieldInstanceIsEmpty=zzz +vocabularyManager_exception_FieldInstanceIssues=zzz +vocabularyManager_exception_FieldInstanceMultipleValuesNotAllowed=zzz +vocabularyManager_exception_FieldInstanceValueIssues=zzz +vocabularyManager_exception_FieldTypeInvalidRegexSyntax=zzz +vocabularyManager_exception_FieldTypeSelectableValuesDoNotMatchSpecifiedValidationRegex=zzz +vocabularyManager_exception_FieldValueContainsNonTranslatedValue=zzz +vocabularyManager_exception_FieldValueHasNonAllowedTranslations=zzz +vocabularyManager_exception_FieldValueIsBlank=zzz +vocabularyManager_exception_FieldValueIsNotUnique=zzz +vocabularyManager_exception_FieldValueMissingRequiredTranslations=zzz +vocabularyManager_exception_FieldValueReferencedRecordBelongsToWrongVocabulary=zzz +vocabularyManager_exception_FieldValueReferencedRecordIssues=zzz +vocabularyManager_exception_FieldValueUnspecifiedTranslations=zzz +vocabularyManager_exception_FieldValuesAreNonSelectableValues=zzz +vocabularyManager_exception_FieldValuesDoNotMatchSpecifiedValidationRegex=zzz +vocabularyManager_exception_GenericValidation=zzz +vocabularyManager_exception_IllegalAttributeProvided=zzz +vocabularyManager_exception_InsertingNonExistingItem=zzz +vocabularyManager_exception_Mapping=zzz +vocabularyManager_exception_MissingRequiredAttribute=zzz +vocabularyManager_exception_RecordImport=zzz +vocabularyManager_exception_RecordImportUnsupportedExcelCellType=zzz +vocabularyManager_exception_RecordValidation=zzz +vocabularyManager_exception_RecordValidationChildrenReferencesNotAllowed=zzz +vocabularyManager_exception_RecordValidationHierarchyIssues=zzz +vocabularyManager_exception_RecordValidationMissingRequiredFields=zzz +vocabularyManager_exception_RecordValidationParentReferenceNotAllowed=zzz +vocabularyManager_exception_RecordValidationSingleRootElementVocabularyAlreadyContainsRecord=zzz +vocabularyManager_exception_RecordValidationUndefinedFieldsGiven=zzz +vocabularyManager_exception_SchemaValidationDefinitionIssues=zzz +vocabularyManager_exception_SchemaValidationMainFieldIsNotRequired=zzz +vocabularyManager_exception_SchemaValidationMissingMainField=zzz +vocabularyManager_exception_SchemaValidationNoDefinitions=zzz +vocabularyManager_exception_SchemaValidationTitleFieldsAreNotRequired=zzz +vocabularyManager_exception_SchemaValidationTooManyMainFields=zzz +vocabularyManager_exception_VocabularyValidationMetadataSchemaIsHierarchical=zzz +vocabularyManager_exception_VocabularyValidationMetadataSchemaIsNotSetToSingleRootElement=zzz +vocabularyManager_exception_VocabularyValidationMetadataSchemaIssues=zzz vocabularyManager_fieldDefinitions=Field definitions zzz vocabularyManager_label=Label zzz vocabularyManager_languageSelection=Language zzz diff --git a/src/main/resources/messages_fr.properties b/src/main/resources/messages_fr.properties index 23ffde99aa..6c36829e1d 100644 --- a/src/main/resources/messages_fr.properties +++ b/src/main/resources/messages_fr.properties @@ -460,6 +460,8 @@ couldNotCreateImageFolder=The directory for the images could not be created. zzz count=Count zzz countImages=Number of images zzz countMetadata=Number of metadata zzz +counterFormat=zzz +counterStartValue=zzz createDoc=Generate Microsoft Word file zzz createExcel=Generate Microsoft Excel file zzz createNewBatchFromSelectedProcesses=Create new batch from selected processes zzz @@ -698,6 +700,7 @@ exportMetsParameter=Export METS parameters zzz exportPdf=Save PDF file in user directory zzz exportRus=Export Rus zzz exportValidation=Export validation zzz +export_verb=zzz failure=Error zzz farbschema=Colour scheme zzz fehler=Error zzz @@ -1330,10 +1333,11 @@ intranda_workflow_crop=LayoutWizzard workflow plugin zzz intranda_workflow_excelimport=Yerusha Upload Plugin zzz intranda_workflow_fileUploadProcessCreation=T\u00E9l\u00E9chargement de fichiers pour la g\u00E9n\u00E9ration d'op\u00E9rations zzz intranda_workflow_hu_importer=Importation pour le portail des collections zzz +intranda_workflow_import_json=Importateur JSON zzz intranda_workflow_khm_importer=KHM Importer -intranda_workflow_liechtenstein_volksblatt_importer=Zeitungsimport Liechtensteiner Volksblatt zzz intranda_workflow_massupload=Mass upload plugin zzz intranda_workflow_metadata-enrichment=Mise \u00E0 jour des liens de vocabulaire zzz +intranda_workflow_newspaper_pages_importer=Importation de journaux pour des pages individuelles zzz intranda_workflow_oepma_importer=\u00D6PMA Importer intranda_workflow_projectexport=Project export zzz invalidCharacter=The name contains invalid characters zzz @@ -1408,6 +1412,9 @@ kw=W zzz label__named_entity=Named entity zzz label__named_entity_type=Named entity type zzz langLaufendeAufgaben=Long-running tasks zzz +lang_eng=zzz +lang_fre=zzz +lang_ger=zzz language=Language zzz lastImage=Last image zzz lastPage=Last page zzz @@ -1846,6 +1853,7 @@ mets_duplicateMetadataGroup=Duplicate this metadata group zzz mets_easyPagination=Reuse "Last Page" again as "First Page" zzz mets_editOcrForCurrentImage=Edit ocr results zzz mets_error_configuredVocabularyInvalid=Error during initialization of '{0}'\: The vocabulary '{1}' cannot be loaded. zzz +mets_error_configuredVocabularyListHierarchical=zzz mets_generation_error=zzz mets_geoname_account_inactive=The search in the GeoNames database could not be carried out because no valid account information was stored. zzz mets_hideHiddenFields=Don't show hidden fields zzz @@ -2282,6 +2290,12 @@ plugin_admin_vocabulary_noVocabularyLoaded=Currently, there is no vocabulary loa plugin_admin_vocabulary_select=Selectable values zzz plugin_admin_vocabulary_type=Type zzz plugin_admin_vocabulary_validation=Validation expression zzz +plugin_administration_archive_AcquisitionAgent=zzz +plugin_administration_archive_AcquisitionMethod=zzz +plugin_administration_archive_AcquisitionNotes=zzz +plugin_administration_archive_ArchivistNote=zzz +plugin_administration_archive_Conventions=zzz +plugin_administration_archive_DescriptionDates=zzz plugin_administration_archive_Number=Num\u00E9ro d'archive zzz plugin_administration_archive_Shelfmark=R\u00E9f\u00E9rence plugin_administration_archive_accessrestrict=Conditions d'acc\u00E8s @@ -2289,6 +2303,8 @@ plugin_administration_archive_accruals=Accroissements plugin_administration_archive_accruals_head=zzz plugin_administration_archive_accruals_p=zzz plugin_administration_archive_acqinfo=Modalit\u00E9s d'entr\u00E9e +plugin_administration_archive_addMultipleNodes=zzz +plugin_administration_archive_addNodes=zzz plugin_administration_archive_advancedSearch=zzz plugin_administration_archive_agencycode=Code de l'agence zzz plugin_administration_archive_altformavail=Existence et lieu de conservation de copies @@ -2307,8 +2323,12 @@ plugin_administration_archive_bibliography=Bibliographie plugin_administration_archive_bioghist=Histoire administrative/Notice biographique plugin_administration_archive_c=Le fichier de la base de donn\u00E9es ne peut pas \u00EAtre charg\u00E9. zzz plugin_administration_archive_clear=zzz +plugin_administration_archive_confirmReplacement=zzz plugin_administration_archive_conventiondeclaration=Principes de distorsion zzz +plugin_administration_archive_counter=zzz plugin_administration_archive_createNewArchive=Cr\u00E9er de nouveaux fonds d'archives zzz +plugin_administration_archive_createNodesModal=zzz +plugin_administration_archive_createNodesModalDesciption=zzz plugin_administration_archive_createProcesses=Cr\u00E9er les op\u00E9rations manquantes pour tous les sous-n\u0153uds zzz plugin_administration_archive_creationHeading=Nouveaux fonds d'archives zzz plugin_administration_archive_creation_filename=Veuillez entrer un nom pour les fonds d'archives. zzz @@ -2321,17 +2341,25 @@ plugin_administration_archive_databaseFileMustBeCreated=Un fichier de base de do plugin_administration_archive_databaseLocked=Ce fichier est en cours d'\u00E9dition par un autre utilisateur. zzz plugin_administration_archive_databaseMustBeCreated=Database must first be created in baseX. Please read the installation guide. zzz plugin_administration_archive_deleteNode=Supprimer le n\u0153ud zzz +plugin_administration_archive_deleteSelectedArchive=zzz plugin_administration_archive_descriptionLevel=Niveau de description plugin_administration_archive_didnote=Notes plugin_administration_archive_download=T\u00E9l\u00E9charger comme fichier EAD zzz +plugin_administration_archive_download_l=zzz +plugin_administration_archive_download_s=zzz plugin_administration_archive_duplicateEadFile=zzz plugin_administration_archive_duplicateNode=zzz +plugin_administration_archive_eadExport=zzz +plugin_administration_archive_eadExportNotConfigured=zzz plugin_administration_archive_eadid=EAD ID zzz plugin_administration_archive_editorName=R\u00E9dacteur en chef zzz +plugin_administration_archive_exit=zzz plugin_administration_archive_extref=zzz plugin_administration_archive_extrefhref=zzz plugin_administration_archive_font=Police zzz +plugin_administration_archive_generated=zzz plugin_administration_archive_langmaterial=Langue et \u00E9criture des documents +plugin_administration_archive_linkNodeModal=zzz plugin_administration_archive_loadDatabase=Commencer le montage zzz plugin_administration_archive_materialspec=Donn\u00E9es sp\u00E9cifiques aux mat\u00E9riaux zzz plugin_administration_archive_missing_Data=Incomplete data, please select database and upload EAD file zzz @@ -2339,8 +2367,13 @@ plugin_administration_archive_moveHierarchyDown=Descendre dans la hi\u00E9rarchi plugin_administration_archive_moveHierarchyUp=Monter dans la hi\u00E9rarchie zzz plugin_administration_archive_moveNode=D\u00E9placer le n\u0153ud vers un autre endroit zzz plugin_administration_archive_moveNodeDown=Descendre zzz +plugin_administration_archive_moveNodeHere=zzz +plugin_administration_archive_moveNodeText=zzz +plugin_administration_archive_moveNodeThis=zzz plugin_administration_archive_moveNodeUp=Aller vers le haut zzz plugin_administration_archive_newNode=Ins\u00E9rer un nouveau n\u0153ud zzz +plugin_administration_archive_noArchiveSelected=zzz +plugin_administration_archive_noArchivesAvailable=zzz plugin_administration_archive_noConnectionToDatabase=Il n'y a pas de connexion \u00E0 la base de donn\u00E9es BaseX. Veuillez v\u00E9rifier l'installation et vous assurer que la base de donn\u00E9es BaseX a \u00E9t\u00E9 lanc\u00E9e. zzz plugin_administration_archive_noElementSelectedHeading=Aucun \u00E9l\u00E9ment n'est actuellement s\u00E9lectionn\u00E9. zzz plugin_administration_archive_noElementSelectedText=Veuillez d'abord s\u00E9lectionner dans la zone de gauche un n\u0153ud que vous souhaitez modifier. zzz @@ -2352,6 +2385,7 @@ plugin_administration_archive_nodeType_image=Image zzz plugin_administration_archive_nodeType_other=Autre document zzz plugin_administration_archive_nodeType_video=Document vid\u00E9o zzz plugin_administration_archive_nodelink=zzz +plugin_administration_archive_numberOfNodes=zzz plugin_administration_archive_oddnote=Autres remarques zzz plugin_administration_archive_originalsloc=Existence et lieu de conservation des originaux plugin_administration_archive_originalsloc_head=zzz @@ -2380,8 +2414,10 @@ plugin_administration_archive_scopecontent=Pr\u00E9sentation du contenu plugin_administration_archive_selectionHeading=S\u00E9lection des fonds d'archives zzz plugin_administration_archive_selectionText=Veuillez d'abord s\u00E9lectionner les fonds d'archives avec lesquels vous souhaitez travailler \: zzz plugin_administration_archive_separatedmaterial=Sources compl\u00E9mentaires +plugin_administration_archive_showAllFields=zzz plugin_administration_archive_show_details=Afficher les d\u00E9tails zzz plugin_administration_archive_suffix=zzz +plugin_administration_archive_text=zzz plugin_administration_archive_titleproper=zzz plugin_administration_archive_unitdate=Dates plugin_administration_archive_unitdatestructured=Date de l'unit\u00E9 structur\u00E9e zzz @@ -2552,6 +2588,7 @@ plugin_administration_licences_name=Nom zzz plugin_administration_licences_ordernumber=Num\u00E9ro de commande zzz plugin_administration_licences_type=Type zzz plugin_administration_licences_usage=Consommation zzz +plugin_administration_linkNodeModalDesciption=zzz plugin_administration_missingPermission=To view this page, you need the following permission\: zzz plugin_administration_nli_daily_press_cancelMessageMultipleImport=The import of multiple records was cancelled. zzz plugin_administration_nli_daily_press_cancelMessageSingleImport=The import of a single record was cancelled. zzz @@ -3228,6 +3265,7 @@ prozesse=Processes zzz prozesse.ProzesseID=Process ID zzz prozesse.Titel=Process title zzz prozesse.erstellungsdatum=Creation date zzz +prozesse.sortHelperDocstructs=zzz prozesse.sortHelperImages=Number of images zzz prozesse.sortHelperMetadata=Number of metadata zzz prozesseBearbeiten=Edit processes zzz @@ -3621,10 +3659,17 @@ vocabularyManager_addNewVocabulary=Add new vocabulary zzz vocabularyManager_addRecord=Add new record zzz vocabularyManager_backToVocabularies=Back to the list of vocabularies zzz vocabularyManager_definition=Field definitions zzz +vocabularyManager_deleteChildRecordsPrompt=zzz vocabularyManager_deleteDefinition=Delete this definition zzz vocabularyManager_deleteRecord=Delete record zzz vocabularyManager_description=Description zzz vocabularyManager_downloadRecords=Download records zzz +vocabularyManager_downloadRecordsAsCsv=zzz +vocabularyManager_downloadRecordsAsExcel=zzz +vocabularyManager_downloadRecordsAsJson=zzz +vocabularyManager_downloadRecordsAsRdfTurtle=zzz +vocabularyManager_downloadRecordsAsRdfXml=zzz +vocabularyManager_editRecord=zzz vocabularyManager_editRecords=Edit records zzz vocabularyManager_editVocabulary=Manage vocabulary zzz vocabularyManager_excelImport_addNew=Add all records zzz @@ -3636,6 +3681,54 @@ vocabularyManager_excelImport_info=Existing records are updated and new records vocabularyManager_excelImport_mergeExisting=Merge existing records zzz vocabularyManager_excelImport_removeExisting=Delete all existing records zzz vocabularyManager_excelImport_vocabularyField=Vocabulary field zzz +vocabularyManager_exception_DataIntegrityViolation=zzz +vocabularyManager_exception_DeletionOfReferencedVocabulary=zzz +vocabularyManager_exception_DeletionOfReferencedVocabularyRecord=zzz +vocabularyManager_exception_EntityNotFound=zzz +vocabularyManager_exception_FieldDefinitionFallbackNotRequired=zzz +vocabularyManager_exception_FieldDefinitionNeitherReferenceVocabularyNorTypeNotPossible=zzz +vocabularyManager_exception_FieldDefinitionNonUniqueFallbackLanguageSpecified=zzz +vocabularyManager_exception_FieldDefinitionReferenceVocabularyAndTypeNotPossible=zzz +vocabularyManager_exception_FieldInstanceBelongsToWrongSchema=zzz +vocabularyManager_exception_FieldInstanceIsEmpty=zzz +vocabularyManager_exception_FieldInstanceIssues=zzz +vocabularyManager_exception_FieldInstanceMultipleValuesNotAllowed=zzz +vocabularyManager_exception_FieldInstanceValueIssues=zzz +vocabularyManager_exception_FieldTypeInvalidRegexSyntax=zzz +vocabularyManager_exception_FieldTypeSelectableValuesDoNotMatchSpecifiedValidationRegex=zzz +vocabularyManager_exception_FieldValueContainsNonTranslatedValue=zzz +vocabularyManager_exception_FieldValueHasNonAllowedTranslations=zzz +vocabularyManager_exception_FieldValueIsBlank=zzz +vocabularyManager_exception_FieldValueIsNotUnique=zzz +vocabularyManager_exception_FieldValueMissingRequiredTranslations=zzz +vocabularyManager_exception_FieldValueReferencedRecordBelongsToWrongVocabulary=zzz +vocabularyManager_exception_FieldValueReferencedRecordIssues=zzz +vocabularyManager_exception_FieldValueUnspecifiedTranslations=zzz +vocabularyManager_exception_FieldValuesAreNonSelectableValues=zzz +vocabularyManager_exception_FieldValuesDoNotMatchSpecifiedValidationRegex=zzz +vocabularyManager_exception_GenericValidation=zzz +vocabularyManager_exception_IllegalAttributeProvided=zzz +vocabularyManager_exception_InsertingNonExistingItem=zzz +vocabularyManager_exception_Mapping=zzz +vocabularyManager_exception_MissingRequiredAttribute=zzz +vocabularyManager_exception_RecordImport=zzz +vocabularyManager_exception_RecordImportUnsupportedExcelCellType=zzz +vocabularyManager_exception_RecordValidation=zzz +vocabularyManager_exception_RecordValidationChildrenReferencesNotAllowed=zzz +vocabularyManager_exception_RecordValidationHierarchyIssues=zzz +vocabularyManager_exception_RecordValidationMissingRequiredFields=zzz +vocabularyManager_exception_RecordValidationParentReferenceNotAllowed=zzz +vocabularyManager_exception_RecordValidationSingleRootElementVocabularyAlreadyContainsRecord=zzz +vocabularyManager_exception_RecordValidationUndefinedFieldsGiven=zzz +vocabularyManager_exception_SchemaValidationDefinitionIssues=zzz +vocabularyManager_exception_SchemaValidationMainFieldIsNotRequired=zzz +vocabularyManager_exception_SchemaValidationMissingMainField=zzz +vocabularyManager_exception_SchemaValidationNoDefinitions=zzz +vocabularyManager_exception_SchemaValidationTitleFieldsAreNotRequired=zzz +vocabularyManager_exception_SchemaValidationTooManyMainFields=zzz +vocabularyManager_exception_VocabularyValidationMetadataSchemaIsHierarchical=zzz +vocabularyManager_exception_VocabularyValidationMetadataSchemaIsNotSetToSingleRootElement=zzz +vocabularyManager_exception_VocabularyValidationMetadataSchemaIssues=zzz vocabularyManager_fieldDefinitions=Field definitions zzz vocabularyManager_label=Label zzz vocabularyManager_languageSelection=Language zzz diff --git a/src/main/resources/messages_it.properties b/src/main/resources/messages_it.properties index c0dd050fbf..8acba10916 100644 --- a/src/main/resources/messages_it.properties +++ b/src/main/resources/messages_it.properties @@ -460,6 +460,8 @@ couldNotCreateImageFolder=Non \u00E8 stato possibile creare la directory per le count=Quantit\u00E0 zzz countImages=Numero di immagini zzz countMetadata=Numero di metadati zzz +counterFormat=zzz +counterStartValue=zzz createDoc=Creare file in formato Microsoft Word zzz createExcel=Creare un file in formato Microsoft Excel zzz createNewBatchFromSelectedProcesses=Creare un nuovo lotto dalle operazioni selezionate zzz @@ -698,6 +700,7 @@ exportMetsParameter=Esportazione dei parametri METS zzz exportPdf=Salvare il file PDF nella directory utente zzz exportRus=Esportazione Rus zzz exportValidation=Export validation zzz +export_verb=zzz failure=Errore zzz farbschema=Schema dei colori zzz fehler=Errore zzz @@ -1330,10 +1333,11 @@ intranda_workflow_crop=LayoutWizzard workflow plugin zzz intranda_workflow_excelimport=Plugin per il caricamento di Yerusha zzz intranda_workflow_fileUploadProcessCreation=Caricamento di file per la generazione di operazioni zzz intranda_workflow_hu_importer=Importazione per il portale di raccolta zzz +intranda_workflow_import_json=Importatore JSON zzz intranda_workflow_khm_importer=KHM Importer -intranda_workflow_liechtenstein_volksblatt_importer=Zeitungsimport Liechtensteiner Volksblatt zzz intranda_workflow_massupload=Plugin per l'upload di massa zzz intranda_workflow_metadata-enrichment=Aggiornamento dei link al vocabolario zzz +intranda_workflow_newspaper_pages_importer=Importazione di giornali per pagine singole zzz intranda_workflow_oepma_importer=\u00D6PMA Importer intranda_workflow_projectexport=Project export zzz invalidCharacter=Il nome contiene caratteri non validi zzz @@ -1408,6 +1412,9 @@ kw=KW zzz label__named_entity=Named entity zzz label__named_entity_type=Named entity type zzz langLaufendeAufgaben=Compiti a lungo termine zzz +lang_eng=zzz +lang_fre=zzz +lang_ger=zzz language=Lingua zzz lastImage=Ultima foto zzz lastPage=Ultima pagina zzz @@ -1846,6 +1853,7 @@ mets_duplicateMetadataGroup=Duplicate this metadata group zzz mets_easyPagination=Reuse "Last Page" again as "First Page" zzz mets_editOcrForCurrentImage=Edit ocr results zzz mets_error_configuredVocabularyInvalid=Error during initialization of '{0}'\: The vocabulary '{1}' cannot be loaded.zzz +mets_error_configuredVocabularyListHierarchical=zzz mets_generation_error=zzz mets_geoname_account_inactive=La ricerca nella banca dati GeoNames non ha potuto essere effettuata perch\u00E9 non sono state memorizzate informazioni valide sul conto. zzz mets_hideHiddenFields=Nascondere i campi nascosti da zzz @@ -2282,6 +2290,12 @@ plugin_admin_vocabulary_noVocabularyLoaded=Nessun vocabolario \u00E8 caricato. S plugin_admin_vocabulary_select=Valori selezionabili zzz plugin_admin_vocabulary_type=Tipo zzz plugin_admin_vocabulary_validation=Stampa di convalida zzz +plugin_administration_archive_AcquisitionAgent=zzz +plugin_administration_archive_AcquisitionMethod=zzz +plugin_administration_archive_AcquisitionNotes=zzz +plugin_administration_archive_ArchivistNote=zzz +plugin_administration_archive_Conventions=zzz +plugin_administration_archive_DescriptionDates=zzz plugin_administration_archive_Number=Numero d'archivio zzz plugin_administration_archive_Shelfmark=Firma(e) zzz plugin_administration_archive_accessrestrict=Regolamenti di accesso zzz @@ -2289,6 +2303,8 @@ plugin_administration_archive_accruals=Nuovi arrivi zzz plugin_administration_archive_accruals_head=zzz plugin_administration_archive_accruals_p=zzz plugin_administration_archive_acqinfo=Ufficio di emissione zzz +plugin_administration_archive_addMultipleNodes=zzz +plugin_administration_archive_addNodes=zzz plugin_administration_archive_advancedSearch=zzz plugin_administration_archive_agencycode=Codice dell'agenzia zzz plugin_administration_archive_altformavail=Copie o riproduzioni zzz @@ -2307,8 +2323,12 @@ plugin_administration_archive_bibliography=Pubblicazioni zzz plugin_administration_archive_bioghist=Administrative | Biographical history zzz plugin_administration_archive_c=Il file del database non pu\u00F2 essere caricato. zzz plugin_administration_archive_clear=zzz +plugin_administration_archive_confirmReplacement=zzz plugin_administration_archive_conventiondeclaration=Principi di distorsione zzz +plugin_administration_archive_counter=zzz plugin_administration_archive_createNewArchive=Creare nuovi fondi d'archivio zzz +plugin_administration_archive_createNodesModal=zzz +plugin_administration_archive_createNodesModalDesciption=zzz plugin_administration_archive_createProcesses=Creare operazioni mancanti per tutti i sotto-nodi zzz plugin_administration_archive_creationHeading=Nuovi fondi d'archivio zzz plugin_administration_archive_creation_filename=Si prega di inserire un nome per i fondi dell'archivio. zzz @@ -2321,17 +2341,25 @@ plugin_administration_archive_databaseFileMustBeCreated=Si deve prima creare un plugin_administration_archive_databaseLocked=Questo file \u00E8 attualmente modificato da un altro utente. zzz plugin_administration_archive_databaseMustBeCreated=Il database deve essere prima creato all'interno dell'istanza di BaseX. zzz plugin_administration_archive_deleteNode=Cancellare il nodo zzz +plugin_administration_archive_deleteSelectedArchive=zzz plugin_administration_archive_descriptionLevel=Livello di distorsione zzz plugin_administration_archive_didnote=Osservazioni generali zzz plugin_administration_archive_download=Scaricare come file EAD zzz +plugin_administration_archive_download_l=zzz +plugin_administration_archive_download_s=zzz plugin_administration_archive_duplicateEadFile=zzz plugin_administration_archive_duplicateNode=zzz +plugin_administration_archive_eadExport=zzz +plugin_administration_archive_eadExportNotConfigured=zzz plugin_administration_archive_eadid=EAD ID zzz plugin_administration_archive_editorName=Editore zzz +plugin_administration_archive_exit=zzz plugin_administration_archive_extref=zzz plugin_administration_archive_extrefhref=zzz plugin_administration_archive_font=Font zzz +plugin_administration_archive_generated=zzz plugin_administration_archive_langmaterial=Language | Scripts of material zzz +plugin_administration_archive_linkNodeModal=zzz plugin_administration_archive_loadDatabase=Iniziare il montaggio zzz plugin_administration_archive_materialspec=Dati specifici del materiale zzz plugin_administration_archive_missing_Data=Incomplete data, please select database and upload EAD file zzz @@ -2339,8 +2367,13 @@ plugin_administration_archive_moveHierarchyDown=Scendere nella gerarchia zzz plugin_administration_archive_moveHierarchyUp=Salire nella gerarchia zzz plugin_administration_archive_moveNode=Spostare il nodo in un altro posto zzz plugin_administration_archive_moveNodeDown=Spostarsi verso il basso zzz +plugin_administration_archive_moveNodeHere=zzz +plugin_administration_archive_moveNodeText=zzz +plugin_administration_archive_moveNodeThis=zzz plugin_administration_archive_moveNodeUp=Muoversi verso l'alto zzz plugin_administration_archive_newNode=Inserire un nuovo nodo zzz +plugin_administration_archive_noArchiveSelected=zzz +plugin_administration_archive_noArchivesAvailable=zzz plugin_administration_archive_noConnectionToDatabase=Non c'\u00E8 nessuna connessione al database di BaseX. Controlla l'installazione e assicurati che il database di BaseX sia stato avviato. zzz plugin_administration_archive_noElementSelectedHeading=Nessun elemento \u00E8 attualmente selezionato. zzz plugin_administration_archive_noElementSelectedText=Seleziona prima un nodo nell'area di sinistra che vorresti modificare. zzz @@ -2352,6 +2385,7 @@ plugin_administration_archive_nodeType_image=Immagine zzz plugin_administration_archive_nodeType_other=Altro documento zzz plugin_administration_archive_nodeType_video=Documento video zzz plugin_administration_archive_nodelink=zzz +plugin_administration_archive_numberOfNodes=zzz plugin_administration_archive_oddnote=Ulteriori osservazioni zzz plugin_administration_archive_originalsloc=Luogo di conservazione degli originali zzz plugin_administration_archive_originalsloc_head=zzz @@ -2380,8 +2414,10 @@ plugin_administration_archive_scopecontent=Forma e contenuto zzz plugin_administration_archive_selectionHeading=Selezione dei fondi dell'archivio zzz plugin_administration_archive_selectionText=Per prima cosa seleziona i fondi dell'archivio con cui vorresti lavorare\: zzz plugin_administration_archive_separatedmaterial=Unit\u00E0 di distorsione correlate zzz +plugin_administration_archive_showAllFields=zzz plugin_administration_archive_show_details=Mostra i dettagli zzz plugin_administration_archive_suffix=zzz +plugin_administration_archive_text=zzz plugin_administration_archive_titleproper=zzz plugin_administration_archive_unitdate=Periodo di origine zzz plugin_administration_archive_unitdatestructured=Data strutturata dell'unit\u00E0 zzz @@ -2552,6 +2588,7 @@ plugin_administration_licences_name=Nome zzz plugin_administration_licences_ordernumber=Numero d'ordine zzz plugin_administration_licences_type=Tipo zzz plugin_administration_licences_usage=Consumo zzz +plugin_administration_linkNodeModalDesciption=zzz plugin_administration_missingPermission=Per visualizzare questa pagina, \u00E8 necessaria la seguente autorizzazione\: zzz plugin_administration_nli_daily_press_cancelMessageMultipleImport=L'importazione di pi\u00F9 registrazioni \u00E8 stata annullata. zzz plugin_administration_nli_daily_press_cancelMessageSingleImport=L'importazione di un singolo record \u00E8 stata interrotta. zzz @@ -3228,6 +3265,7 @@ prozesse=Eventi zzz prozesse.ProzesseID=ID transazione zzz prozesse.Titel=Titolo della transazione zzz prozesse.erstellungsdatum=Data di creazione zzz +prozesse.sortHelperDocstructs=zzz prozesse.sortHelperImages=Numero di immagini zzz prozesse.sortHelperMetadata=Numero di metadati zzz prozesseBearbeiten=Modificare i processi zzz @@ -3621,10 +3659,17 @@ vocabularyManager_addNewVocabulary=Add new vocabulary zzz vocabularyManager_addRecord=Add new record zzz vocabularyManager_backToVocabularies=Back to the list of vocabularies zzz vocabularyManager_definition=Field definitions zzz +vocabularyManager_deleteChildRecordsPrompt=zzz vocabularyManager_deleteDefinition=Delete this definition zzz vocabularyManager_deleteRecord=Delete record zzz vocabularyManager_description=Description zzz vocabularyManager_downloadRecords=Download records zzz +vocabularyManager_downloadRecordsAsCsv=zzz +vocabularyManager_downloadRecordsAsExcel=zzz +vocabularyManager_downloadRecordsAsJson=zzz +vocabularyManager_downloadRecordsAsRdfTurtle=zzz +vocabularyManager_downloadRecordsAsRdfXml=zzz +vocabularyManager_editRecord=zzz vocabularyManager_editRecords=Edit records zzz vocabularyManager_editVocabulary=Manage vocabulary zzz vocabularyManager_excelImport_addNew=Add all records zzz @@ -3636,6 +3681,54 @@ vocabularyManager_excelImport_info=Existing records are updated and new records vocabularyManager_excelImport_mergeExisting=Merge existing records zzz vocabularyManager_excelImport_removeExisting=Delete all existing records zzz vocabularyManager_excelImport_vocabularyField=Vocabulary field zzz +vocabularyManager_exception_DataIntegrityViolation=zzz +vocabularyManager_exception_DeletionOfReferencedVocabulary=zzz +vocabularyManager_exception_DeletionOfReferencedVocabularyRecord=zzz +vocabularyManager_exception_EntityNotFound=zzz +vocabularyManager_exception_FieldDefinitionFallbackNotRequired=zzz +vocabularyManager_exception_FieldDefinitionNeitherReferenceVocabularyNorTypeNotPossible=zzz +vocabularyManager_exception_FieldDefinitionNonUniqueFallbackLanguageSpecified=zzz +vocabularyManager_exception_FieldDefinitionReferenceVocabularyAndTypeNotPossible=zzz +vocabularyManager_exception_FieldInstanceBelongsToWrongSchema=zzz +vocabularyManager_exception_FieldInstanceIsEmpty=zzz +vocabularyManager_exception_FieldInstanceIssues=zzz +vocabularyManager_exception_FieldInstanceMultipleValuesNotAllowed=zzz +vocabularyManager_exception_FieldInstanceValueIssues=zzz +vocabularyManager_exception_FieldTypeInvalidRegexSyntax=zzz +vocabularyManager_exception_FieldTypeSelectableValuesDoNotMatchSpecifiedValidationRegex=zzz +vocabularyManager_exception_FieldValueContainsNonTranslatedValue=zzz +vocabularyManager_exception_FieldValueHasNonAllowedTranslations=zzz +vocabularyManager_exception_FieldValueIsBlank=zzz +vocabularyManager_exception_FieldValueIsNotUnique=zzz +vocabularyManager_exception_FieldValueMissingRequiredTranslations=zzz +vocabularyManager_exception_FieldValueReferencedRecordBelongsToWrongVocabulary=zzz +vocabularyManager_exception_FieldValueReferencedRecordIssues=zzz +vocabularyManager_exception_FieldValueUnspecifiedTranslations=zzz +vocabularyManager_exception_FieldValuesAreNonSelectableValues=zzz +vocabularyManager_exception_FieldValuesDoNotMatchSpecifiedValidationRegex=zzz +vocabularyManager_exception_GenericValidation=zzz +vocabularyManager_exception_IllegalAttributeProvided=zzz +vocabularyManager_exception_InsertingNonExistingItem=zzz +vocabularyManager_exception_Mapping=zzz +vocabularyManager_exception_MissingRequiredAttribute=zzz +vocabularyManager_exception_RecordImport=zzz +vocabularyManager_exception_RecordImportUnsupportedExcelCellType=zzz +vocabularyManager_exception_RecordValidation=zzz +vocabularyManager_exception_RecordValidationChildrenReferencesNotAllowed=zzz +vocabularyManager_exception_RecordValidationHierarchyIssues=zzz +vocabularyManager_exception_RecordValidationMissingRequiredFields=zzz +vocabularyManager_exception_RecordValidationParentReferenceNotAllowed=zzz +vocabularyManager_exception_RecordValidationSingleRootElementVocabularyAlreadyContainsRecord=zzz +vocabularyManager_exception_RecordValidationUndefinedFieldsGiven=zzz +vocabularyManager_exception_SchemaValidationDefinitionIssues=zzz +vocabularyManager_exception_SchemaValidationMainFieldIsNotRequired=zzz +vocabularyManager_exception_SchemaValidationMissingMainField=zzz +vocabularyManager_exception_SchemaValidationNoDefinitions=zzz +vocabularyManager_exception_SchemaValidationTitleFieldsAreNotRequired=zzz +vocabularyManager_exception_SchemaValidationTooManyMainFields=zzz +vocabularyManager_exception_VocabularyValidationMetadataSchemaIsHierarchical=zzz +vocabularyManager_exception_VocabularyValidationMetadataSchemaIsNotSetToSingleRootElement=zzz +vocabularyManager_exception_VocabularyValidationMetadataSchemaIssues=zzz vocabularyManager_fieldDefinitions=Field definitions zzz vocabularyManager_label=Label zzz vocabularyManager_languageSelection=Language zzz diff --git a/src/main/resources/messages_iw.properties b/src/main/resources/messages_iw.properties index 905b070d52..46936beac8 100644 --- a/src/main/resources/messages_iw.properties +++ b/src/main/resources/messages_iw.properties @@ -460,6 +460,8 @@ couldNotCreateImageFolder=\u05EA\u05D9\u05E7\u05D9\u05D9\u05EA \u05EA\u05DE\u05D count=\u05E1\u05E4\u05D9\u05E8\u05D4 countImages=\u05DE\u05E1\u05E4\u05E8 \u05EA\u05DE\u05D5\u05E0\u05D5\u05EA countMetadata=\u05DE\u05E1\u05E4\u05E8 \u05DE\u05D8\u05D0-\u05D3\u05D0\u05D8\u05D0 +counterFormat=zzz +counterStartValue=zzz createDoc=\u05D9\u05D9\u05E6\u05E8 \u05E7\u05D5\u05D1\u05E5 Microsoft Word createExcel=\u05D9\u05D9\u05E6\u05E8 \u05E7\u05D5\u05D1\u05E5 Microsoft Excel createNewBatchFromSelectedProcesses=\u05E6\u05D5\u05E8 \u05DE\u05E7\u05D1\u05E5 \u05D7\u05D3\u05E9 \u05DE\u05EA\u05D5\u05DA \u05D4\u05EA\u05D4\u05DC\u05D9\u05DB\u05D9\u05DD \u05D4\u05E0\u05D1\u05D7\u05E8\u05D9\u05DD @@ -698,6 +700,7 @@ exportMetsParameter=\u05D9\u05D9\u05E6\u05D0 \u05DE\u05E9\u05EA\u05E0\u05D9 METS exportPdf=\u05E9\u05DE\u05D5\u05E8 \u05E7\u05D5\u05D1\u05E5 PDF \u05D1\u05EA\u05D9\u05E7\u05D9\u05D9\u05EA \u05D4\u05D1\u05D9\u05EA* (\u05DE\u05E7\u05D1\u05E5 \u05D4\u05DE\u05DB\u05D9\u05DC \u05E0\u05EA\u05D5\u05E0\u05D9\u05DD \u05D1\u05E0\u05D5\u05E9\u05D0) exportRus=\u05D9\u05D9\u05E6\u05D0 Rus exportValidation=Export validation zzz +export_verb=zzz failure=\u05DB\u05D9\u05E9\u05DC\u05D5\u05DF farbschema=\u05DE\u05D0\u05E8\u05D2 \u05E6\u05D1\u05E2\u05D9\u05DD fehler=\u05E9\u05D2\u05D9\u05D0\u05D4 @@ -1299,6 +1302,7 @@ intranda_administration_showconfigfiles=Show config files zzz intranda_administration_snippetCreator=Snippet Creator intranda_administration_vocabularies=zzz intranda_metadata_changeType=zzz +intranda_metadata_createStructureElements=zzz intranda_quartz_herisJob=zzz intranda_statistics_allStepsPerProject=\u05E9\u05DC\u05D1\u05D9 \u05DE\u05D4\u05DC\u05DA-\u05E2\u05D1\u05D5\u05D3\u05D4 \u05E4\u05E8 \u05E4\u05E8\u05D5\u05D9\u05D9\u05E7\u05D8 intranda_statistics_file_count=Determine number of files zzz @@ -1329,10 +1333,11 @@ intranda_workflow_crop=LayoutWizzard workflow plugin zzz intranda_workflow_excelimport=Yerusha Upload Plugin intranda_workflow_fileUploadProcessCreation=File upload for process creation zzz intranda_workflow_hu_importer=Import for the collection portal zzz +intranda_workflow_import_json=JSON Importer intranda_workflow_khm_importer=KHM Importer -intranda_workflow_liechtenstein_volksblatt_importer=Zeitungsimport Liechtensteiner Volksblatt zzz intranda_workflow_massupload=\u05D4\u05E6\u05D8\u05D1\u05E8\u05D5\u05EA \u05D4\u05E2\u05DC\u05D0\u05EA \u05E4\u05DC\u05D0\u05D2-\u05D0\u05D9\u05DF intranda_workflow_metadata-enrichment=Updating vocabulary links zzz +intranda_workflow_newspaper_pages_importer=Newspaper import for single pages zzz intranda_workflow_oepma_importer=\u00D6PMA Importer intranda_workflow_projectexport=Project export zzz invalidCharacter=\u05EA\u05D5 \u05DC\u05D0 \u05D7\u05D5\u05E7\u05D9 @@ -1407,6 +1412,9 @@ kw=w label__named_entity=zzz label__named_entity_type=zzz langLaufendeAufgaben=\u05D9\u05D5\u05DE\u05DF-\u05E8\u05D9\u05E6\u05D4 \u05E9\u05DC \u05DE\u05E9\u05D9\u05DE\u05D5\u05EA +lang_eng=zzz +lang_fre=zzz +lang_ger=zzz language=\u05E9\u05E4\u05D4 lastImage=\u05E9\u05DD \u05D4\u05EA\u05DE\u05D5\u05E0\u05D4 lastPage=\u05E2\u05DE\u05D5\u05D3 \u05D0\u05D7\u05E8\u05D5\u05DF @@ -1845,6 +1853,7 @@ mets_duplicateMetadataGroup=Duplicate this metadata group zzz mets_easyPagination=Reuse "Last Page" again as "First Page" zzz mets_editOcrForCurrentImage=Edit ocr results zzz mets_error_configuredVocabularyInvalid=Error during initialization of '{0}'\: The vocabulary '{1}' cannot be loaded.zzz +mets_error_configuredVocabularyListHierarchical=zzz mets_generation_error=zzz mets_geoname_account_inactive=\u05D4\u05D7\u05D9\u05E4\u05D5\u05E9 \u05D1\u05DE\u05D0\u05D2\u05E8 \u05D4\u05DE\u05D9\u05D3\u05E2 \u05E9\u05DC geonames \u05DC\u05D0 \u05D4\u05E6\u05DC\u05D9\u05D7 \u05DC\u05D4\u05EA\u05D1\u05E6\u05E2 \u05DE\u05E4\u05E0\u05D9 \u05E9\u05DC\u05D0 \u05D0\u05D5\u05D7\u05E1\u05DF \u05DE\u05D9\u05D3\u05E2 \u05EA\u05E7\u05D9\u05DF \u05E9\u05DC \u05D4\u05D7\u05E9\u05D1\u05D5\u05DFzzz mets_hideHiddenFields=\u05D4\u05E1\u05EA\u05E8 \u05E9\u05D3\u05D5\u05EA \u05DE\u05D5\u05E1\u05EA\u05E8\u05D9\u05DD @@ -2281,6 +2290,12 @@ plugin_admin_vocabulary_noVocabularyLoaded=Currently, there is no vocabulary loa plugin_admin_vocabulary_select=Selectable values zzz plugin_admin_vocabulary_type=Type zzz plugin_admin_vocabulary_validation=Validation expression zzz +plugin_administration_archive_AcquisitionAgent=zzz +plugin_administration_archive_AcquisitionMethod=zzz +plugin_administration_archive_AcquisitionNotes=zzz +plugin_administration_archive_ArchivistNote=zzz +plugin_administration_archive_Conventions=zzz +plugin_administration_archive_DescriptionDates=zzz plugin_administration_archive_Number=Archive Number zzz plugin_administration_archive_Shelfmark=Reference code(s) zzz plugin_administration_archive_accessrestrict=Conditions governing access zzz @@ -2288,6 +2303,8 @@ plugin_administration_archive_accruals=Accruals zzz plugin_administration_archive_accruals_head=zzz plugin_administration_archive_accruals_p=zzz plugin_administration_archive_acqinfo=Immediate source of acquisition or transfer zzz +plugin_administration_archive_addMultipleNodes=zzz +plugin_administration_archive_addNodes=zzz plugin_administration_archive_advancedSearch=zzz plugin_administration_archive_agencycode=Agency code zzz plugin_administration_archive_altformavail=Existence and location of copies zzz @@ -2306,8 +2323,12 @@ plugin_administration_archive_bibliography=Publication note zzz plugin_administration_archive_bioghist=Administrative | Biographical history zzz plugin_administration_archive_c=The database file cannot be loaded. zzz plugin_administration_archive_clear=zzz +plugin_administration_archive_confirmReplacement=zzz plugin_administration_archive_conventiondeclaration=Rules or Conventions zzz +plugin_administration_archive_counter=zzz plugin_administration_archive_createNewArchive=Create new record group zzz +plugin_administration_archive_createNodesModal=zzz +plugin_administration_archive_createNodesModalDesciption=zzz plugin_administration_archive_createProcesses=Create missing processes for all lowest level subnodes zzz plugin_administration_archive_creationHeading=New record group zzz plugin_administration_archive_creation_filename=Please enter a name for archive stock. zzz @@ -2320,17 +2341,25 @@ plugin_administration_archive_databaseFileMustBeCreated=A database file must fir plugin_administration_archive_databaseLocked=The file is currently being edited by another user. zzz plugin_administration_archive_databaseMustBeCreated=The database must first be created within the BaseX instance. zzz plugin_administration_archive_deleteNode=Delete node zzz +plugin_administration_archive_deleteSelectedArchive=zzz plugin_administration_archive_descriptionLevel=Level of description zzz plugin_administration_archive_didnote=Note zzz plugin_administration_archive_download=Download as EAD file zzz +plugin_administration_archive_download_l=zzz +plugin_administration_archive_download_s=zzz plugin_administration_archive_duplicateEadFile=zzz plugin_administration_archive_duplicateNode=zzz +plugin_administration_archive_eadExport=zzz +plugin_administration_archive_eadExportNotConfigured=zzz plugin_administration_archive_eadid=EAD ID zzz plugin_administration_archive_editorName=Editor zzz +plugin_administration_archive_exit=zzz plugin_administration_archive_extref=zzz plugin_administration_archive_extrefhref=zzz plugin_administration_archive_font=Font zzz +plugin_administration_archive_generated=zzz plugin_administration_archive_langmaterial=Language | Scripts of material zzz +plugin_administration_archive_linkNodeModal=zzz plugin_administration_archive_loadDatabase=Start editing zzz plugin_administration_archive_materialspec=Material specific data zzz plugin_administration_archive_missing_Data=Incomplete data, please select database and upload EAD file zzz @@ -2338,8 +2367,13 @@ plugin_administration_archive_moveHierarchyDown=Move down the hierarchy zzz plugin_administration_archive_moveHierarchyUp=Move up the hierarchy zzz plugin_administration_archive_moveNode=Move node to another location zzz plugin_administration_archive_moveNodeDown=Move down zzz +plugin_administration_archive_moveNodeHere=zzz +plugin_administration_archive_moveNodeText=zzz +plugin_administration_archive_moveNodeThis=zzz plugin_administration_archive_moveNodeUp=Move up zzz plugin_administration_archive_newNode=Insert new node zzz +plugin_administration_archive_noArchiveSelected=zzz +plugin_administration_archive_noArchivesAvailable=zzz plugin_administration_archive_noConnectionToDatabase=There is no connection to the BaseX database. Please check the installation and make sure that the BaseX database has been started. zzz plugin_administration_archive_noElementSelectedHeading=No element is currently selected. zzz plugin_administration_archive_noElementSelectedText=Please first select a node in the left-hand area that you would like to edit. zzz @@ -2351,6 +2385,7 @@ plugin_administration_archive_nodeType_image=Image zzz plugin_administration_archive_nodeType_other=Other document zzz plugin_administration_archive_nodeType_video=Video document zzz plugin_administration_archive_nodelink=zzz +plugin_administration_archive_numberOfNodes=zzz plugin_administration_archive_oddnote=Odd notes zzz plugin_administration_archive_originalsloc=Existence and location of originals zzz plugin_administration_archive_originalsloc_head=zzz @@ -2379,8 +2414,10 @@ plugin_administration_archive_scopecontent=Scope and content zzz plugin_administration_archive_selectionHeading=Selection of the record group zzz plugin_administration_archive_selectionText=Please first select the record group you would like to work with\: zzz plugin_administration_archive_separatedmaterial=Related units of description zzz +plugin_administration_archive_showAllFields=zzz plugin_administration_archive_show_details=Show details zzz plugin_administration_archive_suffix=zzz +plugin_administration_archive_text=zzz plugin_administration_archive_titleproper=zzz plugin_administration_archive_unitdate=Date(s) zzz plugin_administration_archive_unitdatestructured=Structured date of the unit zzz @@ -2551,6 +2588,7 @@ plugin_administration_licences_name=zzz plugin_administration_licences_ordernumber=Order number zzz plugin_administration_licences_type=Type zzz plugin_administration_licences_usage=Usage zzz +plugin_administration_linkNodeModalDesciption=zzz plugin_administration_missingPermission=To view this page, you need the following permission\: zzz plugin_administration_nli_daily_press_cancelMessageMultipleImport=\u05D4\u05D9\u05D9\u05D1\u05D5\u05D0 \u05E9\u05DC \u05DE\u05E1\u05E4\u05E8 \u05E8\u05D9\u05E9\u05D5\u05DE\u05D9\u05DD \u05D1\u05D5\u05D8\u05DC plugin_administration_nli_daily_press_cancelMessageSingleImport=\u05D4\u05D9\u05D9\u05D1\u05D5\u05D0 \u05E9\u05DC \u05E8\u05D9\u05E9\u05D5\u05DD \u05D1\u05D5\u05D3\u05D3 \u05D1\u05D5\u05D8\u05DC. @@ -2873,6 +2911,10 @@ plugin_massupload_use_home_directory=\u05D8\u05E2\u05DF \u05EA\u05DE\u05D5\u05E0 plugin_metadata_changeTemplate_changeTemplate=zzz plugin_metadata_changeTemplate_description=zzz plugin_metadata_changeTemplate_selectTemplate=zzz +plugin_metadata_createElements_generateElements=zzz +plugin_metadata_createElements_generateTitle=zzz +plugin_metadata_createElements_numberOfImages=zzz +plugin_metadata_createElements_selectType=zzz plugin_newspaperRecognizer_applyEveryIssue=Apply every issue zzz plugin_newspaperRecognizer_applyEverySecondIssue=Apply every second issue zzz plugin_newspaperRecognizer_applyEveryThirdIssue=Apply every third issue zzz @@ -3223,6 +3265,7 @@ prozesse=\u05EA\u05D4\u05DC\u05D9\u05DB\u05D9\u05DD prozesse.ProzesseID=ID \u05E9\u05DC \u05D4\u05EA\u05D4\u05DC\u05D9\u05DA prozesse.Titel=\u05DB\u05D5\u05EA\u05E8\u05EA \u05D4\u05EA\u05D4\u05DC\u05D9\u05DA prozesse.erstellungsdatum=\u05D9\u05E6\u05D9\u05E8\u05EA \u05EA\u05D0\u05E8\u05D9\u05DA +prozesse.sortHelperDocstructs=zzz prozesse.sortHelperImages=\u05DE\u05E1\u05E4\u05E8 \u05D4\u05EA\u05DE\u05D5\u05E0\u05D5\u05EA prozesse.sortHelperMetadata=\u05DE\u05E1\u05E4\u05E8 \u05D4\u05DE\u05D8\u05D0-\u05D3\u05D0\u05D8\u05D0 prozesseBearbeiten=\u05E2\u05E8\u05D5\u05DA \u05EA\u05D4\u05DC\u05D9\u05DB\u05D9\u05DD @@ -3616,10 +3659,17 @@ vocabularyManager_addNewVocabulary=Add new vocabulary zzz vocabularyManager_addRecord=\u05D4\u05D5\u05E1\u05E3 \u05E8\u05E9\u05D5\u05DE\u05D4 \u05D7\u05D3\u05E9\u05D4 vocabularyManager_backToVocabularies=Back to the list of vocabularies zzz vocabularyManager_definition=Field definitions zzz +vocabularyManager_deleteChildRecordsPrompt=zzz vocabularyManager_deleteDefinition=Delete this definition zzz vocabularyManager_deleteRecord=\u05DE\u05D7\u05E7 \u05E8\u05E9\u05D5\u05DE\u05D4 vocabularyManager_description=\u05EA\u05D9\u05D0\u05D5\u05E8 vocabularyManager_downloadRecords=Download records zzz +vocabularyManager_downloadRecordsAsCsv=zzz +vocabularyManager_downloadRecordsAsExcel=zzz +vocabularyManager_downloadRecordsAsJson=zzz +vocabularyManager_downloadRecordsAsRdfTurtle=zzz +vocabularyManager_downloadRecordsAsRdfXml=zzz +vocabularyManager_editRecord=zzz vocabularyManager_editRecords=Edit records zzz vocabularyManager_editVocabulary=Manage vocabulary zzz vocabularyManager_excelImport_addNew=Add all records zzz @@ -3631,6 +3681,54 @@ vocabularyManager_excelImport_info=Existing records are updated and new records vocabularyManager_excelImport_mergeExisting=Merge existing records zzz vocabularyManager_excelImport_removeExisting=Delete all existing records zzz vocabularyManager_excelImport_vocabularyField=Vocabulary field zzz +vocabularyManager_exception_DataIntegrityViolation=zzz +vocabularyManager_exception_DeletionOfReferencedVocabulary=zzz +vocabularyManager_exception_DeletionOfReferencedVocabularyRecord=zzz +vocabularyManager_exception_EntityNotFound=zzz +vocabularyManager_exception_FieldDefinitionFallbackNotRequired=zzz +vocabularyManager_exception_FieldDefinitionNeitherReferenceVocabularyNorTypeNotPossible=zzz +vocabularyManager_exception_FieldDefinitionNonUniqueFallbackLanguageSpecified=zzz +vocabularyManager_exception_FieldDefinitionReferenceVocabularyAndTypeNotPossible=zzz +vocabularyManager_exception_FieldInstanceBelongsToWrongSchema=zzz +vocabularyManager_exception_FieldInstanceIsEmpty=zzz +vocabularyManager_exception_FieldInstanceIssues=zzz +vocabularyManager_exception_FieldInstanceMultipleValuesNotAllowed=zzz +vocabularyManager_exception_FieldInstanceValueIssues=zzz +vocabularyManager_exception_FieldTypeInvalidRegexSyntax=zzz +vocabularyManager_exception_FieldTypeSelectableValuesDoNotMatchSpecifiedValidationRegex=zzz +vocabularyManager_exception_FieldValueContainsNonTranslatedValue=zzz +vocabularyManager_exception_FieldValueHasNonAllowedTranslations=zzz +vocabularyManager_exception_FieldValueIsBlank=zzz +vocabularyManager_exception_FieldValueIsNotUnique=zzz +vocabularyManager_exception_FieldValueMissingRequiredTranslations=zzz +vocabularyManager_exception_FieldValueReferencedRecordBelongsToWrongVocabulary=zzz +vocabularyManager_exception_FieldValueReferencedRecordIssues=zzz +vocabularyManager_exception_FieldValueUnspecifiedTranslations=zzz +vocabularyManager_exception_FieldValuesAreNonSelectableValues=zzz +vocabularyManager_exception_FieldValuesDoNotMatchSpecifiedValidationRegex=zzz +vocabularyManager_exception_GenericValidation=zzz +vocabularyManager_exception_IllegalAttributeProvided=zzz +vocabularyManager_exception_InsertingNonExistingItem=zzz +vocabularyManager_exception_Mapping=zzz +vocabularyManager_exception_MissingRequiredAttribute=zzz +vocabularyManager_exception_RecordImport=zzz +vocabularyManager_exception_RecordImportUnsupportedExcelCellType=zzz +vocabularyManager_exception_RecordValidation=zzz +vocabularyManager_exception_RecordValidationChildrenReferencesNotAllowed=zzz +vocabularyManager_exception_RecordValidationHierarchyIssues=zzz +vocabularyManager_exception_RecordValidationMissingRequiredFields=zzz +vocabularyManager_exception_RecordValidationParentReferenceNotAllowed=zzz +vocabularyManager_exception_RecordValidationSingleRootElementVocabularyAlreadyContainsRecord=zzz +vocabularyManager_exception_RecordValidationUndefinedFieldsGiven=zzz +vocabularyManager_exception_SchemaValidationDefinitionIssues=zzz +vocabularyManager_exception_SchemaValidationMainFieldIsNotRequired=zzz +vocabularyManager_exception_SchemaValidationMissingMainField=zzz +vocabularyManager_exception_SchemaValidationNoDefinitions=zzz +vocabularyManager_exception_SchemaValidationTitleFieldsAreNotRequired=zzz +vocabularyManager_exception_SchemaValidationTooManyMainFields=zzz +vocabularyManager_exception_VocabularyValidationMetadataSchemaIsHierarchical=zzz +vocabularyManager_exception_VocabularyValidationMetadataSchemaIsNotSetToSingleRootElement=zzz +vocabularyManager_exception_VocabularyValidationMetadataSchemaIssues=zzz vocabularyManager_fieldDefinitions=Field definitions zzz vocabularyManager_label=\u05EA\u05D5\u05D5\u05D9\u05EA vocabularyManager_languageSelection=Language zzz diff --git a/src/main/resources/messages_nl.properties b/src/main/resources/messages_nl.properties index 81a4261d71..2bc77bf2aa 100644 --- a/src/main/resources/messages_nl.properties +++ b/src/main/resources/messages_nl.properties @@ -460,6 +460,8 @@ couldNotCreateImageFolder=De map voor de afbeeldingen kon niet worden aangemaakt count=Hoeveelheid zzz countImages=Aantal beelden zzz countMetadata=Aantal metagegevens zzz +counterFormat=zzz +counterStartValue=zzz createDoc=Maak een bestand aan in Microsoft Word-formaat zzz createExcel=Maak een bestand aan in Microsoft Excel-formaat zzz createNewBatchFromSelectedProcesses=Maak een nieuwe batch aan van de geselecteerde bewerkingen zzz @@ -698,6 +700,7 @@ exportMetsParameter=Exporteer METS Parameters zzz exportPdf=PDF-bestand opslaan in de gebruikersmap zzz exportRus=Rus exporteren zzz exportValidation=Export validation zzz +export_verb=zzz failure=Fout zzz farbschema=Kleurenschema zzz fehler=Fout zzz @@ -1330,10 +1333,11 @@ intranda_workflow_crop=LayoutWizzard workflow plugin zzz intranda_workflow_excelimport=Yerusha Upload Plugin zzz intranda_workflow_fileUploadProcessCreation=Bestand uploaden voor operatie generatie zzz intranda_workflow_hu_importer=Invoer voor het inzamelportaal zzz +intranda_workflow_import_json=JSON-importeur zzz intranda_workflow_khm_importer=KHM Importer -intranda_workflow_liechtenstein_volksblatt_importer=Zeitungsimport Liechtensteiner Volksblatt zzz intranda_workflow_massupload=Massa upload plugin zzz intranda_workflow_metadata-enrichment=Bijwerken van vocabulaire links zzz +intranda_workflow_newspaper_pages_importer=Kranten importeren voor afzonderlijke pagina's zzz intranda_workflow_oepma_importer=\u00D6PMA Importer intranda_workflow_projectexport=Project export zzz invalidCharacter=De naam bevat ongeldige tekens zzz @@ -1408,6 +1412,9 @@ kw=KW zzz label__named_entity=Named entity zzz label__named_entity_type=Named entity type zzz langLaufendeAufgaben=Lange termijn taken zzz +lang_eng=zzz +lang_fre=zzz +lang_ger=zzz language=Taal zzz lastImage=Laatste foto zzz lastPage=Laatste pagina zzz @@ -1846,6 +1853,7 @@ mets_duplicateMetadataGroup=Duplicate this metadata group zzz mets_easyPagination=Reuse "Last Page" again as "First Page" zzz mets_editOcrForCurrentImage=Edit ocr results zzz mets_error_configuredVocabularyInvalid=Error during initialization of '{0}'\: The vocabulary '{1}' cannot be loaded.zzz +mets_error_configuredVocabularyListHierarchical=zzz mets_generation_error=zzz mets_geoname_account_inactive=Het zoeken in de GeoNames database kon niet worden uitgevoerd omdat er geen geldige accountinformatie was opgeslagen. zzz mets_hideHiddenFields=Verberg verborgen velden voor zzz @@ -2282,6 +2290,12 @@ plugin_admin_vocabulary_noVocabularyLoaded=Er is geen vocabulaire geladen. Selec plugin_admin_vocabulary_select=Selecteerbare waarden zzz plugin_admin_vocabulary_type=Type zzz plugin_admin_vocabulary_validation=Validatieafdruk zzz +plugin_administration_archive_AcquisitionAgent=zzz +plugin_administration_archive_AcquisitionMethod=zzz +plugin_administration_archive_AcquisitionNotes=zzz +plugin_administration_archive_ArchivistNote=zzz +plugin_administration_archive_Conventions=zzz +plugin_administration_archive_DescriptionDates=zzz plugin_administration_archive_Number=Archiefnummer zzz plugin_administration_archive_Shelfmark=Handtekening(en) zzz plugin_administration_archive_accessrestrict=Toegangsvoorschriften zzz @@ -2289,6 +2303,8 @@ plugin_administration_archive_accruals=Nieuw binnengekomen zzz plugin_administration_archive_accruals_head=zzz plugin_administration_archive_accruals_p=zzz plugin_administration_archive_acqinfo=Bureau van afgifte zzz +plugin_administration_archive_addMultipleNodes=zzz +plugin_administration_archive_addNodes=zzz plugin_administration_archive_advancedSearch=zzz plugin_administration_archive_agencycode=Code van het agentschap zzz plugin_administration_archive_altformavail=Kopie\u00EBn of reproducties zzz @@ -2307,8 +2323,12 @@ plugin_administration_archive_bibliography=Publicaties zzz plugin_administration_archive_bioghist=Administrative | Biographical history zzz plugin_administration_archive_c=Het databasebestand kan niet worden geladen. zzz plugin_administration_archive_clear=zzz +plugin_administration_archive_confirmReplacement=zzz plugin_administration_archive_conventiondeclaration=Vervormingsprincipes zzz +plugin_administration_archive_counter=zzz plugin_administration_archive_createNewArchive=Cre\u00EBren van nieuwe archiefbestanden zzz +plugin_administration_archive_createNodesModal=zzz +plugin_administration_archive_createNodesModalDesciption=zzz plugin_administration_archive_createProcesses=Cre\u00EBer ontbrekende operaties voor alle subknooppunten zzz plugin_administration_archive_creationHeading=Nieuwe archiefbestanden zzz plugin_administration_archive_creation_filename=Geef een naam op voor de archiefstukken. zzz @@ -2321,17 +2341,25 @@ plugin_administration_archive_databaseFileMustBeCreated=Er moet eerst een databa plugin_administration_archive_databaseLocked=Dit bestand wordt momenteel bewerkt door een andere gebruiker. zzz plugin_administration_archive_databaseMustBeCreated=De database moet eerst worden aangemaakt binnen de BaseX instantie. zzz plugin_administration_archive_deleteNode=Knooppunt verwijderen zzz +plugin_administration_archive_deleteSelectedArchive=zzz plugin_administration_archive_descriptionLevel=Vervormingsniveau zzz plugin_administration_archive_didnote=Algemene opmerkingen zzz plugin_administration_archive_download=Downloaden als EAD-bestand zzz +plugin_administration_archive_download_l=zzz +plugin_administration_archive_download_s=zzz plugin_administration_archive_duplicateEadFile=zzz plugin_administration_archive_duplicateNode=zzz +plugin_administration_archive_eadExport=zzz +plugin_administration_archive_eadExportNotConfigured=zzz plugin_administration_archive_eadid=EAD ID zzz plugin_administration_archive_editorName=Redacteur zzz +plugin_administration_archive_exit=zzz plugin_administration_archive_extref=zzz plugin_administration_archive_extrefhref=zzz plugin_administration_archive_font=Lettertype zzz +plugin_administration_archive_generated=zzz plugin_administration_archive_langmaterial=Language | Scripts of material zzz +plugin_administration_archive_linkNodeModal=zzz plugin_administration_archive_loadDatabase=Begin met bewerken zzz plugin_administration_archive_materialspec=Materiaalspecifieke gegevens zzz plugin_administration_archive_missing_Data=Incomplete data, please select database and upload EAD file zzz @@ -2339,8 +2367,13 @@ plugin_administration_archive_moveHierarchyDown=Naar beneden in de hi\u00EBrarch plugin_administration_archive_moveHierarchyUp=Ga hoger in de hi\u00EBrarchie zzz plugin_administration_archive_moveNode=Verplaats knooppunt naar een andere plaats zzz plugin_administration_archive_moveNodeDown=Naar beneden. zzz +plugin_administration_archive_moveNodeHere=zzz +plugin_administration_archive_moveNodeText=zzz +plugin_administration_archive_moveNodeThis=zzz plugin_administration_archive_moveNodeUp=Naar boven zzz plugin_administration_archive_newNode=Nieuw knooppunt invoegen zzz +plugin_administration_archive_noArchiveSelected=zzz +plugin_administration_archive_noArchivesAvailable=zzz plugin_administration_archive_noConnectionToDatabase=Er is geen verbinding met de BaseX database. Controleer de installatie en zorg ervoor dat de BaseX database is opgestart. zzz plugin_administration_archive_noElementSelectedHeading=Er is momenteel geen element geselecteerd. zzz plugin_administration_archive_noElementSelectedText=Selecteer eerst een knooppunt in het linkergedeelte dat u wilt bewerken. zzz @@ -2352,6 +2385,7 @@ plugin_administration_archive_nodeType_image=Afbeelding zzz plugin_administration_archive_nodeType_other=Ander document zzz plugin_administration_archive_nodeType_video=Videodocument zzz plugin_administration_archive_nodelink=zzz +plugin_administration_archive_numberOfNodes=zzz plugin_administration_archive_oddnote=Verdere opmerkingen zzz plugin_administration_archive_originalsloc=Bewaarplaats van de originelen zzz plugin_administration_archive_originalsloc_head=zzz @@ -2380,8 +2414,10 @@ plugin_administration_archive_scopecontent=Vorm en inhoud zzz plugin_administration_archive_selectionHeading=Selectie van de archiefstukken zzz plugin_administration_archive_selectionText=Selecteer eerst de archiefstukken waarmee u wilt werken\: zzz plugin_administration_archive_separatedmaterial=Verwante vervormingseenheden zzz +plugin_administration_archive_showAllFields=zzz plugin_administration_archive_show_details=Toon details zzz plugin_administration_archive_suffix=zzz +plugin_administration_archive_text=zzz plugin_administration_archive_titleproper=zzz plugin_administration_archive_unitdate=Periode van oorsprong zzz plugin_administration_archive_unitdatestructured=Gestructureerde datum van de eenheid zzz @@ -2552,6 +2588,7 @@ plugin_administration_licences_name=Naam zzz plugin_administration_licences_ordernumber=Bestelnummer zzz plugin_administration_licences_type=Type zzz plugin_administration_licences_usage=Verbruik zzz +plugin_administration_linkNodeModalDesciption=zzz plugin_administration_missingPermission=Om deze pagina te kunnen bekijken, heeft u de volgende toestemming nodig\: zzz plugin_administration_nli_daily_press_cancelMessageMultipleImport=De import van meerdere records werd geannuleerd. zzz plugin_administration_nli_daily_press_cancelMessageSingleImport=De import van \u00E9\u00E9n enkel record werd afgebroken. zzz @@ -3228,6 +3265,7 @@ prozesse=Evenementen zzz prozesse.ProzesseID=Transactie-ID zzz prozesse.Titel=Transactietitel zzz prozesse.erstellungsdatum=Aanmaakdatum zzz +prozesse.sortHelperDocstructs=zzz prozesse.sortHelperImages=Aantal beelden zzz prozesse.sortHelperMetadata=Aantal metagegevens zzz prozesseBearbeiten=Processen bewerken zzz @@ -3621,10 +3659,17 @@ vocabularyManager_addNewVocabulary=Add new vocabulary zzz vocabularyManager_addRecord=Add new record zzz vocabularyManager_backToVocabularies=Back to the list of vocabularies zzz vocabularyManager_definition=Field definitions zzz +vocabularyManager_deleteChildRecordsPrompt=zzz vocabularyManager_deleteDefinition=Delete this definition zzz vocabularyManager_deleteRecord=Delete record zzz vocabularyManager_description=Description zzz vocabularyManager_downloadRecords=Download records zzz +vocabularyManager_downloadRecordsAsCsv=zzz +vocabularyManager_downloadRecordsAsExcel=zzz +vocabularyManager_downloadRecordsAsJson=zzz +vocabularyManager_downloadRecordsAsRdfTurtle=zzz +vocabularyManager_downloadRecordsAsRdfXml=zzz +vocabularyManager_editRecord=zzz vocabularyManager_editRecords=Edit records zzz vocabularyManager_editVocabulary=Manage vocabulary zzz vocabularyManager_excelImport_addNew=Add all records zzz @@ -3636,6 +3681,54 @@ vocabularyManager_excelImport_info=Existing records are updated and new records vocabularyManager_excelImport_mergeExisting=Merge existing records zzz vocabularyManager_excelImport_removeExisting=Delete all existing records zzz vocabularyManager_excelImport_vocabularyField=Vocabulary field zzz +vocabularyManager_exception_DataIntegrityViolation=zzz +vocabularyManager_exception_DeletionOfReferencedVocabulary=zzz +vocabularyManager_exception_DeletionOfReferencedVocabularyRecord=zzz +vocabularyManager_exception_EntityNotFound=zzz +vocabularyManager_exception_FieldDefinitionFallbackNotRequired=zzz +vocabularyManager_exception_FieldDefinitionNeitherReferenceVocabularyNorTypeNotPossible=zzz +vocabularyManager_exception_FieldDefinitionNonUniqueFallbackLanguageSpecified=zzz +vocabularyManager_exception_FieldDefinitionReferenceVocabularyAndTypeNotPossible=zzz +vocabularyManager_exception_FieldInstanceBelongsToWrongSchema=zzz +vocabularyManager_exception_FieldInstanceIsEmpty=zzz +vocabularyManager_exception_FieldInstanceIssues=zzz +vocabularyManager_exception_FieldInstanceMultipleValuesNotAllowed=zzz +vocabularyManager_exception_FieldInstanceValueIssues=zzz +vocabularyManager_exception_FieldTypeInvalidRegexSyntax=zzz +vocabularyManager_exception_FieldTypeSelectableValuesDoNotMatchSpecifiedValidationRegex=zzz +vocabularyManager_exception_FieldValueContainsNonTranslatedValue=zzz +vocabularyManager_exception_FieldValueHasNonAllowedTranslations=zzz +vocabularyManager_exception_FieldValueIsBlank=zzz +vocabularyManager_exception_FieldValueIsNotUnique=zzz +vocabularyManager_exception_FieldValueMissingRequiredTranslations=zzz +vocabularyManager_exception_FieldValueReferencedRecordBelongsToWrongVocabulary=zzz +vocabularyManager_exception_FieldValueReferencedRecordIssues=zzz +vocabularyManager_exception_FieldValueUnspecifiedTranslations=zzz +vocabularyManager_exception_FieldValuesAreNonSelectableValues=zzz +vocabularyManager_exception_FieldValuesDoNotMatchSpecifiedValidationRegex=zzz +vocabularyManager_exception_GenericValidation=zzz +vocabularyManager_exception_IllegalAttributeProvided=zzz +vocabularyManager_exception_InsertingNonExistingItem=zzz +vocabularyManager_exception_Mapping=zzz +vocabularyManager_exception_MissingRequiredAttribute=zzz +vocabularyManager_exception_RecordImport=zzz +vocabularyManager_exception_RecordImportUnsupportedExcelCellType=zzz +vocabularyManager_exception_RecordValidation=zzz +vocabularyManager_exception_RecordValidationChildrenReferencesNotAllowed=zzz +vocabularyManager_exception_RecordValidationHierarchyIssues=zzz +vocabularyManager_exception_RecordValidationMissingRequiredFields=zzz +vocabularyManager_exception_RecordValidationParentReferenceNotAllowed=zzz +vocabularyManager_exception_RecordValidationSingleRootElementVocabularyAlreadyContainsRecord=zzz +vocabularyManager_exception_RecordValidationUndefinedFieldsGiven=zzz +vocabularyManager_exception_SchemaValidationDefinitionIssues=zzz +vocabularyManager_exception_SchemaValidationMainFieldIsNotRequired=zzz +vocabularyManager_exception_SchemaValidationMissingMainField=zzz +vocabularyManager_exception_SchemaValidationNoDefinitions=zzz +vocabularyManager_exception_SchemaValidationTitleFieldsAreNotRequired=zzz +vocabularyManager_exception_SchemaValidationTooManyMainFields=zzz +vocabularyManager_exception_VocabularyValidationMetadataSchemaIsHierarchical=zzz +vocabularyManager_exception_VocabularyValidationMetadataSchemaIsNotSetToSingleRootElement=zzz +vocabularyManager_exception_VocabularyValidationMetadataSchemaIssues=zzz vocabularyManager_fieldDefinitions=Field definitions zzz vocabularyManager_label=Label zzz vocabularyManager_languageSelection=Language zzz diff --git a/src/main/resources/messages_pt.properties b/src/main/resources/messages_pt.properties index 2280817d56..2b2ead09a4 100644 --- a/src/main/resources/messages_pt.properties +++ b/src/main/resources/messages_pt.properties @@ -460,6 +460,8 @@ couldNotCreateImageFolder=O diret\u00F3rio para as imagens n\u00E3o p\u00F4de se count=Quantidade zzz countImages=N\u00FAmero de imagens zzz countMetadata=N\u00FAmero de metadados zzz +counterFormat=zzz +counterStartValue=zzz createDoc=Criar arquivo no formato Microsoft Word zzz createExcel=Criar um arquivo no formato Microsoft Excel zzz createNewBatchFromSelectedProcesses=Criar um novo lote a partir das opera\u00E7\u00F5es selecionadas zzz @@ -698,6 +700,7 @@ exportMetsParameter=Par\u00E2metros METS de Exporta\u00E7\u00E3o zzz exportPdf=Salvar arquivo PDF no diret\u00F3rio do usu\u00E1rio zzz exportRus=Export Rus zzz exportValidation=Export validation zzz +export_verb=zzz failure=Erro zzz farbschema=Esquema de cores zzz fehler=Erro zzz @@ -1330,10 +1333,11 @@ intranda_workflow_crop=LayoutWizzard workflow plugin zzz intranda_workflow_excelimport=Yerusha Upload Plugin zzz intranda_workflow_fileUploadProcessCreation=Carregamento de ficheiros para gera\u00E7\u00E3o de opera\u00E7\u00F5es zzz intranda_workflow_hu_importer=Importa\u00E7\u00E3o para o portal de recolha zzz +intranda_workflow_import_json=Importador JSON zzz intranda_workflow_khm_importer=KHM Importer -intranda_workflow_liechtenstein_volksblatt_importer=Zeitungsimport Liechtensteiner Volksblatt zzz intranda_workflow_massupload=Plugin de carregamento em massa zzz intranda_workflow_metadata-enrichment=Actualizar as liga\u00E7\u00F5es dos voc\u00E1bulos zzz +intranda_workflow_newspaper_pages_importer=Importa\u00E7\u00E3o de jornais para p\u00E1ginas individuais zzz intranda_workflow_oepma_importer=\u00D6PMA Importer intranda_workflow_projectexport=Project export zzz invalidCharacter=O nome cont\u00E9m caracteres inv\u00E1lidos zzz @@ -1408,6 +1412,9 @@ kw=KW zzz label__named_entity=Named entity zzz label__named_entity_type=Named entity type zzz langLaufendeAufgaben=Tarefas a longo prazo zzz +lang_eng=zzz +lang_fre=zzz +lang_ger=zzz language=Idioma zzz lastImage=\u00DAltima foto zzz lastPage=\u00DAltima p\u00E1gina zzz @@ -1846,6 +1853,7 @@ mets_duplicateMetadataGroup=Duplicate this metadata group zzz mets_easyPagination=Reuse "Last Page" again as "First Page" zzz mets_editOcrForCurrentImage=Edit ocr results zzz mets_error_configuredVocabularyInvalid=Error during initialization of '{0}'\: The vocabulary '{1}' cannot be loaded.zzz +mets_error_configuredVocabularyListHierarchical=zzz mets_generation_error=zzz mets_geoname_account_inactive=A pesquisa na base de dados GeoNames n\u00E3o p\u00F4de ser realizada porque n\u00E3o foi armazenada informa\u00E7\u00E3o v\u00E1lida da conta. zzz mets_hideHiddenFields=Ocultar campos escondidos de zzz @@ -2282,6 +2290,12 @@ plugin_admin_vocabulary_noVocabularyLoaded=Nenhum vocabul\u00E1rio est\u00E1 car plugin_admin_vocabulary_select=Valores selecion\u00E1veis zzz plugin_admin_vocabulary_type=Tipo zzz plugin_admin_vocabulary_validation=Impress\u00E3o de valida\u00E7\u00E3o zzz +plugin_administration_archive_AcquisitionAgent=zzz +plugin_administration_archive_AcquisitionMethod=zzz +plugin_administration_archive_AcquisitionNotes=zzz +plugin_administration_archive_ArchivistNote=zzz +plugin_administration_archive_Conventions=zzz +plugin_administration_archive_DescriptionDates=zzz plugin_administration_archive_Number=N\u00FAmero de arquivo zzz plugin_administration_archive_Shelfmark=Assinatura(\u00F5es) zzz plugin_administration_archive_accessrestrict=Regulamentos de acesso zzz @@ -2289,6 +2303,8 @@ plugin_administration_archive_accruals=Rec\u00E9m-chegados zzz plugin_administration_archive_accruals_head=zzz plugin_administration_archive_accruals_p=zzz plugin_administration_archive_acqinfo=Gabinete de emiss\u00E3o zzz +plugin_administration_archive_addMultipleNodes=zzz +plugin_administration_archive_addNodes=zzz plugin_administration_archive_advancedSearch=zzz plugin_administration_archive_agencycode=C\u00F3digo da ag\u00EAncia zzz plugin_administration_archive_altformavail=C\u00F3pias ou reprodu\u00E7\u00F5es zzz @@ -2307,8 +2323,12 @@ plugin_administration_archive_bibliography=Publica\u00E7\u00F5es zzz plugin_administration_archive_bioghist=Administrative | Biographical history zzz plugin_administration_archive_c=O ficheiro da base de dados n\u00E3o pode ser carregado. zzz plugin_administration_archive_clear=zzz +plugin_administration_archive_confirmReplacement=zzz plugin_administration_archive_conventiondeclaration=Princ\u00EDpios de distor\u00E7\u00E3o zzz +plugin_administration_archive_counter=zzz plugin_administration_archive_createNewArchive=Criar novas explora\u00E7\u00F5es de arquivo zzz +plugin_administration_archive_createNodesModal=zzz +plugin_administration_archive_createNodesModalDesciption=zzz plugin_administration_archive_createProcesses=Criar opera\u00E7\u00F5es em falta para todos os sub-n\u00F3s zzz plugin_administration_archive_creationHeading=Novas explora\u00E7\u00F5es de arquivo zzz plugin_administration_archive_creation_filename=Por favor, introduza um nome para as explora\u00E7\u00F5es de arquivo. zzz @@ -2321,17 +2341,25 @@ plugin_administration_archive_databaseFileMustBeCreated=Deve ser criado primeiro plugin_administration_archive_databaseLocked=Este ficheiro est\u00E1 actualmente a ser editado por outro utilizador. zzz plugin_administration_archive_databaseMustBeCreated=A base de dados deve primeiro ser criada no \u00E2mbito da inst\u00E2ncia BaseX. zzz plugin_administration_archive_deleteNode=Eliminar n\u00F3 zzz +plugin_administration_archive_deleteSelectedArchive=zzz plugin_administration_archive_descriptionLevel=N\u00EDvel de distor\u00E7\u00E3o zzz plugin_administration_archive_didnote=Observa\u00E7\u00F5es gerais zzz plugin_administration_archive_download=Descarregar como ficheiro EAD zzz +plugin_administration_archive_download_l=zzz +plugin_administration_archive_download_s=zzz plugin_administration_archive_duplicateEadFile=zzz plugin_administration_archive_duplicateNode=zzz +plugin_administration_archive_eadExport=zzz +plugin_administration_archive_eadExportNotConfigured=zzz plugin_administration_archive_eadid=EAD ID zzz plugin_administration_archive_editorName=Editor zzz +plugin_administration_archive_exit=zzz plugin_administration_archive_extref=zzz plugin_administration_archive_extrefhref=zzz plugin_administration_archive_font=Fonte zzz +plugin_administration_archive_generated=zzz plugin_administration_archive_langmaterial=Language | Scripts of material zzz +plugin_administration_archive_linkNodeModal=zzz plugin_administration_archive_loadDatabase=Comece a editar zzz plugin_administration_archive_materialspec=Dados espec\u00EDficos do material zzz plugin_administration_archive_missing_Data=Incomplete data, please select database and upload EAD file zzz @@ -2339,8 +2367,13 @@ plugin_administration_archive_moveHierarchyDown=Descer a hierarquia zzz plugin_administration_archive_moveHierarchyUp=Subir a hierarquia zzz plugin_administration_archive_moveNode=Mover o n\u00F3 para outro lugar zzz plugin_administration_archive_moveNodeDown=Descer zzz +plugin_administration_archive_moveNodeHere=zzz +plugin_administration_archive_moveNodeText=zzz +plugin_administration_archive_moveNodeThis=zzz plugin_administration_archive_moveNodeUp=Avan\u00E7ar para cima zzz plugin_administration_archive_newNode=Inserir novo n\u00F3 zzz +plugin_administration_archive_noArchiveSelected=zzz +plugin_administration_archive_noArchivesAvailable=zzz plugin_administration_archive_noConnectionToDatabase=N\u00E3o h\u00E1 liga\u00E7\u00E3o \u00E0 base de dados BaseX. Verifique a instala\u00E7\u00E3o e assegure-se de que a base de dados BaseX foi iniciada. zzz plugin_administration_archive_noElementSelectedHeading=Nenhum elemento \u00E9 actualmente seleccionado. zzz plugin_administration_archive_noElementSelectedText=Por favor, seleccione primeiro um n\u00F3 na \u00E1rea da esquerda que gostaria de editar. zzz @@ -2352,6 +2385,7 @@ plugin_administration_archive_nodeType_image=Imagem zzz plugin_administration_archive_nodeType_other=Outro documento zzz plugin_administration_archive_nodeType_video=Documento em v\u00EDdeo zzz plugin_administration_archive_nodelink=zzz +plugin_administration_archive_numberOfNodes=zzz plugin_administration_archive_oddnote=Outras observa\u00E7\u00F5es zzz plugin_administration_archive_originalsloc=Local de armazenamento dos originais zzz plugin_administration_archive_originalsloc_head=zzz @@ -2380,8 +2414,10 @@ plugin_administration_archive_scopecontent=Forma e conte\u00FAdo zzz plugin_administration_archive_selectionHeading=Selec\u00E7\u00E3o do acervo do arquivo zzz plugin_administration_archive_selectionText=Por favor, seleccione primeiro os arquivos com os quais gostaria de trabalhar\: zzz plugin_administration_archive_separatedmaterial=Unidades de distor\u00E7\u00E3o relacionadas zzz +plugin_administration_archive_showAllFields=zzz plugin_administration_archive_show_details=Mostrar detalhes zzz plugin_administration_archive_suffix=zzz +plugin_administration_archive_text=zzz plugin_administration_archive_titleproper=zzz plugin_administration_archive_unitdate=Per\u00EDodo de origem zzz plugin_administration_archive_unitdatestructured=Data estruturada da unidade zzz @@ -2552,6 +2588,7 @@ plugin_administration_licences_name=Nome zzz plugin_administration_licences_ordernumber=N\u00FAmero de encomenda zzz plugin_administration_licences_type=Tipo zzz plugin_administration_licences_usage=Consumo zzz +plugin_administration_linkNodeModalDesciption=zzz plugin_administration_missingPermission=Para visualizar esta p\u00E1gina, voc\u00EA precisa da seguinte autoriza\u00E7\u00E3o\: zzz plugin_administration_nli_daily_press_cancelMessageMultipleImport=A importa\u00E7\u00E3o de v\u00E1rios registos foi cancelada. zzz plugin_administration_nli_daily_press_cancelMessageSingleImport=A importa\u00E7\u00E3o de um \u00FAnico registo foi abortada. zzz @@ -3228,6 +3265,7 @@ prozesse=Eventos zzz prozesse.ProzesseID=Identifica\u00E7\u00E3o da transa\u00E7\u00E3o zzz prozesse.Titel=T\u00EDtulo da transa\u00E7\u00E3o zzz prozesse.erstellungsdatum=Data de cria\u00E7\u00E3o zzz +prozesse.sortHelperDocstructs=zzz prozesse.sortHelperImages=N\u00FAmero de imagens zzz prozesse.sortHelperMetadata=N\u00FAmero de metadados zzz prozesseBearbeiten=Editar processos zzz @@ -3621,10 +3659,17 @@ vocabularyManager_addNewVocabulary=Add new vocabulary zzz vocabularyManager_addRecord=Add new record zzz vocabularyManager_backToVocabularies=Back to the list of vocabularies zzz vocabularyManager_definition=Field definitions zzz +vocabularyManager_deleteChildRecordsPrompt=zzz vocabularyManager_deleteDefinition=Delete this definition zzz vocabularyManager_deleteRecord=Delete record zzz vocabularyManager_description=Description zzz vocabularyManager_downloadRecords=Download records zzz +vocabularyManager_downloadRecordsAsCsv=zzz +vocabularyManager_downloadRecordsAsExcel=zzz +vocabularyManager_downloadRecordsAsJson=zzz +vocabularyManager_downloadRecordsAsRdfTurtle=zzz +vocabularyManager_downloadRecordsAsRdfXml=zzz +vocabularyManager_editRecord=zzz vocabularyManager_editRecords=Edit records zzz vocabularyManager_editVocabulary=Manage vocabulary zzz vocabularyManager_excelImport_addNew=Add all records zzz @@ -3636,6 +3681,54 @@ vocabularyManager_excelImport_info=Existing records are updated and new records vocabularyManager_excelImport_mergeExisting=Merge existing records zzz vocabularyManager_excelImport_removeExisting=Delete all existing records zzz vocabularyManager_excelImport_vocabularyField=Vocabulary field zzz +vocabularyManager_exception_DataIntegrityViolation=zzz +vocabularyManager_exception_DeletionOfReferencedVocabulary=zzz +vocabularyManager_exception_DeletionOfReferencedVocabularyRecord=zzz +vocabularyManager_exception_EntityNotFound=zzz +vocabularyManager_exception_FieldDefinitionFallbackNotRequired=zzz +vocabularyManager_exception_FieldDefinitionNeitherReferenceVocabularyNorTypeNotPossible=zzz +vocabularyManager_exception_FieldDefinitionNonUniqueFallbackLanguageSpecified=zzz +vocabularyManager_exception_FieldDefinitionReferenceVocabularyAndTypeNotPossible=zzz +vocabularyManager_exception_FieldInstanceBelongsToWrongSchema=zzz +vocabularyManager_exception_FieldInstanceIsEmpty=zzz +vocabularyManager_exception_FieldInstanceIssues=zzz +vocabularyManager_exception_FieldInstanceMultipleValuesNotAllowed=zzz +vocabularyManager_exception_FieldInstanceValueIssues=zzz +vocabularyManager_exception_FieldTypeInvalidRegexSyntax=zzz +vocabularyManager_exception_FieldTypeSelectableValuesDoNotMatchSpecifiedValidationRegex=zzz +vocabularyManager_exception_FieldValueContainsNonTranslatedValue=zzz +vocabularyManager_exception_FieldValueHasNonAllowedTranslations=zzz +vocabularyManager_exception_FieldValueIsBlank=zzz +vocabularyManager_exception_FieldValueIsNotUnique=zzz +vocabularyManager_exception_FieldValueMissingRequiredTranslations=zzz +vocabularyManager_exception_FieldValueReferencedRecordBelongsToWrongVocabulary=zzz +vocabularyManager_exception_FieldValueReferencedRecordIssues=zzz +vocabularyManager_exception_FieldValueUnspecifiedTranslations=zzz +vocabularyManager_exception_FieldValuesAreNonSelectableValues=zzz +vocabularyManager_exception_FieldValuesDoNotMatchSpecifiedValidationRegex=zzz +vocabularyManager_exception_GenericValidation=zzz +vocabularyManager_exception_IllegalAttributeProvided=zzz +vocabularyManager_exception_InsertingNonExistingItem=zzz +vocabularyManager_exception_Mapping=zzz +vocabularyManager_exception_MissingRequiredAttribute=zzz +vocabularyManager_exception_RecordImport=zzz +vocabularyManager_exception_RecordImportUnsupportedExcelCellType=zzz +vocabularyManager_exception_RecordValidation=zzz +vocabularyManager_exception_RecordValidationChildrenReferencesNotAllowed=zzz +vocabularyManager_exception_RecordValidationHierarchyIssues=zzz +vocabularyManager_exception_RecordValidationMissingRequiredFields=zzz +vocabularyManager_exception_RecordValidationParentReferenceNotAllowed=zzz +vocabularyManager_exception_RecordValidationSingleRootElementVocabularyAlreadyContainsRecord=zzz +vocabularyManager_exception_RecordValidationUndefinedFieldsGiven=zzz +vocabularyManager_exception_SchemaValidationDefinitionIssues=zzz +vocabularyManager_exception_SchemaValidationMainFieldIsNotRequired=zzz +vocabularyManager_exception_SchemaValidationMissingMainField=zzz +vocabularyManager_exception_SchemaValidationNoDefinitions=zzz +vocabularyManager_exception_SchemaValidationTitleFieldsAreNotRequired=zzz +vocabularyManager_exception_SchemaValidationTooManyMainFields=zzz +vocabularyManager_exception_VocabularyValidationMetadataSchemaIsHierarchical=zzz +vocabularyManager_exception_VocabularyValidationMetadataSchemaIsNotSetToSingleRootElement=zzz +vocabularyManager_exception_VocabularyValidationMetadataSchemaIssues=zzz vocabularyManager_fieldDefinitions=Field definitions zzz vocabularyManager_label=Label zzz vocabularyManager_languageSelection=Language zzz diff --git a/src/main/resources/template.properties b/src/main/resources/template.properties index e62446a115..3f79c86017 100644 --- a/src/main/resources/template.properties +++ b/src/main/resources/template.properties @@ -412,9 +412,12 @@ MetsEditorLockingTime=1800000 # use external ocr for text in mets editor or use existing files #MetsEditorUseExternalOCR=false -# The number of backups can be set here. 0 means that no backups are created +# The number of metadata backups can be set here. 0 means that no backups are created numberOfMetaBackups=25 +# The number of generic backups can be set here. 0 means that no backups are created +numberOfBackups=10 + # ----------------------------------- ## mets editor / user interface # ----------------------------------- @@ -562,3 +565,9 @@ automaticExportWithOcr=true # Allow the PDF generation as downloadable file instead of storing it into the users home directory pdfAsDownload=true + +# ----------------------------------- +## vocabulary server +# ----------------------------------- +vocabularyServerHost=localhost +vocabularyServerPort=8081 diff --git a/src/main/webapp/README.md b/src/main/webapp/README.md index a26af153f5..76e04e96b3 100644 --- a/src/main/webapp/README.md +++ b/src/main/webapp/README.md @@ -6,7 +6,7 @@ Required: `npm` >= v5.7.1 1. Install dependencies: `npm i` -2. For *development* purposes: by default, the development script moves the compiled assets to the same location as the production script. If you wish to move files to another location depending on your Goobi setup, provide the desired location of the web app **relative to the gulpfile** in the variable `customLocation`. +2. For *development* purposes: by default, the development script moves the compiled assets to the same location as the production script. If you wish to move files to another location depending on your Goobi setup, refer to the development section below. 3. Depending on your build target, run one of the following scripts: - `npm run dev` for *development*, move compiled assets to Tomcat and watch for further changes. - `npm run build` for *production*, minify assets as needed without moving them to the server. Do this before merging a PR. @@ -15,6 +15,16 @@ Required: `npm` >= v5.7.1 A number of legacy assets can be found in `uii/template/`. Please avoid changes to these, but refer to the following sections. +### Tomcat Location + +Gulp expects the location of your Tomcat in a global configuration file. This file should be found at `~/.config/gulp_userconfig.json`. The location should be provided similar to this pattern: + +```JSON +{ + "tomcatLocation": "/PATH/TO/TOMCAT/webapps/workflow-core/" +} +``` + ### Javascript New JS modules should be included in `uii/templatePG/js/modules/`. Import new modules in `uii/templatesPG/js/main.js` so that Rollup can handle them. diff --git a/src/main/webapp/gulpfile.js b/src/main/webapp/gulpfile.js index e05c52b077..c4203fdb03 100644 --- a/src/main/webapp/gulpfile.js +++ b/src/main/webapp/gulpfile.js @@ -17,7 +17,7 @@ const cleanup = require('rollup-plugin-cleanup'); const terser = require('@rollup/plugin-terser'); // provide custom asset location for watch task -const customLocation = `/home/florian/eclipse-workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp1/wtpwebapps/workflow-core/`; +let customLocation; // source directories, files, globs const legacySources = { @@ -35,8 +35,7 @@ const sources = { 'node_modules/bootstrap/scss/', ], js: './uii/templatePG/js/**/*.js', - static: [ - 'resources/**/*.xhtml', + staticAssets: [ 'uii/**/*.xhtml', 'uii/**/*.html', 'uii/**/*.jpg', @@ -45,7 +44,9 @@ const sources = { 'uii/**/*.gif', 'uii/**/*.ico', 'uii/**/*.riot' - ] + ], + composites: 'resources/**/*.xhtml', + template: 'uii/templatePG/templatePG.html' } // target directories const legacyTargetFolder = { @@ -54,14 +55,28 @@ const legacyTargetFolder = { const targetFolder = { css: 'uii/templatePG/css/dist/', js: 'dist/js/', - static: 'uii/', + staticAssets: 'uii/', + composites: 'resources/' } // FUNCTIONS +// load custom location from user config +// this is a function so that CI does not fail if the file is not present +function loadConfig() { + const fs = require("fs"); + const homedir = require("os").homedir(); + const config = fs.readFileSync(homedir + '/.config/gulp_userconfig.json') + customLocation = JSON.parse(config).tomcatLocation; +}; + function static() { - console.log("copy " + sources.static + " to " + `${customLocation}${targetFolder.static}`); - return src(sources.static) - .pipe(dest(`${customLocation}${targetFolder.static}`)) + return src(sources.staticAssets) + .pipe(dest(`${customLocation}${targetFolder.staticAssets}`)) +}; + +function composites() { + return src(sources.composites) + .pipe(dest(`${customLocation}${targetFolder.composites}`)) }; // function for legacy less @@ -186,11 +201,13 @@ function prodJsRollup() { }; exports.dev = function() { + loadConfig(); watch(legacySources.less, { ignoreInitial: false }, devLess); watch(legacySources.js, { ignoreInitial: false }, devJsLegacy); watch(sources.js, { ignoreInitial: false }, devJsRollup); watch(sources.bsCss, { ignoreInitial: false }, devBSCss); watch(sources.cssGlob, { ignoreInitial: false }, devCss); - watch(sources.static, { ignoreInitial: false }, static); + watch(sources.staticAssets, { ignoreInitial: false }, static); + watch(sources.composites, { ignoreInitial: false }, composites); }; exports.prod = parallel(prodJsLegacy, prodJsRollup, prodBSCss, prodCss, prodLess); diff --git a/src/main/webapp/package-lock.json b/src/main/webapp/package-lock.json index 724e5eb28d..ef10038a28 100644 --- a/src/main/webapp/package-lock.json +++ b/src/main/webapp/package-lock.json @@ -21,13 +21,13 @@ "grunt-contrib-watch": "*", "grunt-riot": "*", "grunt-sync": "*", - "gulp": "^4.0.2", + "gulp": "^5.0.0", "gulp-clean-css": "^4.3.0", "gulp-concat": "^2.6.1", "gulp-less": "^5.0.0", "gulp-rename": "^2.0.0", "gulp-sass": "^5.1.0", - "gulp-sourcemaps": "^3.0.0", + "gulp-sourcemaps": "^2.6.5", "gulp-uglify-es": "^3.0.0", "less-plugin-autoprefix": "*", "postcss": "^8.4.12", @@ -39,42 +39,31 @@ } }, "node_modules/@gulp-sourcemaps/identity-map": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/identity-map/-/identity-map-2.0.1.tgz", - "integrity": "sha512-Tb+nSISZku+eQ4X1lAkevcQa+jknn/OVUgZ3XCxEKIsLsqYuPoJwJOPQeaOk75X3WPftb29GWY1eqE7GLsXb1Q==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/identity-map/-/identity-map-1.0.2.tgz", + "integrity": "sha512-ciiioYMLdo16ShmfHBXJBOFm3xPC4AuwO4xeRpFeHz7WK9PYsWCmigagG2XyzZpubK4a3qNKoUBDhbzHfa50LQ==", "dev": true, "dependencies": { - "acorn": "^6.4.1", - "normalize-path": "^3.0.0", - "postcss": "^7.0.16", + "acorn": "^5.0.3", + "css": "^2.2.1", + "normalize-path": "^2.1.1", "source-map": "^0.6.0", - "through2": "^3.0.1" + "through2": "^2.0.3" }, "engines": { "node": ">= 0.10" } }, - "node_modules/@gulp-sourcemaps/identity-map/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true - }, - "node_modules/@gulp-sourcemaps/identity-map/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "node_modules/@gulp-sourcemaps/identity-map/node_modules/normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", "dev": true, "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" + "remove-trailing-separator": "^1.0.1" }, "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "node": ">=0.10.0" } }, "node_modules/@gulp-sourcemaps/identity-map/node_modules/source-map": { @@ -86,6 +75,16 @@ "node": ">=0.10.0" } }, + "node_modules/@gulp-sourcemaps/identity-map/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, "node_modules/@gulp-sourcemaps/map-sources": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/map-sources/-/map-sources-1.0.0.tgz", @@ -121,6 +120,27 @@ "xtend": "~4.0.1" } }, + "node_modules/@gulpjs/messages": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@gulpjs/messages/-/messages-1.1.0.tgz", + "integrity": "sha512-Ys9sazDatyTgZVb4xPlDufLweJ/Os2uHWOv+Caxvy2O85JcnT4M3vc73bi8pdLWlv3fdWQz3pdI9tVwo8rQQSg==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@gulpjs/to-absolute-glob": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@gulpjs/to-absolute-glob/-/to-absolute-glob-4.0.0.tgz", + "integrity": "sha512-kjotm7XJrJ6v+7knhPaRgaT6q8F8K2jiafwYdNHLzmV0uGLuZY43FK6smNSHUPrhq5kX2slCUy+RGG/xGqmIKA==", + "dev": true, + "dependencies": { + "is-negated-glob": "^1.0.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", @@ -246,6 +266,110 @@ } } }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.12.0.tgz", + "integrity": "sha512-+ac02NL/2TCKRrJu2wffk1kZ+RyqxVUlbjSagNgPm94frxtr+XDL12E5Ll1enWskLrtrZ2r8L3wED1orIibV/w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.12.0.tgz", + "integrity": "sha512-OBqcX2BMe6nvjQ0Nyp7cC90cnumt8PXmO7Dp3gfAju/6YwG0Tj74z1vKrfRz7qAv23nBcYM8BCbhrsWqO7PzQQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.12.0.tgz", + "integrity": "sha512-X64tZd8dRE/QTrBIEs63kaOBG0b5GVEd3ccoLtyf6IdXtHdh8h+I56C2yC3PtC9Ucnv0CpNFJLqKFVgCYe0lOQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.12.0.tgz", + "integrity": "sha512-cc71KUZoVbUJmGP2cOuiZ9HSOP14AzBAThn3OU+9LcA1+IUqswJyR1cAJj3Mg55HbjZP6OLAIscbQsQLrpgTOg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.12.0.tgz", + "integrity": "sha512-a6w/Y3hyyO6GlpKL2xJ4IOh/7d+APaqLYdMf86xnczU3nurFTaVN9s9jOXQg97BE4nYm/7Ga51rjec5nfRdrvA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.12.0.tgz", + "integrity": "sha512-0fZBq27b+D7Ar5CQMofVN8sggOVhEtzFUwOwPppQt0k+VR+7UHMZZY4y+64WJ06XOhBTKXtQB/Sv0NwQMXyNAA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.12.0.tgz", + "integrity": "sha512-eTvzUS3hhhlgeAv6bfigekzWZjaEX9xP9HhxB0Dvrdbkk5w/b+1Sxct2ZuDxNJKzsRStSq1EaEkVSEe7A7ipgQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.12.0.tgz", + "integrity": "sha512-ix+qAB9qmrCRiaO71VFfY8rkiAZJL8zQRXveS27HS+pKdjwUfEhqo2+YF2oI+H/22Xsiski+qqwIBxVewLK7sw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@rollup/rollup-linux-x64-gnu": { "version": "4.12.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.12.0.tgz", @@ -272,6 +396,45 @@ "linux" ] }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.12.0.tgz", + "integrity": "sha512-JPDxovheWNp6d7AHCgsUlkuCKvtu3RB55iNEkaQcf0ttsDU/JZF+iQnYcQJSk/7PtT4mjjVG8N1kpwnI9SLYaw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.12.0.tgz", + "integrity": "sha512-fjtuvMWRGJn1oZacG8IPnzIV6GF2/XG+h71FKn76OYFqySXInJtseAqdprVTDTyqPxQOG9Exak5/E9Z3+EJ8ZA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.12.0.tgz", + "integrity": "sha512-ZYmr5mS2wd4Dew/JjT0Fqi2NPB/ZhZ2VvPp7SmvPZb4Y1CG/LRcS6tcRo2cYU7zLK5A7cdbhWnnWmUjoI4qapg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@trysound/sax": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", @@ -303,9 +466,9 @@ "dev": true }, "node_modules/acorn": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", + "version": "5.7.4", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", + "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -324,18 +487,6 @@ "acorn": "^5.0.0" } }, - "node_modules/acorn-dynamic-import/node_modules/acorn": { - "version": "5.7.4", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", - "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/ansi-colors": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", @@ -348,18 +499,6 @@ "node": ">=0.10.0" } }, - "node_modules/ansi-gray": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", - "integrity": "sha512-HrgGIZUl8h2EHuZaU9hTR/cU5nhKxpVE1V6kdGsQ8e4zirElJ5fvtfc8N7Q1oq1aatO275i8pUFUCpNWCAnVWw==", - "dev": true, - "dependencies": { - "ansi-wrap": "0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -511,24 +650,6 @@ "node": ">=0.10.0" } }, - "node_modules/append-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz", - "integrity": "sha512-WLbYiXzD3y/ATLZFufV/rZvWdZOs+Z/+5v1rBZ463Jn398pa6kcde27cvozYnBoxXblGZTFfoPpsaEw0orU5BA==", - "dev": true, - "dependencies": { - "buffer-equal": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", - "dev": true - }, "node_modules/argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -547,18 +668,6 @@ "node": ">=0.10.0" } }, - "node_modules/arr-filter": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz", - "integrity": "sha512-A2BETWCqhsecSvCkWAeVBFLH6sXEUGASuzkpjL3GR1SlL/PWL6M3J8EAAld2Uubmh39tvkJTqC9LeLHCUKmFXA==", - "dev": true, - "dependencies": { - "make-iterator": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/arr-flatten": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", @@ -568,18 +677,6 @@ "node": ">=0.10.0" } }, - "node_modules/arr-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz", - "integrity": "sha512-tVqVTHt+Q5Xb09qRkbu+DidW1yYzz5izWS2Xm2yFm7qJnmUfz4HPzNxbHkdRJbz2lrqI7S+z17xNYdFcBBO8Hw==", - "dev": true, - "dependencies": { - "make-iterator": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/arr-union": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", @@ -598,49 +695,6 @@ "node": ">=0.10.0" } }, - "node_modules/array-initial": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz", - "integrity": "sha512-BC4Yl89vneCYfpLrs5JU2aAu9/a+xWbeKhvISg9PT7eWFB9UlRvI+rKEtk6mgxWr3dSkk9gQ8hCrdqt06NXPdw==", - "dev": true, - "dependencies": { - "array-slice": "^1.0.0", - "is-number": "^4.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array-initial/node_modules/is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array-last": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/array-last/-/array-last-1.3.0.tgz", - "integrity": "sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==", - "dev": true, - "dependencies": { - "is-number": "^4.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array-last/node_modules/is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/array-slice": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", @@ -650,20 +704,6 @@ "node": ">=0.10.0" } }, - "node_modules/array-sort": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-sort/-/array-sort-1.0.0.tgz", - "integrity": "sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==", - "dev": true, - "dependencies": { - "default-compare": "^1.0.0", - "get-value": "^2.0.6", - "kind-of": "^5.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/array-union": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/array-union/-/array-union-3.0.1.tgz", @@ -701,18 +741,17 @@ "dev": true }, "node_modules/async-done": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.2.tgz", - "integrity": "sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/async-done/-/async-done-2.0.0.tgz", + "integrity": "sha512-j0s3bzYq9yKIVLKGE/tWlCpa3PfFLcrDZLTSVdnnCTGagXuXBJO4SsY9Xdk/fQBirCkH4evW5xOeJXqlAQFdsw==", "dev": true, "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.2", - "process-nextick-args": "^2.0.0", - "stream-exhaust": "^1.0.1" + "end-of-stream": "^1.4.4", + "once": "^1.4.0", + "stream-exhaust": "^1.0.2" }, "engines": { - "node": ">= 0.10" + "node": ">= 10.13.0" } }, "node_modules/async-each": { @@ -728,15 +767,15 @@ ] }, "node_modules/async-settle": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz", - "integrity": "sha512-VPXfB4Vk49z1LHHodrEQ6Xf7W4gg1w0dAPROHngx7qgDjqmIQ+fXmwgGXTW/ITLai0YLSvWepJOP9EVpMnEAcw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-2.0.0.tgz", + "integrity": "sha512-Obu/KE8FurfQRN6ODdHN9LuXqwC+JFIM9NRyZqJJ4ZfLJmIYN9Rg0/kb+wF70VV5+fJusTMQlJ1t5rF7J/ETdg==", "dev": true, "dependencies": { - "async-done": "^1.2.2" + "async-done": "^2.0.0" }, "engines": { - "node": ">= 0.10" + "node": ">= 10.13.0" } }, "node_modules/atob": { @@ -788,24 +827,24 @@ "postcss": "^8.1.0" } }, + "node_modules/b4a": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz", + "integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==", + "dev": true + }, "node_modules/bach": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz", - "integrity": "sha512-bZOOfCb3gXBXbTFXq3OZtGR88LwGeJvzu6szttaIzymOTS4ZttBNOWSv7aLZja2EMycKtRYV0Oa8SNKH/zkxvg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/bach/-/bach-2.0.1.tgz", + "integrity": "sha512-A7bvGMGiTOxGMpNupYl9HQTf0FFDNF4VCmks4PJpFyN1AX2pdKuxuwdvUz2Hu388wcgp+OvGFNsumBfFNkR7eg==", "dev": true, "dependencies": { - "arr-filter": "^1.1.1", - "arr-flatten": "^1.0.1", - "arr-map": "^2.0.0", - "array-each": "^1.0.0", - "array-initial": "^1.0.0", - "array-last": "^1.1.1", - "async-done": "^1.2.2", - "async-settle": "^1.0.0", - "now-and-later": "^2.0.0" + "async-done": "^2.0.0", + "async-settle": "^2.0.0", + "now-and-later": "^3.0.0" }, "engines": { - "node": ">= 0.10" + "node": ">=10.13.0" } }, "node_modules/balanced-match": { @@ -814,6 +853,13 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/bare-events": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.4.2.tgz", + "integrity": "sha512-qMKFd2qG/36aA4GwvKq8MxnPgCQAmBWmSyLWsJcbn8v03wvIPQ/hG1Ms8bPzndZxMDoHpxez5VOS+gC9Yi24/Q==", + "dev": true, + "optional": true + }, "node_modules/base": { "version": "0.11.2", "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", @@ -857,6 +903,26 @@ "node": ">= 0.4" } }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/binary-extensions": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", @@ -866,6 +932,41 @@ "node": ">=0.10.0" } }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dev": true, + "optional": true, + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/bl": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz", + "integrity": "sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==", + "dev": true, + "dependencies": { + "buffer": "^6.0.3", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/body": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/body/-/body-5.1.0.tgz", @@ -965,16 +1066,28 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/buffer-equal": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.1.tgz", - "integrity": "sha512-QoV3ptgEaQpvVwbXdSO39iqPQTCxSF7A5U99AxbHYqUdCizL/lH2Z0A2y6nbZucxMEOtNyZfG2s6gsVugGpKkg==", + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", "dev": true, - "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" } }, "node_modules/buffer-from": { @@ -1028,15 +1141,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/camelcase": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/caniuse-api": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", @@ -1145,35 +1249,14 @@ } }, "node_modules/cliui": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", - "integrity": "sha512-0yayqDxWQbqk3ojkYqUKqaAQ6AfNKeKWRNA8kR0WXzAsdHpP4BIaOmMAG87JGuO6qcobyW4GjxHd9PmhEd+T9w==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, "dependencies": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wrap-ansi": "^2.0.0" - } - }, - "node_modules/cliui/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cliui/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" } }, "node_modules/clone": { @@ -1221,29 +1304,6 @@ "node": ">= 0.12.0" } }, - "node_modules/code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/collection-map": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz", - "integrity": "sha512-5D2XXSpkOnleOI21TG7p3T0bGAsZ/XknZpKBmGYyluO8pw4zA3K8ZlrBIbC4FXg3m6z/RNFiUFfT2sQK01+UHA==", - "dev": true, - "dependencies": { - "arr-map": "^2.0.2", - "for-own": "^1.0.0", - "make-iterator": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/collection-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", @@ -1275,15 +1335,6 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "dev": true, - "bin": { - "color-support": "bin.js" - } - }, "node_modules/colord": { "version": "2.9.3", "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", @@ -1390,13 +1441,16 @@ } }, "node_modules/copy-props": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-2.0.5.tgz", - "integrity": "sha512-XBlx8HSqrT0ObQwmSzM7WE5k8FxTV75h1DX1Z3n6NhQ/UYYAvInWYmG06vFt7hQZArE2fuO62aihiWIVQwh1sw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-4.0.0.tgz", + "integrity": "sha512-bVWtw1wQLzzKiYROtvNlbJgxgBYt2bMJpkCbKmXM3xyijvcjjWXEk5nyrrT3bgJ7ODb19ZohE2T0Y3FgNPyoTw==", "dev": true, "dependencies": { - "each-props": "^1.3.2", + "each-props": "^3.0.0", "is-plain-object": "^5.0.0" + }, + "engines": { + "node": ">= 10.13.0" } }, "node_modules/core-util-is": { @@ -1406,14 +1460,15 @@ "dev": true }, "node_modules/css": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/css/-/css-3.0.0.tgz", - "integrity": "sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ==", + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz", + "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==", "dev": true, "dependencies": { - "inherits": "^2.0.4", + "inherits": "^2.0.3", "source-map": "^0.6.1", - "source-map-resolve": "^0.6.0" + "source-map-resolve": "^0.5.2", + "urix": "^0.1.0" } }, "node_modules/css-declaration-sorter": { @@ -1641,51 +1696,21 @@ "object-assign": "4.X" } }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decode-uri-component": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", - "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", - "dev": true, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/default-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz", - "integrity": "sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==", - "dev": true, - "dependencies": { - "kind-of": "^5.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/default-resolution": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz", - "integrity": "sha512-2xaP6GiwVwOEbXCGoJ4ufgC76m8cj805jrghScewJC2ZDsb9U0b4BIrba+xt/Uytyd0HvQ6+WymSRTfnYj59GQ==", + "node_modules/decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", "dev": true, "engines": { - "node": ">= 0.10" + "node": ">=0.10" } }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -1703,23 +1728,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", @@ -1826,38 +1834,17 @@ "url": "https://github.com/fb55/domutils?sponsor=1" } }, - "node_modules/duplexify": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", - "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" - } - }, "node_modules/each-props": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/each-props/-/each-props-1.3.2.tgz", - "integrity": "sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/each-props/-/each-props-3.0.0.tgz", + "integrity": "sha512-IYf1hpuWrdzse/s/YJOrFmU15lyhSzxelNVAHTEG3DtP4QsLTWZUzcUL3HMXmKQxXpa4EIrBPpwRgj0aehdvAw==", "dev": true, "dependencies": { - "is-plain-object": "^2.0.1", + "is-plain-object": "^5.0.0", "object.defaults": "^1.1.0" - } - }, - "node_modules/each-props/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">= 10.13.0" } }, "node_modules/electron-to-chromium": { @@ -1912,15 +1899,6 @@ "string-template": "~0.2.1" } }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, "node_modules/es-define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", @@ -2193,20 +2171,11 @@ "node": ">= 0.4" } }, - "node_modules/fancy-log": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", - "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==", - "dev": true, - "dependencies": { - "ansi-gray": "^0.1.1", - "color-support": "^1.1.3", - "parse-node-version": "^1.0.0", - "time-stamp": "^1.0.0" - }, - "engines": { - "node": ">= 0.10" - } + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "dev": true }, "node_modules/fast-glob": { "version": "3.3.2", @@ -2242,6 +2211,15 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "engines": { + "node": ">= 4.9.1" + } + }, "node_modules/fastq": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", @@ -2263,6 +2241,13 @@ "node": ">=0.4.0" } }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true, + "optional": true + }, "node_modules/fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", @@ -2278,19 +2263,6 @@ "node": ">=0.10.0" } }, - "node_modules/find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", - "dev": true, - "dependencies": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/findup-sync": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-5.0.0.tgz", @@ -2343,16 +2315,6 @@ "node": ">= 0.10" } }, - "node_modules/flush-write-stream": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", - "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "readable-stream": "^2.3.6" - } - }, "node_modules/for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", @@ -2411,26 +2373,16 @@ } }, "node_modules/fs-mkdirp-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz", - "integrity": "sha512-+vSd9frUnapVC2RZYfL3FCB2p3g4TBhaUmrsWlSudsGdnxIuUvBB2QM1VZeBtc49QFwrp+wQLrDs3+xxDgI5gQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-2.0.1.tgz", + "integrity": "sha512-UTOY+59K6IA94tec8Wjqm0FSh5OVudGNB0NL/P6fB3HiE3bYOY3VYBGijsnOHNkQSwC1FKkU77pmq7xp9CskLw==", "dev": true, "dependencies": { - "graceful-fs": "^4.1.11", - "through2": "^2.0.3" + "graceful-fs": "^4.2.8", + "streamx": "^2.12.0" }, "engines": { - "node": ">= 0.10" - } - }, - "node_modules/fs-mkdirp-stream/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" + "node": ">=10.13.0" } }, "node_modules/fs.realpath": { @@ -2439,6 +2391,25 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, + "node_modules/fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "deprecated": "The v1 package contains DANGEROUS / INSECURE binaries. Upgrade to safe fsevents v2", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + }, + "engines": { + "node": ">= 4.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -2461,10 +2432,13 @@ } }, "node_modules/get-caller-file": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", - "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", - "dev": true + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } }, "node_modules/get-intrinsic": { "version": "1.2.4", @@ -2512,88 +2486,250 @@ "integrity": "sha512-2zblDBaFcb3rB4rF77XVnuINOE2h2k/OnqXAiy0IrTxUfV1iFp3la33oAQVY9pCpWU268WFYVt2t71hlMuLsOg==", "dev": true, "engines": { - "node": ">=10" + "node": ">=10" + } + }, + "node_modules/glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", + "dev": true, + "dependencies": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + } + }, + "node_modules/glob-parent/node_modules/is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob-stream": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-8.0.2.tgz", + "integrity": "sha512-R8z6eTB55t3QeZMmU1C+Gv+t5UnNRkA55c5yo67fAVfxODxieTwsjNG7utxS/73NdP1NbDgCrhVEg2h00y4fFw==", + "dev": true, + "dependencies": { + "@gulpjs/to-absolute-glob": "^4.0.0", + "anymatch": "^3.1.3", + "fastq": "^1.13.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "is-negated-glob": "^1.0.0", + "normalize-path": "^3.0.0", + "streamx": "^2.12.5" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob-stream/node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/glob-stream/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob-watcher": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-6.0.0.tgz", + "integrity": "sha512-wGM28Ehmcnk2NqRORXFOTOR064L4imSw3EeOqU5bIwUf62eXGwg89WivH6VMahL8zlQHeodzvHpXplrqzrz3Nw==", + "dev": true, + "dependencies": { + "async-done": "^2.0.0", + "chokidar": "^3.5.3" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/glob-watcher/node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/glob-watcher/node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob-watcher/node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/glob-watcher/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/glob-watcher/node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/glob-watcher/node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "node_modules/glob-watcher/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "is-glob": "^4.0.1" }, "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">= 6" } }, - "node_modules/glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", + "node_modules/glob-watcher/node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, "dependencies": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/glob-parent/node_modules/is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", + "node_modules/glob-watcher/node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, - "dependencies": { - "is-extglob": "^2.1.0" - }, "engines": { - "node": ">=0.10.0" + "node": ">=0.12.0" } }, - "node_modules/glob-stream": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz", - "integrity": "sha512-uMbLGAP3S2aDOHUDfdoYcdIePUCfysbAd0IAoWVZbeGU/oNQ8asHVSshLDJUPWxfzj8zsCG7/XeHPHTtow0nsw==", + "node_modules/glob-watcher/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, "dependencies": { - "extend": "^3.0.0", - "glob": "^7.1.1", - "glob-parent": "^3.1.0", - "is-negated-glob": "^1.0.0", - "ordered-read-streams": "^1.0.0", - "pumpify": "^1.3.5", - "readable-stream": "^2.1.5", - "remove-trailing-separator": "^1.0.1", - "to-absolute-glob": "^2.0.0", - "unique-stream": "^2.0.2" + "picomatch": "^2.2.1" }, "engines": { - "node": ">= 0.10" + "node": ">=8.10.0" } }, - "node_modules/glob-watcher": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.5.tgz", - "integrity": "sha512-zOZgGGEHPklZNjZQaZ9f41i7F2YwE+tS5ZHrDhbBCk3stwahn5vQxnFmBJZHoYdusR6R1bLSXeGUy/BhctwKzw==", + "node_modules/glob-watcher/node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "dependencies": { - "anymatch": "^2.0.0", - "async-done": "^1.2.0", - "chokidar": "^2.0.0", - "is-negated-glob": "^1.0.0", - "just-debounce": "^1.0.0", - "normalize-path": "^3.0.0", - "object.defaults": "^1.1.0" + "is-number": "^7.0.0" }, "engines": { - "node": ">= 0.10" + "node": ">=8.0" } }, "node_modules/global-modules": { @@ -2673,15 +2809,15 @@ } }, "node_modules/glogg": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.2.tgz", - "integrity": "sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/glogg/-/glogg-2.2.0.tgz", + "integrity": "sha512-eWv1ds/zAlz+M1ioHsyKJomfY7jbDDPpwSkv14KQj89bycx1nvK5/2Cj/T9g7kzJcX5Bc7Yv22FjfBZS/jl94A==", "dev": true, "dependencies": { - "sparkles": "^1.0.0" + "sparkles": "^2.1.0" }, "engines": { - "node": ">= 0.10" + "node": ">= 10.13.0" } }, "node_modules/gopd": { @@ -2900,21 +3036,21 @@ } }, "node_modules/gulp": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.2.tgz", - "integrity": "sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/gulp/-/gulp-5.0.0.tgz", + "integrity": "sha512-S8Z8066SSileaYw1S2N1I64IUc/myI2bqe2ihOBzO6+nKpvNSg7ZcWJt/AwF8LC/NVN+/QZ560Cb/5OPsyhkhg==", "dev": true, "dependencies": { - "glob-watcher": "^5.0.3", - "gulp-cli": "^2.2.0", - "undertaker": "^1.2.1", - "vinyl-fs": "^3.0.0" + "glob-watcher": "^6.0.0", + "gulp-cli": "^3.0.0", + "undertaker": "^2.0.0", + "vinyl-fs": "^4.0.0" }, "bin": { "gulp": "bin/gulp.js" }, "engines": { - "node": ">= 0.10" + "node": ">=10.13.0" } }, "node_modules/gulp-clean-css": { @@ -2930,44 +3066,47 @@ } }, "node_modules/gulp-cli": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-2.3.0.tgz", - "integrity": "sha512-zzGBl5fHo0EKSXsHzjspp3y5CONegCm8ErO5Qh0UzFzk2y4tMvzLWhoDokADbarfZRL2pGpRp7yt6gfJX4ph7A==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-3.0.0.tgz", + "integrity": "sha512-RtMIitkT8DEMZZygHK2vEuLPqLPAFB4sntSxg4NoDta7ciwGZ18l7JuhCTiS5deOJi2IoK0btE+hs6R4sfj7AA==", "dev": true, "dependencies": { - "ansi-colors": "^1.0.1", - "archy": "^1.0.0", - "array-sort": "^1.0.0", - "color-support": "^1.1.3", - "concat-stream": "^1.6.0", - "copy-props": "^2.0.1", - "fancy-log": "^1.3.2", - "gulplog": "^1.0.0", - "interpret": "^1.4.0", - "isobject": "^3.0.1", - "liftoff": "^3.1.0", - "matchdep": "^2.0.0", - "mute-stdout": "^1.0.0", - "pretty-hrtime": "^1.0.0", - "replace-homedir": "^1.0.0", - "semver-greatest-satisfied-range": "^1.1.0", - "v8flags": "^3.2.0", - "yargs": "^7.1.0" + "@gulpjs/messages": "^1.1.0", + "chalk": "^4.1.2", + "copy-props": "^4.0.0", + "gulplog": "^2.2.0", + "interpret": "^3.1.1", + "liftoff": "^5.0.0", + "mute-stdout": "^2.0.0", + "replace-homedir": "^2.0.0", + "semver-greatest-satisfied-range": "^2.0.0", + "string-width": "^4.2.3", + "v8flags": "^4.0.0", + "yargs": "^16.2.0" }, "bin": { "gulp": "bin/gulp.js" }, "engines": { - "node": ">= 0.10" + "node": ">=10.13.0" } }, "node_modules/gulp-cli/node_modules/interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", "dev": true, "engines": { - "node": ">= 0.10" + "node": ">=10.13.0" + } + }, + "node_modules/gulp-cli/node_modules/v8flags": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-4.0.1.tgz", + "integrity": "sha512-fcRLaS4H/hrZk9hYwbdRM35D0U8IYMfEClhXxCivOojl+yTRAZH3Zy2sSy6qVCiGbV9YAtPssP6jaChqC9vPCg==", + "dev": true, + "engines": { + "node": ">= 10.13.0" } }, "node_modules/gulp-concat": { @@ -3061,25 +3200,25 @@ } }, "node_modules/gulp-sourcemaps": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/gulp-sourcemaps/-/gulp-sourcemaps-3.0.0.tgz", - "integrity": "sha512-RqvUckJkuYqy4VaIH60RMal4ZtG0IbQ6PXMNkNsshEGJ9cldUPRb/YCgboYae+CLAs1HQNb4ADTKCx65HInquQ==", - "dev": true, - "dependencies": { - "@gulp-sourcemaps/identity-map": "^2.0.1", - "@gulp-sourcemaps/map-sources": "^1.0.0", - "acorn": "^6.4.1", - "convert-source-map": "^1.0.0", - "css": "^3.0.0", - "debug-fabulous": "^1.0.0", - "detect-newline": "^2.0.0", - "graceful-fs": "^4.0.0", - "source-map": "^0.6.0", - "strip-bom-string": "^1.0.0", - "through2": "^2.0.0" + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/gulp-sourcemaps/-/gulp-sourcemaps-2.6.5.tgz", + "integrity": "sha512-SYLBRzPTew8T5Suh2U8jCSDKY+4NARua4aqjj8HOysBh2tSgT9u4jc1FYirAdPx1akUxxDeK++fqw6Jg0LkQRg==", + "dev": true, + "dependencies": { + "@gulp-sourcemaps/identity-map": "1.X", + "@gulp-sourcemaps/map-sources": "1.X", + "acorn": "5.X", + "convert-source-map": "1.X", + "css": "2.X", + "debug-fabulous": "1.X", + "detect-newline": "2.X", + "graceful-fs": "4.X", + "source-map": "~0.6.0", + "strip-bom-string": "1.X", + "through2": "2.X" }, "engines": { - "node": ">= 6" + "node": ">=4" } }, "node_modules/gulp-sourcemaps/node_modules/source-map": { @@ -3115,15 +3254,15 @@ } }, "node_modules/gulplog": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", - "integrity": "sha512-hm6N8nrm3Y08jXie48jsC55eCZz9mnb4OirAStEk2deqeyhXU3C1otDVh+ccttMuc1sBi6RX6ZJ720hs9RCvgw==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-2.2.0.tgz", + "integrity": "sha512-V2FaKiOhpR3DRXZuYdRLn/qiY0yI5XmqbTKrYbdemJ+xOh2d2MOweI/XFgMzd/9+1twdvMwllnZbWZNJ+BOm4A==", "dev": true, "dependencies": { - "glogg": "^1.0.0" + "glogg": "^2.2.0" }, "engines": { - "node": ">= 0.10" + "node": ">= 10.13.0" } }, "node_modules/has-flag": { @@ -3243,12 +3382,6 @@ "node": "*" } }, - "node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, "node_modules/http-parser-js": { "version": "0.5.8", "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", @@ -3267,6 +3400,26 @@ "node": ">=0.10.0" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/ignore": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", @@ -3323,15 +3476,6 @@ "integrity": "sha512-CLM8SNMDu7C5psFCn6Wg/tgpj/bKAg7hc2gWqcuR9OD5Ft9PhBpIu8PLicPeis+xDd6YX2ncI8MCA64I9tftIA==", "dev": true }, - "node_modules/invert-kv": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", - "integrity": "sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-absolute": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", @@ -3357,12 +3501,6 @@ "node": ">= 0.10" } }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, "node_modules/is-binary-path": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", @@ -3437,15 +3575,12 @@ } }, "node_modules/is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, - "dependencies": { - "number-is-nan": "^1.0.0" - }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, "node_modules/is-glob": { @@ -3541,12 +3676,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", - "dev": true - }, "node_modules/is-valid-glob": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz", @@ -3628,12 +3757,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, "node_modules/jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", @@ -3643,68 +3766,22 @@ "graceful-fs": "^4.1.6" } }, - "node_modules/just-debounce": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.1.0.tgz", - "integrity": "sha512-qpcRocdkUmf+UTNBYx5w6dexX5J31AKK1OmPwH630a83DdVVUIngk55RSAiIGpQyoH0dlr872VHfPjnQnK1qDQ==", - "dev": true - }, - "node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/last-run": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz", - "integrity": "sha512-U/VxvpX4N/rFvPzr3qG5EtLKEnNI0emvIQB3/ecEwv+8GHaUKbIB8vxv1Oai5FAF0d0r7LXHhLLe5K/yChm5GQ==", - "dev": true, - "dependencies": { - "default-resolution": "^2.0.0", - "es6-weak-map": "^2.0.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/lazystream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", - "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", - "dev": true, - "dependencies": { - "readable-stream": "^2.0.5" - }, - "engines": { - "node": ">= 0.6.3" - } - }, - "node_modules/lcid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", - "integrity": "sha512-YiGkH6EnGrDGqLMITnGjXtGmNtjoXw9SVUzcaos8RBi7Ps0VBylkq+vOcY9QE5poLasPCR849ucFUkl0UzUyOw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/last-run/-/last-run-2.0.0.tgz", + "integrity": "sha512-j+y6WhTLN4Itnf9j5ZQos1BGPCS8DAwmgMroR3OzfxAsBxam0hMw7J8M3KqZl0pLQJ1jNnwIexg5DYpC/ctwEQ==", "dev": true, - "dependencies": { - "invert-kv": "^1.0.0" - }, "engines": { - "node": ">=0.10.0" + "node": ">= 10.13.0" } }, "node_modules/lead": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz", - "integrity": "sha512-IpSVCk9AYvLHo5ctcIXxOBpMWUe+4TKN3VPWAKUbJikkmsGp0VrSM8IttVc32D6J4WUsiPE6aEFRNmIoF/gdow==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/lead/-/lead-4.0.0.tgz", + "integrity": "sha512-DpMa59o5uGUWWjruMp71e6knmwKU3jRBBn1kjuLWN9EeIOxNeSAwvHf03WIl8g/ZMR2oSQC9ej3yeLBwdDc/pg==", "dev": true, - "dependencies": { - "flush-write-stream": "^1.0.2" - }, "engines": { - "node": ">= 0.10" + "node": ">=10.13.0" } }, "node_modules/less": { @@ -3855,169 +3932,82 @@ "node": ">=0.10.0" } }, - "node_modules/less-plugin-autoprefix/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/less/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/liftoff": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", - "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==", - "dev": true, - "dependencies": { - "extend": "^3.0.0", - "findup-sync": "^3.0.0", - "fined": "^1.0.1", - "flagged-respawn": "^1.0.0", - "is-plain-object": "^2.0.4", - "object.map": "^1.0.0", - "rechoir": "^0.6.2", - "resolve": "^1.1.7" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/liftoff/node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/liftoff/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", - "dev": true, - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/liftoff/node_modules/findup-sync": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", - "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", + "node_modules/less-plugin-autoprefix/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "dependencies": { - "detect-file": "^1.0.0", - "is-glob": "^4.0.0", - "micromatch": "^3.0.4", - "resolve-dir": "^1.0.1" + "has-flag": "^3.0.0" }, "engines": { - "node": ">= 0.10" + "node": ">=4" } }, - "node_modules/liftoff/node_modules/is-descriptor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", - "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "node_modules/less/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" - }, + "optional": true, "engines": { - "node": ">= 0.4" + "node": ">=0.10.0" } }, - "node_modules/liftoff/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", "dev": true, "dependencies": { - "is-plain-object": "^2.0.4" + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.8.0" } }, - "node_modules/liftoff/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "node_modules/liftoff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-5.0.0.tgz", + "integrity": "sha512-a5BQjbCHnB+cy+gsro8lXJ4kZluzOijzJ1UVVfyJYZC+IP2pLv1h4+aysQeKuTmyO8NAqfyQAk4HWaP/HjcKTg==", "dev": true, "dependencies": { - "isobject": "^3.0.1" + "extend": "^3.0.2", + "findup-sync": "^5.0.0", + "fined": "^2.0.0", + "flagged-respawn": "^2.0.0", + "is-plain-object": "^5.0.0", + "rechoir": "^0.8.0", + "resolve": "^1.20.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=10.13.0" } }, - "node_modules/liftoff/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "node_modules/liftoff/node_modules/fined": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fined/-/fined-2.0.0.tgz", + "integrity": "sha512-OFRzsL6ZMHz5s0JrsEr+TpdGNCtrVtnuG3x1yzGNiQHT0yaDnXAj8V/lWcpJVrnoDpcwXcASxAZYbuXda2Y82A==", "dev": true, + "dependencies": { + "expand-tilde": "^2.0.2", + "is-plain-object": "^5.0.0", + "object.defaults": "^1.1.0", + "object.pick": "^1.3.0", + "parse-filepath": "^1.0.2" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 10.13.0" } }, - "node_modules/liftoff/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "node_modules/liftoff/node_modules/flagged-respawn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-2.0.0.tgz", + "integrity": "sha512-Gq/a6YCi8zexmGHMuJwahTGzXlAZAOsbCVKduWXC6TlLCjjFRlExMJc4GC2NYPYZ0r/brw9P7CpRgQmlPVeOoA==", "dev": true, - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, "engines": { - "node": ">=0.10.0" + "node": ">= 10.13.0" } }, "node_modules/liftup": { @@ -4093,31 +4083,6 @@ "integrity": "sha512-XPQH8Z2GDP/Hwz2PCDrh2mth4yFejwA1OZ/81Ti3LgKyhDcEjsSsqFWZojHG0va/duGd+WyosY7eXLDoOyqcPw==", "dev": true }, - "node_modules/load-json-file": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/load-json-file/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/locate-character": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-2.0.5.tgz", @@ -4252,144 +4217,6 @@ "node": ">=0.10.0" } }, - "node_modules/matchdep": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz", - "integrity": "sha512-LFgVbaHIHMqCRuCZyfCtUOq9/Lnzhi7Z0KFUE2fhD54+JN2jLh3hC02RLkqauJ3U4soU6H1J3tfj/Byk7GoEjA==", - "dev": true, - "dependencies": { - "findup-sync": "^2.0.0", - "micromatch": "^3.0.4", - "resolve": "^1.4.0", - "stack-trace": "0.0.10" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/matchdep/node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/matchdep/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", - "dev": true, - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/matchdep/node_modules/findup-sync": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", - "integrity": "sha512-vs+3unmJT45eczmcAZ6zMJtxN3l/QXeccaXQx5cu/MeJMhewVfoWZqibRkOxPnmoR59+Zy5hjabfQc6JLSah4g==", - "dev": true, - "dependencies": { - "detect-file": "^1.0.0", - "is-glob": "^3.1.0", - "micromatch": "^3.0.4", - "resolve-dir": "^1.0.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/matchdep/node_modules/is-descriptor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", - "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/matchdep/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/matchdep/node_modules/is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/matchdep/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/matchdep/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/matchdep/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/md5-file": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/md5-file/-/md5-file-2.0.7.tgz", @@ -4441,21 +4268,21 @@ } }, "node_modules/micromatch/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" } }, "node_modules/micromatch/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "dependencies": { "to-regex-range": "^5.0.1" @@ -4563,14 +4390,21 @@ "dev": true }, "node_modules/mute-stdout": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz", - "integrity": "sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-2.0.0.tgz", + "integrity": "sha512-32GSKM3Wyc8dg/p39lWPKYu8zci9mJFzV1Np9Of0ZEpe6Fhssn/FbI7ywAMd40uX+p3ZKh3T5EeCFv81qS3HmQ==", "dev": true, "engines": { - "node": ">= 0.10" + "node": ">= 10.13.0" } }, + "node_modules/nan": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.20.0.tgz", + "integrity": "sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==", + "dev": true, + "optional": true + }, "node_modules/nanoid": { "version": "3.3.7", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", @@ -4724,18 +4558,6 @@ "nopt": "bin/nopt.js" } }, - "node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -4767,15 +4589,15 @@ } }, "node_modules/now-and-later": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz", - "integrity": "sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-3.0.0.tgz", + "integrity": "sha512-pGO4pzSdaxhWTGkfSfHx3hVzJVslFPwBp2Myq9MYN/ChfJZF87ochMAXnvz6/58RJSf5ik2q9tXprBBrk2cpcg==", "dev": true, "dependencies": { - "once": "^1.3.2" + "once": "^1.4.0" }, "engines": { - "node": ">= 0.10" + "node": ">= 10.13.0" } }, "node_modules/nth-check": { @@ -4796,15 +4618,6 @@ "integrity": "sha512-Y1wZESM7VUThYY+4W+X4ySH2maqcA+p7UR+w8VWNWVAd6lwuXXWz/w/Cz43J/dI2I+PS6wD5N+bJUF+gjWvIqg==", "dev": true }, - "node_modules/number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/o-stream": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/o-stream/-/o-stream-0.3.0.tgz", @@ -4855,15 +4668,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/object-visit": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", @@ -4873,25 +4677,7 @@ "isobject": "^3.0.0" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object.assign": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", - "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.10.0" } }, "node_modules/object.defaults": { @@ -4934,19 +4720,6 @@ "node": ">=0.10.0" } }, - "node_modules/object.reduce": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object.reduce/-/object.reduce-1.0.1.tgz", - "integrity": "sha512-naLhxxpUESbNkRqc35oQ2scZSJueHGQNUfMW/0U37IgN6tE2dgDWg3whf+NEliy3F/QysrO48XKUz/nGPe+AQw==", - "dev": true, - "dependencies": { - "for-own": "^1.0.0", - "make-iterator": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -4973,15 +4746,6 @@ "node": ">= 0.8.0" } }, - "node_modules/ordered-read-streams": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", - "integrity": "sha512-Z87aSjx3r5c0ZB7bcJqIgIRX5bxR7A4aSzvIbaxd0oTkWBCOoKfuGHiKj60CHVUgg1Phm5yMZzBdt8XqRs73Mw==", - "dev": true, - "dependencies": { - "readable-stream": "^2.0.1" - } - }, "node_modules/os-homedir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", @@ -4991,18 +4755,6 @@ "node": ">=0.10.0" } }, - "node_modules/os-locale": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", - "integrity": "sha512-PRT7ZORmwu2MEFt4/fv3Q+mEfN4zetKxufQrkShY2oGvUms9r8otu5HfdyIFHkYXjO7laNsoVGmM2MANfuTA8g==", - "dev": true, - "dependencies": { - "lcid": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", @@ -5036,18 +4788,6 @@ "node": ">=0.8" } }, - "node_modules/parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", - "dev": true, - "dependencies": { - "error-ex": "^1.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/parse-ms": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-1.0.1.tgz", @@ -5090,18 +4830,6 @@ "integrity": "sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==", "dev": true }, - "node_modules/path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", - "dev": true, - "dependencies": { - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -5184,27 +4912,6 @@ "node": ">=6" } }, - "node_modules/pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", - "dev": true, - "dependencies": { - "pinkie": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/plugin-error": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", @@ -5359,12 +5066,12 @@ } }, "node_modules/postcss-cli/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -5409,9 +5116,9 @@ } }, "node_modules/postcss-cli/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "dependencies": { "to-regex-range": "^5.0.1" @@ -5434,13 +5141,18 @@ "node": ">=12" } }, - "node_modules/postcss-cli/node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "node_modules/postcss-cli/node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": "6.* || 8.* || >= 10.*" + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, "node_modules/postcss-cli/node_modules/glob-parent": { @@ -5467,15 +5179,6 @@ "node": ">=8" } }, - "node_modules/postcss-cli/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/postcss-cli/node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -5509,20 +5212,6 @@ "node": ">=8.10.0" } }, - "node_modules/postcss-cli/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/postcss-cli/node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -5544,32 +5233,6 @@ "node": ">= 10.0.0" } }, - "node_modules/postcss-cli/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/postcss-cli/node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, "node_modules/postcss-cli/node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", @@ -6106,27 +5769,6 @@ "dev": true, "optional": true }, - "node_modules/pump": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/pumpify": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", - "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", - "dev": true, - "dependencies": { - "duplexify": "^3.6.0", - "inherits": "^2.0.3", - "pump": "^2.0.0" - } - }, "node_modules/qs": { "version": "6.11.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", @@ -6162,6 +5804,12 @@ } ] }, + "node_modules/queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", + "dev": true + }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -6208,56 +5856,6 @@ "node": ">=0.10.0" } }, - "node_modules/read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", - "dev": true, - "dependencies": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", - "dev": true, - "dependencies": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/read-pkg/node_modules/path-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/read-pkg/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", @@ -6384,15 +5982,15 @@ } }, "node_modules/rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", "dev": true, "dependencies": { - "resolve": "^1.1.6" + "resolve": "^1.20.0" }, "engines": { - "node": ">= 0.10" + "node": ">= 10.13.0" } }, "node_modules/regex-not": { @@ -6445,43 +6043,6 @@ "node": ">=0.10.0" } }, - "node_modules/remove-bom-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz", - "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5", - "is-utf8": "^0.2.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/remove-bom-stream": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz", - "integrity": "sha512-wigO8/O08XHb8YPzpDDT+QmRANfW6vLqxfaXm1YXhnFf3AkSLyjfG3GEFg4McZkmgL7KvCj5u2KczkvSP6NfHA==", - "dev": true, - "dependencies": { - "remove-bom-buffer": "^3.0.0", - "safe-buffer": "^5.1.0", - "through2": "^2.0.3" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/remove-bom-stream/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, "node_modules/remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", @@ -6516,17 +6077,12 @@ } }, "node_modules/replace-homedir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-1.0.0.tgz", - "integrity": "sha512-CHPV/GAglbIB1tnQgaiysb8H2yCy8WQ7lcEwQ/eT+kLj0QHV8LnJW0zpqpE7RSkrMSRoa+EBoag86clf7WAgSg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-2.0.0.tgz", + "integrity": "sha512-bgEuQQ/BHW0XkkJtawzrfzHFSN70f/3cNOiHa2QsYxqrjaC30X1k74FJ6xswVBP0sr0SpGIdVFuPwfrYziVeyw==", "dev": true, - "dependencies": { - "homedir-polyfill": "^1.0.1", - "is-absolute": "^1.0.0", - "remove-trailing-separator": "^1.1.0" - }, "engines": { - "node": ">= 0.10" + "node": ">= 10.13.0" } }, "node_modules/require-directory": { @@ -6538,12 +6094,6 @@ "node": ">=0.10.0" } }, - "node_modules/require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==", - "dev": true - }, "node_modules/require-relative": { "version": "0.8.7", "resolved": "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz", @@ -6581,15 +6131,15 @@ } }, "node_modules/resolve-options": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz", - "integrity": "sha512-NYDgziiroVeDC29xq7bp/CacZERYsA9bXYd1ZmcJlF3BcrZv5pTb4NG7SjdyKDnXZ84aC4vo2u6sNKIA1LCu/A==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-2.0.0.tgz", + "integrity": "sha512-/FopbmmFOQCfsCx77BRFdKOniglTiHumLgwvd6IDPihy1GKkadZbgQJBcTb2lMzSR1pndzd96b1nZrreZ7+9/A==", "dev": true, "dependencies": { - "value-or-function": "^3.0.0" + "value-or-function": "^4.0.0" }, "engines": { - "node": ">= 0.10" + "node": ">= 10.13.0" } }, "node_modules/resolve-url": { @@ -6658,18 +6208,6 @@ "node": ">=4.0.0" } }, - "node_modules/riot-cli/node_modules/acorn": { - "version": "5.7.4", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", - "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/riot-cli/node_modules/ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", @@ -6855,6 +6393,20 @@ "estree-walker": "^0.6.1" } }, + "node_modules/rollup/node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -6945,12 +6497,12 @@ } }, "node_modules/sass/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -6981,9 +6533,9 @@ } }, "node_modules/sass/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "dependencies": { "to-regex-range": "^5.0.1" @@ -6992,6 +6544,20 @@ "node": ">=8" } }, + "node_modules/sass/node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/sass/node_modules/glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", @@ -7061,20 +6627,21 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, + "optional": true, "bin": { "semver": "bin/semver" } }, "node_modules/semver-greatest-satisfied-range": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz", - "integrity": "sha512-Ny/iyOzSSa8M5ML46IAx3iXc6tfOsYU2R4AXi2UpHk60Zrgyq6eqPj/xiOfS0rRl/iiQ/rdJkVjw/5cdUyCntQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-2.0.0.tgz", + "integrity": "sha512-lH3f6kMbwyANB7HuOWRMlLCa2itaCrZJ+SAqqkSZrZKO/cAsk2EOyaKHUtNkVLFyFW9pct22SFesFp3Z7zpA0g==", "dev": true, "dependencies": { - "sver-compat": "^1.5.0" + "sver": "^1.8.3" }, "engines": { - "node": ">= 0.10" + "node": ">= 10.13.0" } }, "node_modules/serialize-javascript": { @@ -7086,12 +6653,6 @@ "randombytes": "^2.1.0" } }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "dev": true - }, "node_modules/set-function-length": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.1.tgz", @@ -7296,20 +6857,6 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, - "node_modules/snapdragon/node_modules/source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", - "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", - "dev": true, - "dependencies": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, "node_modules/source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -7329,14 +6876,17 @@ } }, "node_modules/source-map-resolve": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.6.0.tgz", - "integrity": "sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==", + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", "dev": true, "dependencies": { "atob": "^2.1.2", - "decode-uri-component": "^0.2.0" + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" } }, "node_modules/source-map-support": { @@ -7373,46 +6923,14 @@ "dev": true }, "node_modules/sparkles": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz", - "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-2.1.0.tgz", + "integrity": "sha512-r7iW1bDw8R/cFifrD3JnQJX0K1jqT0kprL48BiBpLZLJPmAm34zsVBsK5lc7HirZYZqMW65dOXZgbAGt/I6frg==", "dev": true, "engines": { - "node": ">= 0.10" - } - }, - "node_modules/spdx-correct": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", - "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", - "dev": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", - "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", - "dev": true - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" + "node": ">= 10.13.0" } }, - "node_modules/spdx-license-ids": { - "version": "3.0.17", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz", - "integrity": "sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==", - "dev": true - }, "node_modules/split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", @@ -7475,15 +6993,6 @@ "deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility", "dev": true }, - "node_modules/stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/static-extend": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", @@ -7497,17 +7006,34 @@ "node": ">=0.10.0" } }, + "node_modules/stream-composer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stream-composer/-/stream-composer-1.0.2.tgz", + "integrity": "sha512-bnBselmwfX5K10AH6L4c8+S5lgZMWI7ZYrz2rvYjCPB2DIMC4Ig8OpxGpNJSxRZ58oti7y1IcNvjBAz9vW5m4w==", + "dev": true, + "dependencies": { + "streamx": "^2.13.2" + } + }, "node_modules/stream-exhaust": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz", "integrity": "sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==", "dev": true }, - "node_modules/stream-shift": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", - "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==", - "dev": true + "node_modules/streamx": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.18.0.tgz", + "integrity": "sha512-LLUC1TWdjVdn1weXGcSxyTR3T4+acB6tVGXT95y0nGbca4t4o/ng1wKAGTljm9VicuCVLvRlqFYXYy5GwgM7sQ==", + "dev": true, + "dependencies": { + "fast-fifo": "^1.3.2", + "queue-tick": "^1.0.1", + "text-decoder": "^1.1.0" + }, + "optionalDependencies": { + "bare-events": "^2.2.0" + } }, "node_modules/string_decoder": { "version": "1.1.1", @@ -7539,38 +7065,17 @@ "dev": true }, "node_modules/string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", - "dev": true, - "dependencies": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/string-width/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/string-width/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "dependencies": { - "ansi-regex": "^2.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, "node_modules/strip-ansi": { @@ -7585,18 +7090,6 @@ "node": ">=8" } }, - "node_modules/strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==", - "dev": true, - "dependencies": { - "is-utf8": "^0.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/strip-bom-string": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", @@ -7646,14 +7139,23 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/sver-compat": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz", - "integrity": "sha512-aFTHfmjwizMNlNE6dsGmoAM4lHjL0CyiobWaFiXWSlD7cIxshW422Nb8KbXCmR6z+0ZEPY+daXJrDyh/vuwTyg==", + "node_modules/sver": { + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/sver/-/sver-1.8.4.tgz", + "integrity": "sha512-71o1zfzyawLfIWBOmw8brleKyvnbn73oVHNCsu51uPMz/HWiKkkXsI31JjHW5zqXEqnPYkIiHd8ZmL7FCimLEA==", "dev": true, - "dependencies": { - "es6-iterator": "^2.0.1", - "es6-symbol": "^3.1.1" + "optionalDependencies": { + "semver": "^6.3.0" + } + }, + "node_modules/sver/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "optional": true, + "bin": { + "semver": "bin/semver.js" } }, "node_modules/svgo": { @@ -7677,6 +7179,15 @@ "node": ">=10.13.0" } }, + "node_modules/teex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz", + "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==", + "dev": true, + "dependencies": { + "streamx": "^2.12.5" + } + }, "node_modules/terser": { "version": "5.28.1", "resolved": "https://registry.npmjs.org/terser/-/terser-5.28.1.tgz", @@ -7713,6 +7224,15 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true }, + "node_modules/text-decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.1.1.tgz", + "integrity": "sha512-8zll7REEv4GDD3x4/0pW+ppIxSNs7H1J10IKFZsuOMscumCdM2a+toDGLPA3T+1+fLBql4zbt5z83GEQGGV5VA==", + "dev": true, + "dependencies": { + "b4a": "^1.6.4" + } + }, "node_modules/thenby": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/thenby/-/thenby-1.3.4.tgz", @@ -7728,35 +7248,6 @@ "readable-stream": "2 || 3" } }, - "node_modules/through2-filter": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz", - "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==", - "dev": true, - "dependencies": { - "through2": "~2.0.0", - "xtend": "~4.0.0" - } - }, - "node_modules/through2-filter/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "node_modules/time-stamp": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", - "integrity": "sha512-gLCeArryy2yNTRzTGKbZbloctj64jkZ57hj5zdraXue6aFgd6PmvVtEyiUU+hvU0v7q08oVv8r8ev0tRo6bvgw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/time-zone": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/time-zone/-/time-zone-1.0.0.tgz", @@ -7790,19 +7281,6 @@ "qs": "^6.4.0" } }, - "node_modules/to-absolute-glob": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz", - "integrity": "sha512-rtwLUQEwT8ZeKQbyFJyomBRYXyE16U5VKuy0ftxLMK/PZb2fkOsg5r9kHdauuVDbsNdIBoC/HCthpidamQFXYA==", - "dev": true, - "dependencies": { - "is-absolute": "^1.0.0", - "is-negated-glob": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", @@ -7919,25 +7397,15 @@ } }, "node_modules/to-through": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz", - "integrity": "sha512-+QIz37Ly7acM4EMdw2PRN389OneM5+d844tirkGp4dPKzI5OE72V9OsbFp+CIYJDahZ41ZV05hNtcPAQUAm9/Q==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/to-through/-/to-through-3.0.0.tgz", + "integrity": "sha512-y8MN937s/HVhEoBU1SxfHC+wxCHkV1a9gW8eAdTadYh/bGyesZIVcbjI+mSpFbSVwQici/XjBjuUyri1dnXwBw==", "dev": true, "dependencies": { - "through2": "^2.0.3" + "streamx": "^2.12.5" }, "engines": { - "node": ">= 0.10" - } - }, - "node_modules/to-through/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" + "node": ">=10.13.0" } }, "node_modules/tslib": { @@ -7999,40 +7467,37 @@ "dev": true }, "node_modules/undertaker": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.3.0.tgz", - "integrity": "sha512-/RXwi5m/Mu3H6IHQGww3GNt1PNXlbeCuclF2QYR14L/2CHPz3DFZkvB5hZ0N/QUkiXWCACML2jXViIQEQc2MLg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-2.0.0.tgz", + "integrity": "sha512-tO/bf30wBbTsJ7go80j0RzA2rcwX6o7XPBpeFcb+jzoeb4pfMM2zUeSDIkY1AWqeZabWxaQZ/h8N9t35QKDLPQ==", "dev": true, "dependencies": { - "arr-flatten": "^1.0.1", - "arr-map": "^2.0.0", - "bach": "^1.0.0", - "collection-map": "^1.0.0", - "es6-weak-map": "^2.0.1", - "fast-levenshtein": "^1.0.0", - "last-run": "^1.1.0", - "object.defaults": "^1.0.0", - "object.reduce": "^1.0.0", - "undertaker-registry": "^1.0.0" + "bach": "^2.0.1", + "fast-levenshtein": "^3.0.0", + "last-run": "^2.0.0", + "undertaker-registry": "^2.0.0" }, "engines": { - "node": ">= 0.10" + "node": ">=10.13.0" } }, "node_modules/undertaker-registry": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-1.0.1.tgz", - "integrity": "sha512-UR1khWeAjugW3548EfQmL9Z7pGMlBgXteQpr1IZeZBtnkCJQJIJ1Scj0mb9wQaPvUZ9Q17XqW6TIaPchJkyfqw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-2.0.0.tgz", + "integrity": "sha512-+hhVICbnp+rlzZMgxXenpvTxpuvA67Bfgtt+O9WOE5jo7w/dyiF1VmoZVIHvP2EkUjsyKyTwYKlLhA+j47m1Ew==", "dev": true, "engines": { - "node": ">= 0.10" + "node": ">= 10.13.0" } }, "node_modules/undertaker/node_modules/fast-levenshtein": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.1.4.tgz", - "integrity": "sha512-Ia0sQNrMPXXkqVFt6w6M1n1oKo3NfKs+mvaV811Jwir7vAk9a6PVV9VPYf6X3BU97QiLEmuW3uXH9u87zDFfdw==", - "dev": true + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-3.0.0.tgz", + "integrity": "sha512-hKKNajm46uNmTlhHSyZkmToAc56uZJwYq7yrciZjqOxnlfQwERDQJmHPUp7m1m9wx8vgOe8IaCKZ5Kv2k1DdCQ==", + "dev": true, + "dependencies": { + "fastest-levenshtein": "^1.0.7" + } }, "node_modules/union-value": { "version": "1.0.1", @@ -8049,16 +7514,6 @@ "node": ">=0.10.0" } }, - "node_modules/unique-stream": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz", - "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==", - "dev": true, - "dependencies": { - "json-stable-stringify-without-jsonify": "^1.0.1", - "through2-filter": "^3.0.0" - } - }, "node_modules/universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", @@ -8190,23 +7645,13 @@ "node": ">= 0.10" } }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, "node_modules/value-or-function": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz", - "integrity": "sha512-jdBB2FrWvQC/pnPtIqcLsMaQgjhdb6B7tk1MMyTKapox+tQZbdRP4uLxu/JY0t7fbfDCUMnuelzEYv5GsxHhdg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-4.0.0.tgz", + "integrity": "sha512-aeVK81SIuT6aMJfNo9Vte8Dw0/FZINGBV8BfCraGtqVxIeLAEhJyoWs8SmvRVmXfGss2PmmOwZCuBPbZR+IYWg==", "dev": true, "engines": { - "node": ">= 0.10" + "node": ">= 10.13.0" } }, "node_modules/vinyl": { @@ -8226,72 +7671,113 @@ "node": ">= 0.10" } }, + "node_modules/vinyl-contents": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/vinyl-contents/-/vinyl-contents-2.0.0.tgz", + "integrity": "sha512-cHq6NnGyi2pZ7xwdHSW1v4Jfnho4TEGtxZHw01cmnc8+i7jgR6bRnED/LbrKan/Q7CvVLbnvA5OepnhbpjBZ5Q==", + "dev": true, + "dependencies": { + "bl": "^5.0.0", + "vinyl": "^3.0.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/vinyl-contents/node_modules/vinyl": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-3.0.0.tgz", + "integrity": "sha512-rC2VRfAVVCGEgjnxHUnpIVh3AGuk62rP3tqVrn+yab0YH7UULisC085+NYH+mnqf3Wx4SpSi1RQMwudL89N03g==", + "dev": true, + "dependencies": { + "clone": "^2.1.2", + "clone-stats": "^1.0.0", + "remove-trailing-separator": "^1.1.0", + "replace-ext": "^2.0.0", + "teex": "^1.0.1" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/vinyl-fs": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz", - "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-4.0.0.tgz", + "integrity": "sha512-7GbgBnYfaquMk3Qu9g22x000vbYkOex32930rBnc3qByw6HfMEAoELjCjoJv4HuEQxHAurT+nvMHm6MnJllFLw==", "dev": true, "dependencies": { - "fs-mkdirp-stream": "^1.0.0", - "glob-stream": "^6.1.0", - "graceful-fs": "^4.0.0", + "fs-mkdirp-stream": "^2.0.1", + "glob-stream": "^8.0.0", + "graceful-fs": "^4.2.11", + "iconv-lite": "^0.6.3", "is-valid-glob": "^1.0.0", - "lazystream": "^1.0.0", - "lead": "^1.0.0", - "object.assign": "^4.0.4", - "pumpify": "^1.3.5", - "readable-stream": "^2.3.3", - "remove-bom-buffer": "^3.0.0", - "remove-bom-stream": "^1.2.0", - "resolve-options": "^1.1.0", - "through2": "^2.0.0", - "to-through": "^2.0.0", - "value-or-function": "^3.0.0", - "vinyl": "^2.0.0", - "vinyl-sourcemap": "^1.1.0" + "lead": "^4.0.0", + "normalize-path": "3.0.0", + "resolve-options": "^2.0.0", + "stream-composer": "^1.0.2", + "streamx": "^2.14.0", + "to-through": "^3.0.0", + "value-or-function": "^4.0.0", + "vinyl": "^3.0.0", + "vinyl-sourcemap": "^2.0.0" }, "engines": { - "node": ">= 0.10" + "node": ">=10.13.0" } }, - "node_modules/vinyl-fs/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "node_modules/vinyl-fs/node_modules/vinyl": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-3.0.0.tgz", + "integrity": "sha512-rC2VRfAVVCGEgjnxHUnpIVh3AGuk62rP3tqVrn+yab0YH7UULisC085+NYH+mnqf3Wx4SpSi1RQMwudL89N03g==", "dev": true, "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" + "clone": "^2.1.2", + "clone-stats": "^1.0.0", + "remove-trailing-separator": "^1.1.0", + "replace-ext": "^2.0.0", + "teex": "^1.0.1" + }, + "engines": { + "node": ">=10.13.0" } }, "node_modules/vinyl-sourcemap": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz", - "integrity": "sha512-NiibMgt6VJGJmyw7vtzhctDcfKch4e4n9TBeoWlirb7FMg9/1Ov9k+A5ZRAtywBpRPiyECvQRQllYM8dECegVA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-2.0.0.tgz", + "integrity": "sha512-BAEvWxbBUXvlNoFQVFVHpybBbjW1r03WhohJzJDSfgrrK5xVYIDTan6xN14DlyImShgDRv2gl9qhM6irVMsV0Q==", "dev": true, "dependencies": { - "append-buffer": "^1.0.2", - "convert-source-map": "^1.5.0", - "graceful-fs": "^4.1.6", - "normalize-path": "^2.1.1", - "now-and-later": "^2.0.0", - "remove-bom-buffer": "^3.0.0", - "vinyl": "^2.0.0" + "convert-source-map": "^2.0.0", + "graceful-fs": "^4.2.10", + "now-and-later": "^3.0.0", + "streamx": "^2.12.5", + "vinyl": "^3.0.0", + "vinyl-contents": "^2.0.0" }, "engines": { - "node": ">= 0.10" + "node": ">=10.13.0" } }, - "node_modules/vinyl-sourcemap/node_modules/normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", + "node_modules/vinyl-sourcemap/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/vinyl-sourcemap/node_modules/vinyl": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-3.0.0.tgz", + "integrity": "sha512-rC2VRfAVVCGEgjnxHUnpIVh3AGuk62rP3tqVrn+yab0YH7UULisC085+NYH+mnqf3Wx4SpSi1RQMwudL89N03g==", "dev": true, "dependencies": { - "remove-trailing-separator": "^1.0.1" + "clone": "^2.1.2", + "clone-stats": "^1.0.0", + "remove-trailing-separator": "^1.1.0", + "replace-ext": "^2.0.0", + "teex": "^1.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=10.13.0" } }, "node_modules/vinyl-sourcemaps-apply": { @@ -8350,12 +7836,6 @@ "node": ">= 8" } }, - "node_modules/which-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", - "integrity": "sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==", - "dev": true - }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -8366,37 +7846,20 @@ } }, "node_modules/wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "dependencies": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" + "node": ">=10" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, "node_modules/wrappy": { @@ -8415,10 +7878,13 @@ } }, "node_modules/y18n": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz", - "integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==", - "dev": true + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } }, "node_modules/yaml": { "version": "1.10.2", @@ -8430,34 +7896,30 @@ } }, "node_modules/yargs": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.2.tgz", - "integrity": "sha512-ZEjj/dQYQy0Zx0lgLMLR8QuaqTihnxirir7EwUHp1Axq4e3+k8jXU5K0VLbNvedv1f4EWtBonDIZm0NUr+jCcA==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "dev": true, "dependencies": { - "camelcase": "^3.0.0", - "cliui": "^3.2.0", - "decamelize": "^1.1.1", - "get-caller-file": "^1.0.1", - "os-locale": "^1.4.0", - "read-pkg-up": "^1.0.1", + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^1.0.2", - "which-module": "^1.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^5.0.1" + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" } }, "node_modules/yargs-parser": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.1.tgz", - "integrity": "sha512-wpav5XYiddjXxirPoCTUPbqM0PXvJ9hiBMvuJgInvo4/lAOTZzUprArw17q2O1P2+GHhbBr18/iQwjL5Z9BqfA==", + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true, - "dependencies": { - "camelcase": "^3.0.0", - "object.assign": "^4.1.0" + "engines": { + "node": ">=10" } } } diff --git a/src/main/webapp/package.json b/src/main/webapp/package.json index 574e025c22..0278dc49ce 100644 --- a/src/main/webapp/package.json +++ b/src/main/webapp/package.json @@ -30,13 +30,13 @@ "grunt-contrib-watch": "*", "grunt-riot": "*", "grunt-sync": "*", - "gulp": "^4.0.2", + "gulp": "^5.0.0", "gulp-clean-css": "^4.3.0", "gulp-concat": "^2.6.1", "gulp-less": "^5.0.0", "gulp-rename": "^2.0.0", "gulp-sass": "^5.1.0", - "gulp-sourcemaps": "^3.0.0", + "gulp-sourcemaps": "^2.6.5", "gulp-uglify-es": "^3.0.0", "less-plugin-autoprefix": "*", "postcss": "^8.4.12", diff --git a/src/main/webapp/resources/compositesPG/formInputDropdownBadges.xhtml b/src/main/webapp/resources/compositesPG/formInputDropdownBadges.xhtml new file mode 100644 index 0000000000..39c2c2fd96 --- /dev/null +++ b/src/main/webapp/resources/compositesPG/formInputDropdownBadges.xhtml @@ -0,0 +1,53 @@ + + + + + + + +
+ + + + + + + + + + + + + +
+
+
diff --git a/src/main/webapp/resources/compositesPG/formInputGeonamesAjax.xhtml b/src/main/webapp/resources/compositesPG/formInputGeonamesAjax.xhtml index 060a1559f9..b9cb365e97 100644 --- a/src/main/webapp/resources/compositesPG/formInputGeonamesAjax.xhtml +++ b/src/main/webapp/resources/compositesPG/formInputGeonamesAjax.xhtml @@ -55,7 +55,7 @@ + styleClass="#{cc.attrs.classRight} d-flex flex-column gap-1"> @@ -117,9 +120,10 @@ id="geonamesSearchBox" tabindex="-1" role="dialog" - aria-labelledby="geonamesSearchBox" + aria-labelledby="geonamesSearchBoxTitle" aria-hidden="true">