From c2ead8ac02672ab9af997272e211b0f0992288a1 Mon Sep 17 00:00:00 2001 From: JvD_Ericsson Date: Fri, 22 Jul 2022 10:25:52 +0100 Subject: [PATCH] Service import - Import unknown node types Issue-ID: SDC-4118 Signed-off-by: JvD_Ericsson Change-Id: Id620eef55ffb6849006e8a7bc063709150628e76 --- .../openecomp/sdc/be/components/csar/CsarInfo.java | 16 ++ .../sdc/be/components/csar/ServiceCsarInfo.java | 198 +++++++++++++++++++-- .../be/components/impl/ResourceImportManager.java | 8 +- .../impl/ServiceImportBusinessLogic.java | 49 ++++- .../be/components/ResourceImportManagerTest.java | 60 +++++++ .../impl/ServiceImportBusinessLogicTest.java | 3 + .../csars/service-Etsiwithchild-csar.csar | Bin 0 -> 50857 bytes .../openecomp/sdc/be/model/NodeTypeDefinition.java | 14 ++ 8 files changed, 322 insertions(+), 26 deletions(-) create mode 100644 catalog-be/src/test/resources/csars/service-Etsiwithchild-csar.csar create mode 100644 catalog-model/src/main/java/org/openecomp/sdc/be/model/NodeTypeDefinition.java diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/csar/CsarInfo.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/csar/CsarInfo.java index 49b7bb2f86..0bc6224273 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/csar/CsarInfo.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/csar/CsarInfo.java @@ -26,6 +26,7 @@ import static org.openecomp.sdc.be.components.impl.ImportUtils.findToscaElement; import com.google.common.annotations.VisibleForTesting; import fj.data.Either; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -35,6 +36,7 @@ import java.util.Optional; import java.util.PriorityQueue; import java.util.Queue; import java.util.Set; +import java.util.stream.Stream; import lombok.Getter; import lombok.Setter; import org.apache.commons.collections.MapUtils; @@ -194,6 +196,20 @@ public abstract class CsarInfo { return Collections.emptyMap(); } + @SuppressWarnings("unchecked") + protected Map getTypesFromTemplate(final Map mappedToscaTemplate, TypeUtils.ToscaTagNamesEnum type, Collection names) { + Map allTypes = getTypesFromTemplate(mappedToscaTemplate, type); + + final Map typesToReturn = new HashMap<>(); + final Stream> requestedTypes = allTypes.entrySet().stream().filter(entry -> names.contains(entry.getKey())); + + requestedTypes.forEach(requestedType -> { + typesToReturn.put(requestedType.getKey(), requestedType.getValue()); + }); + + return typesToReturn; + } + protected Set findNodeTypesUsedInNodeTemplates(final Map> nodeTemplates) { final Set nodeTypes = new HashSet<>(); for (final Map nodeTemplate : nodeTemplates.values()) { diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/csar/ServiceCsarInfo.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/csar/ServiceCsarInfo.java index ca3c92bcbd..8dfe106713 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/csar/ServiceCsarInfo.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/csar/ServiceCsarInfo.java @@ -21,7 +21,10 @@ package org.openecomp.sdc.be.components.csar; +import static org.openecomp.sdc.be.components.impl.ImportUtils.Constants.DEFAULT_ICON; import static org.openecomp.sdc.be.components.impl.ImportUtils.findToscaElement; + +import fj.data.Either; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; @@ -31,28 +34,35 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; +import org.openecomp.sdc.be.components.impl.ImportUtils; import org.openecomp.sdc.be.components.impl.ImportUtils.ResultStatusEnum; import org.openecomp.sdc.be.components.impl.ImportUtils.ToscaElementTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.NodeTypeDefinition; import org.openecomp.sdc.be.model.NodeTypeInfo; +import org.openecomp.sdc.be.model.NodeTypeMetadata; import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.category.CategoryDefinition; +import org.openecomp.sdc.be.model.category.SubCategoryDefinition; import org.openecomp.sdc.be.utils.TypeUtils; import org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum; import org.openecomp.sdc.common.log.wrappers.Logger; import org.yaml.snakeyaml.Yaml; -import fj.data.Either; /** * Provides access to the contents of a Service CSAR */ public class ServiceCsarInfo extends CsarInfo { - private Map> mainTemplateImports; private static final Logger log = Logger.getLogger(ServiceCsarInfo.class); + private final Map> mainTemplateImports; + private List nodeTypeDefinitions; public ServiceCsarInfo(final User modifier, final String csarUUID, final Map csar, final String vfResourceName, - final String mainTemplateName, final String mainTemplateContent, final boolean isUpdate) { + final String mainTemplateName, final String mainTemplateContent, final boolean isUpdate) { super(modifier, csarUUID, csar, vfResourceName, mainTemplateName, mainTemplateContent, isUpdate); final Path mainTemplateDir = Paths.get(getMainTemplateName().substring(0, getMainTemplateName().lastIndexOf('/') + 1)); @@ -60,12 +70,12 @@ public class ServiceCsarInfo extends CsarInfo { filesHandled.add(Paths.get(mainTemplateName)); this.mainTemplateImports = getTemplateImports(csar, new Yaml().load(mainTemplateContent), mainTemplateDir, filesHandled); } - + private Map> getTemplateImports(final Map csar, Map mappedToscaMainTemplate, - final Path fileParentDir, final Collection filesHandled) { + final Path fileParentDir, final Collection filesHandled) { final Map> templateImports = new HashMap<>(); - final List importFilePaths = getTempateImportFilePaths(mappedToscaMainTemplate, fileParentDir); + final List importFilePaths = getTemplateImportFilePaths(mappedToscaMainTemplate, fileParentDir); importFilePaths.stream().filter(path -> !filesHandled.contains(path)).forEach( importFilePath -> { @@ -74,9 +84,7 @@ public class ServiceCsarInfo extends CsarInfo { filesHandled.add(importFilePath); Map mappedImportFile = new Yaml().load(new String(csar.get(importFilePath.toString()))); templateImports.put(importFilePath.toString(), mappedImportFile); - templateImports.putAll(getTemplateImports(csar, mappedImportFile, importFilePath.getParent(), filesHandled)); - } else { log.info("Import {} cannot be found in CSAR", importFilePath.toString()); } @@ -84,18 +92,18 @@ public class ServiceCsarInfo extends CsarInfo { return templateImports; } - + @SuppressWarnings({"unchecked", "rawtypes"}) - private List getTempateImportFilePaths(final Map mappedToscaTemplate, final Path fileParentDir) { + private List getTemplateImportFilePaths(final Map mappedToscaTemplate, final Path fileParentDir) { final Either importsEither = - findToscaElement(mappedToscaTemplate, ToscaTagNamesEnum.IMPORTS, ToscaElementTypeEnum.ALL); + findToscaElement(mappedToscaTemplate, ToscaTagNamesEnum.IMPORTS, ToscaElementTypeEnum.ALL); if (importsEither.isLeft()) { final List importsList = (List) importsEither.left().value(); if (CollectionUtils.isNotEmpty(importsList)) { if (importsList.get(0) instanceof String) { List importPaths = new ArrayList<>(); - importsList.stream().forEach(importPath -> importPaths.add(Paths.get((String)importPath))); + importsList.stream().forEach(importPath -> importPaths.add(Paths.get((String) importPath))); return importPaths; } else if (importsList.get(0) instanceof Map) { return getTemplateImportFilePathsMultiLineGrammar(importsList, fileParentDir); @@ -110,11 +118,11 @@ public class ServiceCsarInfo extends CsarInfo { private List getTemplateImportFilePathsMultiLineGrammar(final List> importsList, final Path fileParentDir) { final List importFiles = new ArrayList<>(); - for (Map importFileMultiLineGrammar : (List>) importsList) { + for (Map importFileMultiLineGrammar : importsList) { if (MapUtils.isNotEmpty(importFileMultiLineGrammar)) { if (importFileMultiLineGrammar.values().iterator().next() instanceof String) { Path relativePath = Paths.get((String) importFileMultiLineGrammar.get("file")); - Path absolutePath = fileParentDir.resolve(relativePath).normalize(); + Path absolutePath = fileParentDir == null ? relativePath : fileParentDir.resolve(relativePath).normalize(); importFiles.add(absolutePath); } else if (importFileMultiLineGrammar.values().iterator().next() instanceof Map) { importFileMultiLineGrammar.values().forEach(value -> { @@ -137,9 +145,169 @@ public class ServiceCsarInfo extends CsarInfo { public Map getDataTypes() { final Map definitions = new HashMap<>(); mainTemplateImports.entrySet().stream() - .forEach(entry -> definitions.putAll(getTypesFromTemplate(entry.getValue(), TypeUtils.ToscaTagNamesEnum.DATA_TYPES))); + .forEach(entry -> definitions.putAll(getTypesFromTemplate(entry.getValue(), TypeUtils.ToscaTagNamesEnum.DATA_TYPES))); definitions.putAll(getTypesFromTemplate(getMappedToscaMainTemplate(), TypeUtils.ToscaTagNamesEnum.DATA_TYPES)); return definitions; } + public List getNodeTypesUsed() { + if (nodeTypeDefinitions == null) { + nodeTypeDefinitions = new ArrayList<>(); + final Set nodeTypesUsed = getNodeTypesUsedInToscaTemplate(getMappedToscaMainTemplate()); + nodeTypeDefinitions.addAll(getNodeTypeDefinitions(nodeTypesUsed)); + } + nodeTypeDefinitions = sortNodeTypesByDependencyOrder(nodeTypeDefinitions); + return nodeTypeDefinitions; + } + + private List sortNodeTypesByDependencyOrder(final List nodeTypes) { + final List sortedNodeTypeDefinitions = new ArrayList<>(); + final Map nodeTypeDefinitionsMap = new HashMap<>(); + + nodeTypes.forEach(nodeType -> { + int highestDependencyIndex = -1; + for (final String dependencyName : getDependencyTypes(nodeType, nodeTypes)) { + final NodeTypeDefinition dependency = nodeTypeDefinitionsMap.get(dependencyName); + final int indexOfDependency = sortedNodeTypeDefinitions.lastIndexOf(dependency); + highestDependencyIndex = indexOfDependency > highestDependencyIndex ? indexOfDependency : highestDependencyIndex; + } + sortedNodeTypeDefinitions.add(highestDependencyIndex + 1, nodeType); + nodeTypeDefinitionsMap.put(nodeType.getNodeTypeMetadata().getToscaName(), nodeType); + }); + return sortedNodeTypeDefinitions; + } + + private Collection getDependencyTypes(final NodeTypeDefinition nodeType, final List nodeTypes) { + final Set dependencies = new HashSet<>(); + Either derivedFromTypeEither = findToscaElement((Map) nodeType.getMappedNodeType().getValue(), + TypeUtils.ToscaTagNamesEnum.DERIVED_FROM, ToscaElementTypeEnum.STRING); + if (derivedFromTypeEither.isLeft() && derivedFromTypeEither.left().value() != null) { + final String derivedFrom = (String) derivedFromTypeEither.left().value(); + dependencies.add(derivedFrom); + nodeTypes.stream().filter(derivedFromCandidate -> derivedFrom.contentEquals(derivedFromCandidate.getNodeTypeMetadata().getToscaName())) + .forEach(derivedFromNodeType -> dependencies.addAll(getDependencyTypes(derivedFromNodeType, nodeTypes))); + } + return dependencies; + } + + private Set getNodeTypeDefinitions(final Set nodeTypesToGet) { + final Set nodeTypesToReturn = new HashSet<>(); + final Set foundNodeTypes = getTypes(nodeTypesToGet); + nodeTypesToReturn.addAll(foundNodeTypes); + final Set recursiveNodeTypesToGet = new HashSet<>(); + foundNodeTypes.stream().forEach(nodeTypeDef -> { + Either derivedFromTypeEither = + findToscaElement((Map) nodeTypeDef.getMappedNodeType().getValue(), TypeUtils.ToscaTagNamesEnum.DERIVED_FROM, + ToscaElementTypeEnum.STRING); + if (derivedFromTypeEither.isLeft()) { + recursiveNodeTypesToGet.add((String)derivedFromTypeEither.left().value()); + } + }); + recursiveNodeTypesToGet.removeAll(nodeTypesToGet); + if (CollectionUtils.isNotEmpty(recursiveNodeTypesToGet)) { + nodeTypesToReturn.addAll(getNodeTypeDefinitions(recursiveNodeTypesToGet)); + } + return nodeTypesToReturn; + } + + + private Set getTypes(final Set nodeTypes) { + Set nodeTypeDefinitionsLocal = new HashSet<>(); + mainTemplateImports.entrySet().forEach(entry -> { + final Map types = getTypesFromTemplate(entry.getValue(), TypeUtils.ToscaTagNamesEnum.NODE_TYPES, nodeTypes); + if (MapUtils.isNotEmpty(types)) { + types.entrySet().stream().forEach(typesEntry -> { + final NodeTypeMetadata metadata = + getMetaDataFromTemplate(entry.getValue(), typesEntry.getKey()); + nodeTypeDefinitionsLocal.add(new NodeTypeDefinition(typesEntry, metadata)); + }); + } + }); + return nodeTypeDefinitionsLocal; + } + + @SuppressWarnings("unchecked") + private Set getNodeTypesUsedInToscaTemplate(Map mappedToscaTemplate) { + final Either nodeTemplatesEither = findToscaElement(mappedToscaTemplate, + TypeUtils.ToscaTagNamesEnum.NODE_TEMPLATES, ToscaElementTypeEnum.MAP); + final Set nodeTypesUsedInNodeTemplates = new HashSet<>(); + if (nodeTemplatesEither.isLeft()) { + final Map> nodeTemplates = + (Map>) nodeTemplatesEither.left().value(); + nodeTypesUsedInNodeTemplates.addAll(findNodeTypesUsedInNodeTemplates(nodeTemplates)); + } + return nodeTypesUsedInNodeTemplates; + } + + private NodeTypeMetadata getMetaDataFromTemplate(Map mappedResourceTemplate, String nodeTemplateType) { + NodeTypeMetadata nodeTypeMetadata = new NodeTypeMetadata(); + Either, ImportUtils.ResultStatusEnum> metadataEither = ImportUtils.findFirstToscaMapElement(mappedResourceTemplate, TypeUtils.ToscaTagNamesEnum.METADATA); + if (metadataEither.isLeft() && metadataEither.left().value().get("type").equals(ResourceTypeEnum.VFC.getValue())) { + Map metadata = metadataEither.left().value(); + createMetadataFromTemplate(nodeTypeMetadata, metadata, nodeTemplateType); + } else { + createDefaultMetadata(nodeTypeMetadata, nodeTemplateType); + } + return nodeTypeMetadata; + } + + private void createMetadataFromTemplate(NodeTypeMetadata nodeTypeMetadata, Map metadata, String nodeTemplateType) { + nodeTypeMetadata.setToscaName(nodeTemplateType); + nodeTypeMetadata.setContactId(getModifier().getUserId()); + nodeTypeMetadata.setDescription((String) metadata.get("description")); + List tags = new ArrayList<>(); + tags.add((String) metadata.get("name")); + nodeTypeMetadata.setTags(tags); + SubCategoryDefinition subCategory = new SubCategoryDefinition(); + subCategory.setName((String) metadata.get("subcategory")); + CategoryDefinition category = new CategoryDefinition(); + category.setName((String) metadata.get("category")); + category.setNormalizedName(((String) metadata.get("category")).toLowerCase()); + category.setIcons(List.of(DEFAULT_ICON)); + category.setNormalizedName(((String) metadata.get("category")).toLowerCase()); + category.addSubCategory(subCategory); + List categories = new ArrayList<>(); + categories.add(category); + nodeTypeMetadata.setCategories(categories); + nodeTypeMetadata.setName((String) metadata.get("name")); + nodeTypeMetadata.setIcon("defaulticon"); + nodeTypeMetadata.setResourceVendorModelNumber((String) metadata.get("resourceVendorModelNumber")); + nodeTypeMetadata.setResourceType((String) metadata.get("type")); + nodeTypeMetadata.setVendorName((String) metadata.get("resourceVendor")); + nodeTypeMetadata.setVendorRelease((String) metadata.get("resourceVendorRelease")); + nodeTypeMetadata.setModel((String) metadata.get("model")); + nodeTypeMetadata.setNormative(false); + } + + private void createDefaultMetadata(NodeTypeMetadata nodeTypeMetadata, String nodeTemplateType) { + nodeTypeMetadata.setToscaName(nodeTemplateType); + nodeTypeMetadata.setContactId(getModifier().getUserId()); + nodeTypeMetadata.setDescription("A vfc of type " + nodeTemplateType); + Either, ResultStatusEnum> mainMetadataEither = ImportUtils.findFirstToscaMapElement(getMappedToscaMainTemplate(), + ToscaTagNamesEnum.METADATA); + Map mainMetadata = mainMetadataEither.left().value(); + nodeTypeMetadata.setModel((String) mainMetadata.get("model")); + SubCategoryDefinition subCategory = new SubCategoryDefinition(); + subCategory.setName("Network Elements"); + CategoryDefinition category = new CategoryDefinition(); + category.setName("Generic"); + category.setNormalizedName("generic"); + category.setIcons(List.of(DEFAULT_ICON)); + category.setNormalizedName("generic"); + category.addSubCategory(subCategory); + List categories = new ArrayList<>(); + categories.add(category); + nodeTypeMetadata.setCategories(categories); + String[] nodeTemplateName = nodeTemplateType.split("\\."); + String name = nodeTemplateName[nodeTemplateName.length - 1]; + nodeTypeMetadata.setName(name); + List tags = new ArrayList<>(); + tags.add(name); + nodeTypeMetadata.setTags(tags); + nodeTypeMetadata.setIcon("defaulticon"); + nodeTypeMetadata.setVendorName((String) mainMetadata.get("name")); + nodeTypeMetadata.setVendorRelease("1"); + nodeTypeMetadata.setNormative(false); + } + } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceImportManager.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceImportManager.java index d02a84f491..a20c30624e 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceImportManager.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceImportManager.java @@ -169,11 +169,15 @@ public class ResourceImportManager { log.error(EcompLoggerErrorCode.BUSINESS_PROCESS_ERROR, ResourceImportManager.class.getName(), "Could not parse node types YAML", e); throw new ByActionStatusComponentException(ActionStatus.INVALID_NODE_TYPES_YAML); } - if (!nodeTypesYamlMap.containsKey(ToscaTagNamesEnum.NODE_TYPES.getElementName())) { return; } final Map nodeTypesMap = (Map) nodeTypesYamlMap.get(ToscaTagNamesEnum.NODE_TYPES.getElementName()); + importAllNormativeResource(nodeTypesMap, nodeTypesMetadataList,user, createNewVersion,needLock); + } + + public void importAllNormativeResource(final Map nodeTypesMap, final NodeTypesMetadataList nodeTypesMetadataList, + final User user, final boolean createNewVersion, final boolean needLock) { try { nodeTypesMetadataList.getNodeMetadataList().forEach(nodeTypeMetadata -> { final String nodeTypeToscaName = nodeTypeMetadata.getToscaName(); @@ -358,7 +362,6 @@ public class ResourceImportManager { final Either existingResource = getExistingResource(resource); final Map toscaJsonAll = (Map) ymlObj; Map toscaJson = toscaJsonAll; - // Checks if exist and builds the node_types map if (toscaJsonAll.containsKey(ToscaTagNamesEnum.NODE_TYPES.getElementName()) && resource.getResourceType() != ResourceTypeEnum.CVFC) { toscaJson = new HashMap<>(); toscaJson.put(ToscaTagNamesEnum.NODE_TYPES.getElementName(), toscaJsonAll.get(ToscaTagNamesEnum.NODE_TYPES.getElementName())); @@ -372,7 +375,6 @@ public class ResourceImportManager { resource.setDataTypes(extractDataTypeFromJson(resourceBusinessLogic, toscaAttributes, resource.getModel())); } } - // Derived From final Resource parentResource = setDerivedFrom(toscaJson, resource); if (StringUtils.isEmpty(resource.getToscaResourceName())) { setToscaResourceName(toscaJson, resource); diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceImportBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceImportBusinessLogic.java index e4129a24eb..7b328f755d 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceImportBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceImportBusinessLogic.java @@ -37,8 +37,6 @@ import java.util.Map.Entry; import java.util.Optional; import java.util.Set; import java.util.regex.Pattern; -import java.util.stream.Collectors; -import java.util.stream.Stream; import lombok.Getter; import lombok.Setter; import org.apache.commons.collections.CollectionUtils; @@ -84,7 +82,6 @@ import org.openecomp.sdc.be.model.CapabilityDefinition; import org.openecomp.sdc.be.model.CapabilityRequirementRelationship; import org.openecomp.sdc.be.model.Component; import org.openecomp.sdc.be.model.ComponentInstance; -import org.openecomp.sdc.be.model.ComponentInstanceAttribute; import org.openecomp.sdc.be.model.ComponentInstanceInput; import org.openecomp.sdc.be.model.ComponentInstanceProperty; import org.openecomp.sdc.be.model.ComponentParametersView; @@ -94,7 +91,10 @@ import org.openecomp.sdc.be.model.GroupDefinition; import org.openecomp.sdc.be.model.InputDefinition; import org.openecomp.sdc.be.model.LifeCycleTransitionEnum; import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.NodeTypeDefinition; import org.openecomp.sdc.be.model.NodeTypeInfo; +import org.openecomp.sdc.be.model.NodeTypeMetadata; +import org.openecomp.sdc.be.model.NodeTypesMetadataList; import org.openecomp.sdc.be.model.Operation; import org.openecomp.sdc.be.model.OutputDefinition; import org.openecomp.sdc.be.model.ParsedToscaYamlInfo; @@ -168,6 +168,7 @@ public class ServiceImportBusinessLogic { private final ComponentNodeFilterBusinessLogic componentNodeFilterBusinessLogic; private final GroupBusinessLogic groupBusinessLogic; private final PolicyBusinessLogic policyBusinessLogic; + private final ResourceImportManager resourceImportManager; private final JanusGraphDao janusGraphDao; private final ArtifactsBusinessLogic artifactsBusinessLogic; private final IGraphLockOperation graphLockOperation; @@ -189,7 +190,9 @@ public class ServiceImportBusinessLogic { final ComponentNodeFilterBusinessLogic componentNodeFilterBusinessLogic, final PolicyBusinessLogic policyBusinessLogic, final JanusGraphDao janusGraphDao, final IGraphLockOperation graphLockOperation, final ToscaFunctionService toscaFunctionService, - final PropertyOperation propertyOperation, final DataTypeBusinessLogic dataTypeBusinessLogic) { + final PropertyOperation propertyOperation, final DataTypeBusinessLogic dataTypeBusinessLogic, + ResourceImportManager resourceImportManager) { + this.resourceImportManager = resourceImportManager; this.componentInstanceBusinessLogic = componentInstanceBusinessLogic; this.uiComponentDataConverter = uiComponentDataConverter; this.componentsUtils = componentsUtils; @@ -211,7 +214,7 @@ public class ServiceImportBusinessLogic { this.propertyOperation = propertyOperation; this.dataTypeBusinessLogic = dataTypeBusinessLogic; } - + @Autowired public void setApplicationDataTypeCache(ApplicationDataTypeCache applicationDataTypeCache) { this.applicationDataTypeCache = applicationDataTypeCache; @@ -249,12 +252,15 @@ public class ServiceImportBusinessLogic { log.trace("************* created successfully from YAML, resource TOSCA "); try { ServiceCsarInfo csarInfo = csarBusinessLogic.getCsarInfo(service, null, user, csarUIPayload, csarUUID); - + final Map dataTypesToCreate = getDatatypesToCreate(service.getModel(), csarInfo); if (MapUtils.isNotEmpty(dataTypesToCreate)) { dataTypeBusinessLogic.createDataTypeFromYaml(new Yaml().dump(dataTypesToCreate), service.getModel(), true); } - + final List nodeTypesToCreate = getNodeTypesToCreate(service.getModel(), csarInfo); + if (CollectionUtils.isNotEmpty(nodeTypesToCreate)) { + createNodeTypes(nodeTypesToCreate, csarInfo); + } Map nodeTypesInfo = csarInfo.extractTypesInfo(); Either>>, ResponseFormat> findNodeTypesArtifactsToHandleRes = serviceImportParseLogic .findNodeTypesArtifactsToHandle(nodeTypesInfo, csarInfo, service); @@ -272,7 +278,7 @@ public class ServiceImportBusinessLogic { throw new ComponentException(ActionStatus.GENERAL_ERROR); } } - + private Map getDatatypesToCreate(final String model, final CsarInfo csarInfo) { final Map dataTypesToCreate = new HashMap<>(); @@ -286,6 +292,33 @@ public class ServiceImportBusinessLogic { return dataTypesToCreate; } + private void createNodeTypes(List nodeTypesToCreate, ServiceCsarInfo csarInfo) { + NodeTypesMetadataList nodeTypesMetadataList = new NodeTypesMetadataList(); + List nodeTypeMetadataList = new ArrayList<>(); + + final Map allTypesToCreate = new HashMap<>(); + nodeTypesToCreate.stream().forEach(nodeType -> { + allTypesToCreate.put(nodeType.getMappedNodeType().getKey(), nodeType.getMappedNodeType().getValue()); + nodeTypeMetadataList.add(nodeType.getNodeTypeMetadata()); + }); + + nodeTypesMetadataList.setNodeMetadataList(nodeTypeMetadataList); + resourceImportManager.importAllNormativeResource(allTypesToCreate, nodeTypesMetadataList, csarInfo.getModifier(), true, false); + } + + private List getNodeTypesToCreate(final String model, final ServiceCsarInfo csarInfo) { + List namesOfNodeTypesToCreate = new ArrayList<>(); + + for (final NodeTypeDefinition nodeTypeDefinition : csarInfo.getNodeTypesUsed()) { + Either result = toscaOperationFacade + .getLatestByToscaResourceName(nodeTypeDefinition.getMappedNodeType().getKey(), model); + if (result.isRight() && result.right().value().equals(StorageOperationStatus.NOT_FOUND)) { + namesOfNodeTypesToCreate.add(nodeTypeDefinition); + } + } + return namesOfNodeTypesToCreate; + } + protected Service createServiceFromYaml(Service service, String topologyTemplateYaml, String yamlName, Map nodeTypesInfo, CsarInfo csarInfo, Map>> nodeTypesArtifactsToCreate, diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/components/ResourceImportManagerTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/components/ResourceImportManagerTest.java index 32d174f194..04a87e1db4 100644 --- a/catalog-be/src/test/java/org/openecomp/sdc/be/components/ResourceImportManagerTest.java +++ b/catalog-be/src/test/java/org/openecomp/sdc/be/components/ResourceImportManagerTest.java @@ -29,10 +29,13 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyMap; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.contains; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.anyBoolean; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -40,13 +43,17 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import fj.data.Either; +import java.io.File; import java.io.IOException; +import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; +import java.util.Set; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.tuple.ImmutablePair; @@ -55,6 +62,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.stubbing.Answer; import org.openecomp.sdc.be.auditing.impl.AuditingManager; +import org.openecomp.sdc.be.components.csar.ServiceCsarInfo; import org.openecomp.sdc.be.components.impl.ImportUtils; import org.openecomp.sdc.be.components.impl.ImportUtilsTest; import org.openecomp.sdc.be.components.impl.InterfaceDefinitionHandler; @@ -80,6 +88,7 @@ import org.openecomp.sdc.be.impl.ComponentsUtils; import org.openecomp.sdc.be.model.CapabilityDefinition; import org.openecomp.sdc.be.model.Component; import org.openecomp.sdc.be.model.InterfaceDefinition; +import org.openecomp.sdc.be.model.NodeTypeDefinition; import org.openecomp.sdc.be.model.NodeTypeMetadata; import org.openecomp.sdc.be.model.NodeTypesMetadataList; import org.openecomp.sdc.be.model.PropertyConstraint; @@ -98,6 +107,8 @@ import org.openecomp.sdc.be.utils.TypeUtils; import org.openecomp.sdc.common.api.ConfigurationSource; import org.openecomp.sdc.common.impl.ExternalConfiguration; import org.openecomp.sdc.common.impl.FSConfigurationSource; +import org.openecomp.sdc.common.zip.ZipUtils; +import org.openecomp.sdc.common.zip.exception.ZipException; import org.openecomp.sdc.exception.PolicyException; import org.openecomp.sdc.exception.ResponseFormat; @@ -463,6 +474,30 @@ class ResourceImportManagerTest { assertEquals(ActionStatus.COMPONENT_WITH_VENDOR_RELEASE_ALREADY_EXISTS, actualException.getActionStatus()); } + @Test + void getAllResourcesYamlAndNodeTypesMetadataListTest() { + NodeTypesMetadataList nodeTypesMetadataList = new NodeTypesMetadataList(); + List nodeTypeMetadataList = new ArrayList<>(); + Map allTypesToCreate = new HashMap<>(); + ServiceCsarInfo csarInfo= getCsarInfo(); + List nodeTypesToCreate = csarInfo.getNodeTypesUsed(); + nodeTypesToCreate.stream().forEach(nodeType -> { + allTypesToCreate.put(nodeType.getMappedNodeType().getKey(), nodeType.getMappedNodeType().getValue()); + nodeTypeMetadataList.add(nodeType.getNodeTypeMetadata()); + }); + nodeTypesMetadataList.setNodeMetadataList(nodeTypeMetadataList); + + when(toscaOperationFacade.getLatestByName(any(), any())).thenReturn(Either.left(null)).thenReturn(Either.left(null)); + when(toscaOperationFacade.getLatestByToscaResourceName("org.openecomp.resource.VFC-root", "ETSI SOL001 v2.5.1")) + .thenReturn(Either.left(null)); + when(resourceBusinessLogic + .createOrUpdateResourceByImport(any(Resource.class), any(User.class), eq(true), eq(true), eq(false), eq(null), eq(null), eq(false))) + .thenReturn(new ImmutablePair<>(new Resource(), ActionStatus.OK)).thenReturn(new ImmutablePair<>(new Resource(), ActionStatus.OK)); + + importManager.importAllNormativeResource(allTypesToCreate, nodeTypesMetadataList, user, false, false); + verify(janusGraphDao).commit(); + } + private void setResourceBusinessLogicMock() { when(resourceBusinessLogic.getUserAdmin()).thenReturn(userAdmin); when(resourceBusinessLogic.createOrUpdateResourceByImport(any(Resource.class), any(User.class), anyBoolean(), anyBoolean(), anyBoolean(), @@ -718,4 +753,29 @@ class ResourceImportManagerTest { assertEquals(ImportUtils.Constants.VENDOR_RELEASE, resource.getVendorRelease()); } + protected ServiceCsarInfo getCsarInfo() { + String csarUuid = "0010"; + User user = new User("jh0003"); + + try { + File csarFile = new File( + ResourceImportManagerTest.class.getClassLoader().getResource("csars/service-Etsiwithchild-csar.csar").toURI()); + Map csar = ZipUtils.readZip(csarFile, false); + + String vfReousrceName = "resouceName"; + String mainTemplateName = "Definitions/service-Etsiwithchild-template.yml"; + + Optional keyOp = csar.keySet().stream().filter(k -> k.endsWith("service-Etsiwithchild-template.yml")).findAny(); + byte[] mainTemplateService = keyOp.map(csar::get).orElse(null); + assertNotNull(mainTemplateService); + final String mainTemplateContent = new String(mainTemplateService); + + return new ServiceCsarInfo(user, csarUuid, csar, vfReousrceName, mainTemplateName, mainTemplateContent, false); + } catch (URISyntaxException | ZipException e) { + fail(e); + } + return null; + } + + } diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ServiceImportBusinessLogicTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ServiceImportBusinessLogicTest.java index d40bac1585..3671ba7828 100644 --- a/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ServiceImportBusinessLogicTest.java +++ b/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ServiceImportBusinessLogicTest.java @@ -204,6 +204,9 @@ class ServiceImportBusinessLogicTest extends ServiceImportBussinessLogicBaseTest when(applicationDataTypeCache.get(any(), contains("tosca.datatypes.test_"))).thenReturn(Either.right(JanusGraphOperationStatus.NOT_FOUND)); when(applicationDataTypeCache.get(any(), matches("^((?!tosca.datatypes.test_).)*$"))).thenReturn(Either.left(new DataTypeDefinition())); + when(toscaOperationFacade.getLatestByToscaResourceName(contains("org.openecomp.resource"), isNull())).thenReturn(Either.left(null)); + when(toscaOperationFacade.getLatestByToscaResourceName(contains("tosca.nodes."), isNull())).thenReturn(Either.left(null)); + Service result = sIBL.createService(oldService, AuditingActionEnum.CREATE_RESOURCE, user, payload, payloadName); assertNotNull(result); assertNotNull(result.getComponentInstances()); diff --git a/catalog-be/src/test/resources/csars/service-Etsiwithchild-csar.csar b/catalog-be/src/test/resources/csars/service-Etsiwithchild-csar.csar new file mode 100644 index 0000000000000000000000000000000000000000..bd6e7a285893a7203a602c22554cd4c1f3c2f91b GIT binary patch literal 50857 zcmZ^oGmtP0kZs4dZQC>7*tTukwr$(CZQHhObN{NBybZRK?hg7!H@J0LUJ4il1pop9 z0)WBbOBvw*D~kVS0Y_&GQv)MsCwdWOB?&!w0U;>?F%fzbXD16c3ukj9a|>%@I!_CG z04)BKKKcJs3h6(o|9xZRWZ)RQZWKockd%K=X0z35v$ga88t;FL!)B|^HP@E~`9@An z@g@0k%623ZL4G-axVSh#(Lov1{vXEhUv))PQ%P4zR7gWeNepC9jYh?$u#p4T<14Xd zTo;t8Pf+%H5(AC9G({rd(QGQQT=<}_5;1mAjg2rm*qb8xtrPW% z9J{d+cb{=?M*SFsiV-slmoj{8)!MoAwZd}LN*lk`zbrv~tjaX)C|sWMw3Fu5Z7qFC zB``t1V{zIlAf`ozr@$C?r{+~{QZ9GXdnG%45<`8!cdspdn8Ea8*6E&*lwDLA)OBsM z^^1XEb0?ro>;^oeH~9{70kF{;ZS0 zF)RdO;Y4OS`>wJX)TH3%(P@vcec1cHDeNDrEB8oFXM_X(d#uVf>`N^_v(%S;;noBT zY)yrUUI$Xp)p+^9mi`CIPk@5fwRmFkXR_J0?$uo!M;4>mnu|BMUVL-C+Na@N{M|YG z4%;5n2q+QZ_5JHPU}zA^2}3^ctNwrs<>H-Ch#sil=nH0CeA^myy*5t2_M35T*d7C9 zUY-?*-We8dg!!An8M@-R)bU94p=$TzUdz#81!2P;1Fs}KY^>W*q6|1u02JiVsIm%{ z57c>&>2{Y(y?jN!6>*=+qdrM@r%94SC{|9^y%pu4EC4s-KKERwAcRz$)At;dE?H|& zrIZ)U6@Z8ywD|}v<1T1jC441*uM>$V2y%ut`gH3x_IS{`Y^!rVX&<%=bzrR#tan{6 z6ev`l6XwBi3@Tw1aducZ7DZI5PLtH(=Whd)G}4uEleAmX@)p$h_-;rjQZtn$6EUUq z*jVdh{)2-W^AE9pFp}oe?Q6B~Er<->B&|NJu8CBi6U{m5tN66LikYr&g}?ibQMpbC zTLRw#+1yfXu+>4x3wwwr_a`>W50%vYH zk-%0q3g~oYwMbyjjiR%WvKU78t5~>?=*ng*k0NZ!*-G7zFK8!X!FM~5!Vh@>gyt80 zuVZzccZiR|_>UO@36M7ZE^GU!K0r(c#$H!B;fLBGyXBC}a!&+rs8%MgKmHA?)s?Af zPfMYDq)9`VrK_c7;C5KgWr#FyYshxnS!J;|=c2${fLYx{g30!6zw?@Ff1G$Jbz70~ zCYS}%DIkoOP22?_wF`Hiu1FZ^Ehh7{k={6Jjj)D=`9S-I-T z&G_?lTf5j-;li>^RR${1m!+1g-V+xkulPaO0|P`WIMq;;)OsU7z+9Fk#W3s0o*Hw! ze+Y#SRn9z#(<)E(xB*`)7Mfp z0*Db5qLj05SJ~jBcAoYUW8gTl%p33^3{;?FFdozHU?aq^|0ROFT#gC$>B-O>e1NP) z>ir5~C2h9a6QSjoIardzqb&q#vHs3ZsWgU!9^aED9a}eE;1b=t)I@4Kn}#u{=lb&U zr?s3OwE=dWad{2jI8!JoQ6+0orD}EBE%(vUKJRcGheg-~bUNcCzMAuwvGMhT02!ii z2onPUex^m?*$wzr^Xj_gDn=)Em^${1@Vu&SG|$BY+I{{?Git=)k~_fXOFJl@mw#h{ z!QEAH^zZqa!NDDe6))RqR7?I8BSpV2tN2*+}aMFNfB&< zXJ$@iJZK$!aJW zl^Qot8~HToV9Vg&`{#fubM!YvZ(CuyxHTvY)s`>iVf0EL#>5MGwmf3=wclhl`~7Pb z6c#*7wJxf0%G?+ia7=75O*N`Yd7OQ_I&-4I@0bqez1t5b=hI|axhm5s)X$VJ@k0oI7Hg%*CPapfg-MAmHi1~nSf#KD@@$7ns6{WE6AzD%$DIAg`|qYm z>9)&zPo`?!=eIFWv-jmw!%Z>?$jdbqnE+S|n2`ca5=I^Zps`U0p=9LU)wXcrSAh!c zW;23T@wV(s%fLVt<$KU)&(zu#tU@zLScR@_^YLk@)Af+@qMZvSm^S-7PwvIc*&JK6fY~ObBvhBM4HdCVlSPi>W5AW69u4?PZu(M@BsFSO<6C}RA>7P z1@-IYCVnsUAqiFC+icc{zO$*&>2$b}DAo%!gm?L$oa;RpBg`7yuLU7=j0IPuJjtG{ z$R=+zkNIYI`!EFz2-9047~qyflvTrJ^O5vR<-g-|NOQ5}gC{6M5sC;73jN2izuW9l zU}(Q9&<#?AM%_=h*&8#=y?vQ``IpdNhNvU=y)wGd9U+dNgA0KUxhCq}yT)2+qg~6i zHG!SfpSviVp5VGCy}%Z1#JBeQ3JJdOj>1w!m~6a*6lF`Pg!d=tRmu}dl?tT{DE480 zzvw@rB90+|7J&nXMQ7%3QZ;!Cg^@VDIAR;LNiJ(hH1U>`%&%TzT^c0V+fWs&4z*h+ z2XK%S=&SrXBH3GLXVJ%kkQM_|F-73JB~#Wed@jN7NyoX&t=28%ialuu5M`O7RU6Xh zHq^JAQH`ewO4j}3i`m&7efcL`CAv-HvFq29_0m1tU7`u13+1#G8#xv;H(_np)ucdN zn_LeYjLrPDY99x1o$iEY))N?F0V3xBA$0)JrfK{KnnweSHh@fD2W4QojHHouHLnrk z2~WK*6os(5EV(7;(K?Vaw?wFCJlv`>MW~6cOrK-+pHIPOSlIDXo#lyegx(5K9SR~5 zzpHo%@1ygFv~Y3`Z_@dp0SGTwkw3s86U?ytm)wXgd2&JZWzXe@nnCvik479FVkLYg zD?6V4rNOb}RKI!E8$FoV>k{cyc&Gb~r_jE_7LM_2}L3yr^Z1j&nj0aWRm8Y2Z!QkY3NDx3U{(r`4W&HfE zV_}2cx6fGF3yJ#u`K0o*HJCPBe%zPciQy|8o;`3>?FhBuPjqG z7|4X_i428;LsgpQJbQkNnkP=x?LxOM#(a8~kT9H&^O5+B_fn38vuUj})ZTY5oT;<1 z$!8`f4Fe0??1`b(3!Ot*dLA_$A2(ch_7n05I3<*h0hLTSSzu4A(%Vx>v#X)%SK>`- zy()#8NnkUre3P8$-d)-&2)PU*)r2y&JQva`o9_<;NyvGyq}kHQ<=-wvccxp;QH+b= z2$oHIgN7ySCA`Yx(A)>pDBTC`O}t@x?5j(03*;QaP((%zv!D;WXFZ-l-ZHKnR$U*e zH`wu!1lCTZmSag?2YfLQrm#r*XdTt#9!Qdc(@l!`Xe{k%3Q1Elc=2pv@anqpXWfXI zA7^Lf!7&t5kJf=7{@)+peZk&sM&c&DyHB|kzfu`CVXaule-uOTFMO0jKYj|Ld$ZFr zdmFo<2?-K=vm3&DBTECzAAV6zGhG+XO@_+=Z1qgW7B=uZ6Wl88Am3SEFsKYxeUjm~rB>VKc*wq|B*QZY*gC{Rtq*$p`7 zL5>g(?in#j_v@kv{qTymipvWm2FI2E^yCHSDK|Ov^-C4#Ks^k3!sGyky%)~6o~85; z4Mw_QRFzRRIF)~cDL7|ViUG6HdN3~QRVfGh82DBs!)$hwG3pmw!`17IYK#n`M>OO0 zG7k8PsUZ&WgzN^D*gS!>=CcN+=KwnKCl#HGEnl9A__X!8(=nA=V3;2gcSxX2&wEPa z=fV7F!;})|)&}nIl5{-oA>8c5SQu%gQ~Mk4jkOE_n||4e3!^QH6i+z*t>-a9{%mSi zv!Mw^A~Fj=91-iH6z3H|5IY)N8)FHe>kgzP-}mb)!;VKjPrrw>ZL?UEXn!8bC$`X=&eA@U~W?}zAl-_l-OMt@6^vfU~%aTyT_9%-+ zgX^qak(&*K^45w{6&T+5cr$GBHhnv}0N-u{t|m{={sB|sy{i-V z<;y?BwoOW++gFl|eS%zJat7E$K3F@JN`K8U)!-IX$Y-TP)&qfD(qtHyf2XLoujr_+ z>JaX}n0@?0pi^M zsvCPKajTgPp*s&Lu%RPckb)zga%EY(mTEAj-{=Vv9AD-BCe3paX57Pi&9kI@Z01b4n{rNnj= zyIuO1(mI`Q5BdQ)7iQsdKTTs(8*a%vVUh}9h0qEll}UX`CQ6lPih)6RKt%Z1^Bt+bV@ZCsCy&z`Lx9ARu7M zze>t|#$ZxcJWT_-B>wL&0(>W#QS#(R1iHovN4icMZ_q-Poxsde7~1&$a3Oj59KBt$ zYAd5nr#!M|sf^o6*_L{T@$!c6`>&|}Pt3e|Mdc%p8Ws=^D|`!o%*QU2nV3`3tu9DcUww#M zxp4FngdQQO4{x*R-Ss7pz!-x(cGFt7y;DfDl3~>(o+RwL=2g)A5njtY)1Vk8NEI@k zB`G>xlh@w}lyb_qmF-4m2-3s7Ca+WX(zb&NMA^pBEhc#aUrDd=topeT@u1|m##%p> zA_a5j^3!9AR{ym&G|N3&t9h3xRFZ9$GnRc0wk=`Ns^H}GM&Tpx${%cLhCZo$I+=A0 zsIka6bylyfM6)vT3PvuJG#)~w$SgK@*u%ghXUs4hRKBqRpBpoRm;or{NVY{%1gf;X zGwu-HUY#_#Dymx{5DuPAfS0elR{g-auhoa0+e!o9t`H;bg9pYIf7#D;1Sj{MILjdh6B1xq0GprxVx zQnP3yKK99x=s(aaxUWztKieYW&JOkm)-Xn)TwK9O94`tr)ofHeHl1fFbtPG_#yv$D ztWQ^zhYZs0$?#stZTNUXDckKhdqGU1`NaNCLYUbD7r(V?giE*T#5LmlA)=_pN={Rj zm~!{jZD7ry6mJYT@c^j8dV{frD)=UN&{uI=Y{vZLzHFmmaz=AUk=3pMdN3;GR9^X( zZ1>k6H~@9ib)?FS8zc=7b^SrC2=Md>7lU3*)Jn$-{ES;>79sQf8w_{u@v&??Ltu^W zF82v_&npa{-k^A%?jx{_j`$@!2f}kW{!wRF&o8fIiXdEZAqFx9{ZZ>iuKeAvvhrqN zTN||1%qj^8rZ`>y?tjBs4k#wm3Wz2o8D&q5H>J}M^epkI#-1M>=^uRqN|KFSuEXv) z&WdsOsE8&vm$fqYH(tGE&s3+*#*#e=Yu$Ae76?}V3{(+wgs}`{9QENK&zBkyAX#D6 zKAx)#a8v27UwGhUg=2d;T1IR!%TV68k8rGW>US>tRkb0pli%ewZX$0NoxD9_)!r%e zP$Q3=h#sy4&XvDyu+cY6?y^&Np4HBOIds;@($TOF6e*n5tT8>?=`EeI12!p@BKVtq z+6X^ZqCt-Dvv$-7&z~8>^oE65?;bgVK7iWVmChX_CK;Csmv^n&d7ac+XoC4V&- z5>CVzOxBq0u+|Z?>}ioc)Xp6>`cgsP=7fLrqp{^wRk&FIr-a~&=ynVF$zD9_r`rJ^ zrsZo%w!9IaBb@?z==cj2?6B3~NGnPEZEG8Vxnv0eqJ&bSpCcCv2ZytseKbLNP-gb= z(!B;sk+qh%umFPVYw)+ohyIRw>E-JOo*s;+Zmf`U*Z$^@8It&tN#Be5oBNqFrG7n- z&lKtyI?&F?Osk@D3#jB6+9e7=G9lhU3(!|~Uqb?Z1Q3!4?+8CcR~%EV^%AGFT$P|+~>(UR0wro ze_|}H4cN`28bdNleW=qWiI2HJ1pbrW7`I^%ZYEZ0mci+E@K^uEx>CBYd91KXET$z-g)5d1ZYT|-7Xycp)Fw4vMG z2=>02WF;>@#tNlh)2|}Q1T0wJ`mv6D# zq=PPixfGwRUn)1UMrC?hk+MSsIhz8*>p8<)!@-=4Cli#VaPE?;uaRXY^!~Y&(XEwO$BLUzO@ZQ zG#Ig8e;uhiXu@_prLuPt)OvwEz3QQ{7{tdPcB?3+>PquPd5qcZm zHBAc}s2-ARS?#j*3bfrkx@>IQ{KF?2u0Sp@@Bt;8)&G!<$OKde=^u08JeOF z@9ESt{}MZqZi8*|ZYWkc`C-@~{g^!`EBx4DJ2;Ph;M}sQ!@soWYzFVqtg5OP>F(C# zd2srD4@3O)N9o4Cy_vq*Jh!XNR)oSm~<*7`!SZAqWg#s=|jXQQ!O$l03Dz#?gXwvPF%Q#T(S{KNqz%6PIn(tp(!xd3S^MQV0P0z5eddMCZe`s5)KhMb&PmWB=0dIa9~BXr2hJb9&I} z$HDW#&>KjSFwg#_dhO=XlOBWN!QswpZKxx+sESCbD_WS_Ug;q)3mM1fXAr7l@wpY` z$+HY#o-BV!tyf#q*&2O8NT=$&B5=PQ#@ZSh3co7IvDqBRvdKyW^RpLF2&Y8U5W*eS ztL=y&RU(_&D+lfki+wdH59@xbOUX9LwvJVUx6yJpSNBShcw_a#!Vzro^83}mH6P7$ zS6*bWSc;KYAu?Jy456jbkSUu4`IvV&2CE6zZkKkEeDNDcHcuI1lWm5w)Z=AlAAhf` zR`U3&HxEBh_T6iz2N9OAcYHxnggwEV0&U+Y|8}kHORRPYiE;4&N+|u$Q)<#*fo0)_ zHF1|XQ{V?T(K08)&3JY`8aZv1An%WCne7OjDQIV8-jm_K+=$FYgjj&=KR@VW)7OC# zJ)tv~IYN4bm`XVZHWk;@O)ZhJo$%Lq@ct_ne3q2w=pWnX#XtOmVV~8Bykb4^>-nY> zGS+Q%9xiL!!fD)C}6(zVMuNsT7?)9+ZRA z2|WS4{E*YVM@cQ!Qu7f7T`}!+>SnRZqlRYY@_nvd{XTU&66Fu$n++075!T|s%uo4? z2_&2IG1I&`N@gJ!l)90#pMJfC1^#FYu6w)=?{FdNj7yjhB1@#*c^Qa>%7VzmWbbA(AW1fg{Vk+j zWuHr*-^VumF3X#{3T-U>`~nZaSy!G^^))5wq1sw_DrXLgw#W~I!0hf#vDIN{@#Gn}@g<mQ4nzpta^Bj_OSKqm?XB1s?ZnR?*>D^oK zu8EoHix4l|Q+;F>^XT7>E-mzIck7Xcm)YeA#R z7AGct*94%e9mQCjrku783lV(yl$!A_h1R$iax{D*akICs$V4yo4>dC5itaMZs%z`I zKC}^Pv>p0K6HH?>o8IRW)H8!IHi=hq`&#;Q$~k{)5Opmo z=TJyw^orE6Gz@)B{<(kg$t@dXG#w*i>W7pyMB&F=DDAtS`DWdQAHT+cVV4g*;%hDJ zuunaR8p1Lvt#mng!c}@Bws@}USKx5UY-}r+$S31by@G1&4&>dNF&_vzswntn0UMeR zO#|61z+6r1bc|ZKG_0y4E?ln;;2+AQRMqG(GTb$gK;tkSdyCakUPOD`7DgEL{d5|d zMbszNeN*wOOL%nPswU2F4Y1wRf#Yrc5+~%4Ihj`>ky>uZKGzssFl4Zit^WTNY z9wjYH_k6nZFetOe=F*}oQ@cw5(42C9W1_OK^JnDdvlc;)sh;CSiu&Z>NLJ=4m$_M4 znB0d>?2Hvr24LKT&3U%w@}O z{DRgm6{{)0=mP5ibgtzvi;rK!r;mQdS*82;Y3Q*GE=Hrz=SE29w39`?b{9dzWoAX$ z`q})*wxolQr-usuyN>1a$-*d)NF19qZcps>cM=vjwlbwYC+Y-u7E9v43}H)1Ow~}X zH9#LA!nTtc#4EooQzi~7fM}Xb58;mo!5prhz z2xypB0s7Ezvhfwocym}JhK7!QZ2YA)l1=$hd7^5sa^PnWNHq4tJI!6iWN;>4n+k*& z1~+8NUr*y!LM;RWN`uILgTc%R9<5m?EssD=mP8gmYJpPB){U2!~&eQiC9>gD9Rg9PqCz zCG~6KJ}%I>jZ5on(wc@@?3@!HJX2GKJYuQDGKOvoV;^T$LXLELRYwTbuoZh!UUA_R zF({j!7q+2o1~uKs9B;nHTNiD|IihsIjkpb}P5#D?5wO$eCYygd6N)%C^Erf^xQGXJ zb%zi1e@W#8mcR${yz?rXJg zgpxv3ax5PS-V|^g)M#;{ohOj>{gDTp#9d+*!0f5iiN%S?-1x_ddvzu3Q9{pCKoQj7 zm#m8oUl^Et zAPa&*_mubvP(@+rJqC>=4LGQ0pIba)ejRSa?dBYkdvA`^qDglSWIu`$H~)<9o?r3C zAJ4)6=G@$nNdY;O+#^-glj!=@D zrP+7laxzY95^9lr38KJ%GxaxzwO}>H$NOP8jd#(|T($Pn=$vCV)85*yS``xdTuk5y zW#d{u(t_L88iL1-VoLtoPVsnN?5-WW$ZlLr*F?i!YXFv@FH0Fyx} zh{-Ju2^XsI~;@+ggsmiXbI zvETavG>QPU#%7*~c>@Fr4X{|9V|W*<{$Np%kSWo?K}RUY|2$I>cBDUZClKGC#4ool zQY#!t;nW$`98Lf1`=iQ4e(?OP8VRN6Z0%#6h*nBw6vXd@nc5?SBoC_7HX?gQuU3M- zNeuH0-mpjQMWT?nSNj6bWbJzxZo29T}S8YRh%Vc@HUIUq#upF0&8r{QccZ5-N{9J|#5*gYz#ImsIXaWpmx?NAzQJ za~#hL_t~;%4K|;)~5_nXBOb#t?_3RI@tV(8^U;)fMsztrF3NNFq;Vs@;v6Tq+W{kbla$eLzs`Mq)waLOh? zZylJ7vVAtnfNC&~iG7dd94 zDU0l$X05^|y+Ck#kt(a!fwcC{Rj)z&Wyp#Cjur)w1bLigL;!S=F3`^Wf0?plMqG2+nS_rH@Nek=`vNK#uU~_PeAH{f z^e)LdZMt9CK!ERQEhnxSr@O*RV_$@SDs|a()$>v_@rM8M?~4Jr6kd^pJrAzUKiMc> zl6Mb$5Bhh-t)d0H~N+txBAdWF8T-JPWhTnlCwB7rZyL zY36G#s>k$l06@#CusY;vc2?w@%G@%lO0jImj*EK9ZEKX*E+%QSO0LXf}Infu6SE z(eccJ?h}G0h9-s4Izy9V5l$v_Od=8;!g7dDapy1zI7nw7VPcorba{&mxpJ)~&=0aJ zK{-pB<0W*iYJfvzl`|>~Hper)7;p$vM83CT5+79VxOOP-VUL1_0kmly^~!y}pMY#M zB7-pA=_oC_^+cV#&d1axkT+i=xgB6Kw`N~tL<{%poLScO{yS2IZ zhCDrrUt;8!f6Mvc=rmZNA@n9|P|fCl4A^V|^+O_!h#0;44g(dPBabz%LQq6x^stz}=1qdvxB8v7^0;A|>ONJW4-5c}I(%>D;rDnQ zH6I;Ld^$K`FHXSM%WPIwtP(;WF5vIXv2lkm%LT+Q^y-j0l;KAd8Z-%n+E}&#S;wNl zaAs|RfmKs^?3L>bBEjE+TpZWA=_x4x?M+1<@{n&CXmn*F4<&7rtToWAS7+v7#?47fEf#E!t{KUq@~|~ zzY{L1w%v$72qnYSBl0}(xgP6>A*TTs5gY6iS8PI>0^oq85zhlLS5)S7LsWr`wfd%_8RxlN9MbD1t~XkGW{>=lr5Ef3 zN5`_E{Pd%FfhA5$F1iQ$sGi1zXrgGWkJmhtrii5e=8KOut(+UB>K0v(bw`942s|?U zP%9|M@@@OoW~Vk3j)D6nA;*1`bVuF7su3)#!*@kCw`?1w{B;2|7`2{X?CS$`44TYc z6Kk`|&PVL9%jeSI#G#8xR|7fk4|X&&`$_?p{!GK(yf)Qw%&zpYh`$9uuPWYqs=n_h z*6c^~Vq>RI`!TiUlLEjj!B1q2u-xXK>f0?D9shml9NC-vx!wCzDxbXemt6Kt&7e)) zwmGKG?gQ5?;dZ}zj$1s3cXr#%JT-C}YJYkXI3<=wKB}CMZZ*I@@4f~Wj>KQDAm@tv z!TRG2(RkkHUta_vwTz+p2J%SS)wrYtxB|@%J}NU@yxOjxC&(T96w8)7e>xQytctZq z%}!til-GxIV@A{llsA8DRj|8jPGa|8$@VeYUOQmD#kO*8*H^g6|B<%M>YXJf#I2^6 zbvsAaplAMJi!)ZH`6i)%2^rN_ghyi&-tM;l3upLqrfPxp{joA&p3z+@=~sg$p6^Gv z6^u-^T0lD$)}n=japuG=I3o|WbesUAL&ci|IfhWf>`DimI=JpXpz&f_9}*Ge zRHzEgywUEqRmnO#+(i-xiP`n5M~}20Z86zNH^KlnxBbZKk^SU&1{{p!3au3S#!#N$ z_2cV?UhQ8W7o!K)b-nSG}$6J0UB&T685 zyz|beg2yO5@&MI~>5N?61ND z{o7nxEo!mkbnxqK#d7=X#h1Px>td=bHfH~qoRC*0icS}ws1R@`__nZ6U`K~vLIj@?&?8o0)cQIoP72cVHO6pZ#BKcz21&l1l&u)P;zSZM+7rnNTvj8v-q zP{P9aP~%Nbp3;bqk%#-pphqSZ-mMtSU%RwuXqrXan&;#DBl_4i(#PD}4@ zGe+@OjJ=-l%ITS&gB}CZhU9*iC*D@DKrg`AN(#4*y?ZBW&EoPv-P-07E|3&&eSw^ zHyPmGD}H_myh*)O>N#y4>~!76wWgATDvD7cqh%oQvaZo+*l=MLGlA<}78HdkJGTm- z4JN@yAU;nFNlzdB_T`+NtJMj;=N#27*^(D7K6oz4#eo=$D{+5P4-EM7u-czD*KUo& z3~XVKYM;j$czO=uH7ZS@H~Gs$@bJc7jHwGR4>vxdLoUTE)EtOk3q?)4CKa*vdg^!NT z@MDl(&hbji?b0(?=S-$hc?k>jGE-&QWTWwFRaTn*v5oAduH!!hWRqZe44>RfdO3%E zQQrOllwuDDdvj zVek;nZoF%b3FX^{2W=xLS6PiY38$3+-I*FcJ&*#c71C)~xVuv_8y0j(nkk?qj8n=d*9-ul|kUm6v=i&R$;U(j996^#9zLgebI6wl$smU=;<^02d`0 z1}w6FJ7(%_8fZJbj%*JqJ$(Fo#$h32tai-nZFI=)r)Ri%?J`bt89#q_P|4R~-G2Yi5^;KI_%M}FA zU_bI$sQDhK!OFvTyROj>5Pmp8YLrJ$6?HL;VW5unR zQQmKzfdgr%GIyC^sltHTM|CmU_2+AIMsM-J~9WhTvdOrS2ixQ*`y8H-4U!E;O5q zsEQAyNl$K)7OplUDH<(di5>YPHihVLr67+_IgPKBEfFA!?+$jONx@SKlL>^}`~rvm zP2CA#n9&a|bI1#HGLvS3ZlnBeq@Ln1p8@GsB#oIxEv)bp&{?Fkz#m8@E@}Df>dq!4 z4hZ2IE|G$i&_qxZc0WNra~oR&o^OTiTbq*P`vQAZsy91y!^h`jcoKTlIqQg2eQO;_ ze+kk3CEzx5#7kYT)Zc4oU}GzI+>QhBvX>nRTt}Hxc6U+tZR1Vo=Io%;MXn{|d8e)o z;KYh(Z3b=W9HXtM?7a?advCcJgnU zO5+ShUlxuh_Er@uW`TG~%EUf*1+(=pZ-)a*l} zK|G>0de0@2Xli$ouwSG%dB&;H+0c9r0d~vPR%*kU-$G{r>SADkU>3kGaA^cwoblG= z%;j6sbXPT*YqFMR`;;ZQj3IIQCvj4Cs>VK{VXB3;Ej|9d7Mml`4)3ulqXjr&Je$P8 z5D^8MFZ=T(yXUZOI)Yy^e?Km~d3>A$lW?_H=GJY)Jo!ZtT@8HH0zdY_ehwN#J|w1q zco7SfYh2E_!tt*yPA~w>X|;BJ*2l6h-1Eb9?zISN&wyz84310Kq5On--oOHiYPuYL zl-%%69dSY+`fa5B{_I7`4X#)-w4}b4nZBJeb5FLchK$(~A~SrX4wsUNhR%x6>K*xv zDWIlK5y{0#$(5u8lx<%{GJi7;rNB&uo&0C~}gkhJW4$WWhXKsM|Km5Q)U)1xj%wLb(&YF}cGCmC}oghM} z%Jvx@Gl!-H@*T#Mrrkh5fZ7Bgzy6&?|FmE%7@2Piht*fqt8=Ja^B%k9s&^c)HWKiA z!boAl*uxWLj-ub)e*O+uetB8g*9%K2rNh86-Ht-2%??Vfr=gabB9!nZ74w&-rEaie zTAc8bJVuOMw$#pt0XP-QAmH)xhOL@{4@Cg{t|2Nw@5lZ3lvD~D7%tlPdylN==~AA> zOm;>!d~C;koV5$q^7f0r+T1`MdJg?)r^Mf3sD{)zwh=BYY)T5oTpv`nQ>#@>?RYpK zti|xo^yD&w9L+R=TuMw-*T5D&Ju1oU5XNorsi7%LGsu6aPsHAw;7(?lUIaBL$Hjh7 zQJSMftv_7sj;`#zk0rh@h45ppBoZIEfD69)wOWc$$_X8R_|0ZRVPm4l z8$V?1Qp&V~d8{fsZ2~mEPMiGxKrJfBib)bEnYxLMeFibV`sPX;^r@Wf?QdT&_8q%_kY9PF)hz|0^VhVb79vg!>nZH z{HFn-z)_q@k`08rN{oxN%+{Vu?W_CCEWHIUL!?=Q+g5^48*0c$nyQOqmbD30e-#u0 zAgQJXfz8#I0t}VDt7vLthC>=vDQymU$!UtTjj_QA+v7YuDPa`~r&D_$pfHW!){r{^ z*TGxvY~7_p!Z1br1!?{8Yk2Xv4ZxkzYwy^;Z`YH$o5UJ(GQ^@RjQ}hq2OG0OI5$1D zJvznSY^n5E0da~7n# zUmgbAuIVgRL+)$0P~THwmx~E0aQar64ql+8snPe=t~KF16R82Qoj19Whg4@5ny_Fg z)bt1rg(tmY|6}Nw_a4P>VOyFWzIlZ$12k1{iKWCW)FzgYP}}Qk_)_xbby~g=7db%u zGF8-j^r>|ly(b3ezYf+M?=H6yKJ4H<7ug~4ZJTtMR-x8$hZ0m3qHBUBbvqa-Ku#sK zS%)0f$! zES(Dl&4Cnc^2pez!-&b3=+1oX;&}L1k~zn4gxF@b7zrpR5(*-B!D4r6Csf_gL&Pr_ z)C(l!q$*OgGdy8r%0Fn>k9izr^=%GLqhb3N_4-<-RjePmiX=U#!Yz!41@JmnW)T5u zsgyrz^!#BmGmO6RX{PJlw92G&l>185z3$0|#d+wU2$~FG<-r>?Iv7UvWokhB|q^p#tYBy<8{o*>OPmSna!-=oOtz*qX~$ zc^pubsuv81EX8MP^48*&Er^-p;|0hhlS zo6z}P#`Jx?L$okJvm|(J+qP}nwr$(CZQJ&DZQHhO-~Qih=Jo5I$y!v_sS~HF77>}X zil*p04c_!D(aJ?<&5{ZZ{@{3cR!_BM`zYK(ii8Azu3LffRc%R68X8OKySei$2U3{GElu5H6z{oJm3%XDJ z++0%yys6DPeLbDvfBy;O?VTOM4iNH=|0lx@(spnU`j?yP>UZ6`%GvtX-j|t$ugmKD z<`TdCG6qb5ee|;KSD$T-7LeSiL0->ws^=AD(d1Yp0pj^lAtOr-7e5clCm06y@_H z)4()Gh~K~TSAetVyc}EX$oFQ}(c$#OxvODV5WGx*>cIa zEV8|Uau*DhZtvaoGU>!Yf9#8He7j==BQ?O_Cwzto{3Byo7@gHR z5?JXAO}vItBldV@db$CU+-(=ORR}6L8>=l-e{wy%snnCNMwYZ!52;DZDL(@12ykl4~q(@t|D!sFA(hxy zb8PKOl;<-F3??Jv&h;kh(p!HW&zEL{ysOKW$l988#QbnzjW$<5J)NhL!Id&=kZ(8N z`B}!gGDiD22sTa?RiyUb2%DWd;9Tm8u{~3>w@FWM9QP5u-1<_PyVgr}Q-6oBlSjRm z${s7c0CsRSe^jXB9Fa+gsj3OnkKq_e;gd>kUm(u>$00v59f! zl-XHZ(<4arE6~mXJXTEg-P?da=-{^M?>d=y{%z=g6qcpqfZp|1qh({W{jbQ1UZ9Bh z&;S$W?PF-4`>u-0kRn*|7VWTOvNhF2^D#TeC9{P??P7r(?H>1% zHjWiVE_~(2U4<*DZbk1u$u)wwP6Hy#e(?CcAH*csD@$WoFZl%~*gc`WEDErOT zIZ@Trx`eqRrypkv6)J1+%!Gujq$3}J$RNK!-pZtg``q_OZdP9N^y+F^7rj@3Fb&k3$W4iK4&^B6!gBcB6Kz{#c$0QyWgHWRp6 zwOAw)3W<=D6!>OPg}t{3OM9Yjj*1)gsD{=*Fc+R5ZiK(^bd++KY_(;Szu5nn>Dqv& z65Dz;kalc~qGZJrYIJ`~0>4M;T7hil2vf52Ogy)3&?ee8IuWf?H&)kfD0vT$s;8q^&O+&5z9iUnF3?G0{bkfl7bbe=xs}C6zgHEldJ!8`r1@Ql|Ta3ua`Mi`gyF;q8 z&Z*eJsy9|6K2Y=#7lexo@i7JV@3E_Lta_)Nah(x`XgcqKZ~}jPvbrT>cz9L6SoyRR zt&FkqLN6eE+rja;vd4JnM2?p$D_BSe-wvZZdR|W-m%FsFGvXu68hRm&TAZ$vQ?;m* zzO7S|M}Fn*g3fhHQye4Q&42sOy+U;qSycg{i{Z*xr@NL)v}lfZT~7LpJDy3)HXCaD zj6AZK6p<8)xfgvdL~vQH)KRTBv}BfWd9Sm!oK5osdG^gv&H8SAb9&vltMpbC=93Y2 z^HixF#{{6b&0Jb03$Z1!N9pZ|1dsOgL2}IiYBY^SC`#T;_~IiDB(SY%Uo2-Oku@}8 zEN9Kz$;!Ewczo8))?5Z7L4JgZ(O>rI^IO?8pk~z@W8NhT0m+BluM%ZNn zY%AqVD?}PZ!b=ZKw+B3j3IfU*jGxwdlc8Q}k{F+rw2>BT6~%|Dd~tA$TgZ_8gHp9# z9oz~$P6x5P`&U|>R9~JEg--R~Ge)?W@iPpJX5Ww|p11bI7w1g>ghP=&q5-*0?UdA6 zB}=%qT;D3#H3FdVaj@6j+T2+^KggjDDX-6Z3_sB(k87-Am(Pn7VVM^FIsKrnA(`j* zU&M~)3QmDN>#%xZif>ORNEg^3Fj2yZ^OO%wcPc_*E)ULygM45Zi6E%dVUVL26a*0A zD6vMD_m&#LjRKJ%uLzDAYd9>RaspY5O}nW*%;joul6BgJD;Bsuy{X`iCJ|fQOy`;y z7g|m;&&QL@GP0G(6G+(SfK|UNJn%w*_#jWNeQp=!A}sX9a^uivBzeCE&GAJ|DLpwo z_p0N&Y>f>BN$3XG(6+ik88}O*lRl1WXQyB8_V0o&yP6BWyCSoGib1JbQK46_*O_cT zp&eKu4fXIV$@BL4pq&olzF9L37?6-Mw{hDD0meU+(@tt<{F(PZMf^2nS0>dY@5(mKXGzZQ@0{C zf7Ed zbbEJ6kh=Wjy*3n*^*3%hgX71@~BD}v2n>D|>ie{>RF@k9N@%1)z@ z=O`%MQVaRexNhjQ?$agOdg-EBT;0n- z1m`Qkqzwwuk-k=fAEi^Ib^B8ZR8~2UC<;0dbQu{g*{XO8u`B{XP772wq12_P6@KRxE{L<*VY#pTgQ=PlV-3JCFRV430$J=bQe{2LMe*r zWzo2zYCn(pV*;CT4LHkXyoovNf*kVzr8pW??F7W0XvBW(I^#6nml;|ulXLJj8ZIly zt18OPnW8kkX*It%hAq(XacKD1){e^C)&KlFdtZfLY_F-GW#N_7%aupnIp$xRa#X-B zGbxGXN|Hjz4R)PW61bpxFKl{#pWs;S zm5yvV7EIYoxf4pTb7Ae?cGnetdJa0KJ1KIJ+9;t9-GI01+7Lm^fv*5hyJSkJNLd%w z-D2jo{+377O!N{kP?LhR!m8+dX`aWrdq3wwB^Xz*_DTju1lb-EtO@xK1V1o3Jk#7y zDaFIRR>w!vqc*N)v-N$O7MU}!RFLL!e+4&E^>A1 z25d8I$^_R=z>Jb=I9(jLJ{x_B+UvFU+59=}(SB()LdE*iFJG* zA#RwqbwPXkGfa3`30%v#Lf3(flD(cFl1Mj)E9@KS{V0W%+MC)5JW#+t$i<&smB$!| zEIW`!q?ISj-)&!h$WaMwz^WJDm9iRJ(v;5)t2G?6IS2CxJ~ z7m8@|hB_{FrvfA9;`X5&J)*ikEY@Be;~OG1#6ird97W$~E2l)Z=bCY$}5Wx_$(MOMQECbA_wVDbZl$VSz zm`F&kXpsPJUcnU?fe$;uWvRoHH2Dsxof?RDamojATK`@H4-@uUP=|{X+;cq#kxZt` zB$Z+aiu!lXDWx1jiD$6Ksb?7!suwBT8k$(JCg$dAYi3a}9y(^cV%@9R=EvLvgNo*- z3X*=CcpoK@iS?A!f&SDXT%gEFP_rD47ZEzG1fs z%!|}Wc&k3QDUUyCO(1LJ-nxRr)%~5hq@c^AW&LH8uLaLy4P1(TL+%<|vY&>BTEKUQ zRW=O+u~AjQJ|B@yK?tE77y?L&Q`aF98?H#TIG#jZZEHZ63u{Q%wE3)wJ0}4RgB-u` zppB8Vv3Zps;18@KLXp9%1d(_a_Q|p;zVq|LwyI$avWKHL_WVmHvG@IPF>KandfUDG zb(QlS8n61&^78(4RGwaykyc$!_ZuSh(VmvBQtojhpA%WlXrIi5gfUjPD32wWKz}!5 zZd*!S^O+WUz37Lpk!nS-C^NH}zOWoHBmYow12!KEY_`%-%`0z(O zOi69HZ5N9ucYT0+s>^`XbyFs}xJL#cu@W{KHA}vjT!VBsd0fq}HbYm@-Zh?2`#$6ge4yh(g%c(VZ`Jxyu#n_tOrzmIJUwT6c z_if^99L>~Igfx#FhhzRzp>Z(ac3jw`=1uV23$*Sc@=IB9JYGAvmBy76ni^q%-4)#) z_4l1tw-a%{VO68TM=IPoaFq4Wdo{(E@gDB?=;e2o0Xt>M4N3P;h)BfIEhP8sin=b{ z8{I!~&Uk;ngPRL8k7aW+O&M9HbZ!XwZ=U)5jyuc9@B$MC2*3yM%l(Qb;+I3^I8`*{ z+(b4PRu(1~7V}qTaqBnn`wzJ@=cf;HV5-0(5N)75k+5yV@5?_@XX;McAE^_KR7GWV z&$y;^*B`m_y90Hc4=O)DIO*{5Te*MPBrt#J6#z?&x#BA|;!$Cl6G~qo;j5>~9@o_7 zC*=?zXqh4Fp$Gt6G!`1FZ>f^aJhT!+W1FJ=D%VO7y9zdw6%9#?1j}%M9j$6p(uz_J z*I9K(!ERG$!9s+T1$&!EkWd6$bs)i^0qdFd{tM~>n+lYE5+IC5gv`zGf%xNq8Q#vu zLvi_digb{OLyu%c8{u$#5ck3h8F<{rpb-Ks_8D4E3ZceT9^XJn zkS8$C1j6vzjG6OV9%rpT^vt{YA`W{mT$b9@=-t?Q;mw19s=-VUhFW14p6jdA=2-%e z@3eao{1;qm;VCy$i+uW}n1s>>DdnuvxY~(oxIJ7F6P5i&dk2g?lJXXV#-_(;`kYoJ z&7+wk`QOHjVfA-%7qL9U)16dli%sg=_UZ-?b#d0gITWkRXH+vyFkKh<);Geo+SOs4 zr4oz9jsr28Z%p=P5nRmBF4QY9-X4EDI6MIi7p%Ax>x4=iEeSSWRtc!cqmD%kD`Iy5 zNB7u*f31eJU3R#Z4r^$he4Ccj{5O<7e(LF~>U8qoCvFK($0}GU4d}6vi?q%TW_H27 z4tlD1WuvAJ_6FvMk4LL~-$<6$?{MYHA2T;??mt?=rNEciWRGIzpPW;uX9mdvyn7GM zpv`VzxYGxXZbU$1vV`|ra?>oiIIzp?)>nj~%v^OsJn~LcPqkM$p34BZ;pEN$(7q_B z)qwLA@qMqCv}o^ZP%PvCO@uE=gBQt<>OFvv?W73%tWgs8JTN$F ziohE|p+JDh7QvNf#K%u7z&u7+`dPg120(Qcsbyi7z)Mh6UA174+`;>J z;rW{6e+fu?+6|=8&CtTDHhE$`=4>DgHE@7|a=MaCwHJHB-AX}_R zMCsyCLwu*KzY}W%AcSyXQb~5!FGP|^)~dGKcMK890DVf65^mg)~&B3+KAOkAL zGVHEUpTv)D&7!wsdf7OjmOO&P^I%$8a1Q$+ZuX2ujjbWDdDV6b)vqK3uOo+0 zzUHgZS@fwZEo&g1xsYM4r>H!7@Y1U_9$6AMbKp2~DZfT}(S?(nzx#4ob4Mgg9$V~| z*rkG&Yw?yqC@$)WX1BP}8b`HaE;CkeQ-DfZ1a!xa^~bQ^^3Z9)Nw$<#*6YH{jtrqd|4b7I-tp6^f9B8r?xw=Fiaw?CKD zMUZFqP6EB|fO0%H6e~TL3D0A;$L>ogbFFHgI-r&?T3mFu+4O{g^iBd(mgZWGF0gwn zZCzIFj2yO|g?octWX~vBsQ{w=yS#h&!1!AY6FMj~A8k0jtO=zW5`1Eb4m)ss z5((t&q{aBg>Qh}W#>Yjk$R9!J5f4VFNgE`?3TPVUT#gA?aLaWd#@KptMI3S3izqpX zHk4xY)i$NCmuK@5hIsWhh0g&HiM*Wv6vn^l8DS1AZw##Xoz=Lm;<$Cu88f-o5DAx8qN~8ji8>AUtfpZaKUK2A*a5 z^q~YM#@VP0d_LMS2HPvXiHbLe%4dm|*UZ>RwUY9h%NBxB(@2IRVdREkPe$(MKwOa2{zt-$e&OhCZZ zkwN(7kwGrCx*LhjCkX{*=*)_8;w_m6IqR-b6Cp?5!~gjZ_|LaBHdl@emb5|4jqSc* zxzm77%Y9I+E5rfP56$usFh6_C(?fm?G6@cRBhB&Kz@5wqx;6E+NP0Ktm9I2|jY;UL zB#KL|=o6~fKgrnIZ{Y2#(A$-u{&GzScP4Bto66RI^9AX$UPL70x8AGduJIUz4OH<( zh#8j(l|cUd60YPr#vRI(?aaE`yb-o({<+!g z&BY!sOuz<}RmdW}(&9 z-%4Pmg3I`NaVVy)4_TErHv-+;5H2>9h_B1!rf2&ES3mo3l4VpO)1^L5w+Ozj(~6I> z+JPrsPbG)#v9sMf5GDe4HCy%)ueoP$Vc?OLdFwPH14b>tw#gy>j5E`w6sU+UDS&!9 zDue3_EFeQ=T0cz6Qdro3grA^9duKwEmYgllHu-5(%y84lzCQYns@i7JaeaJtXM~Lw zOcjUY)t9u5Xax<@fuc>JjPQ zJ4Do5+{87CN$=98Q(NU*yh}B_@_xJN>7hZx^KC9SMs6iU)5nQ@D3x3_q7KcDlIdU( z@f5oEsnnP(n(b&WY$heT55ZyYs;tJjn*8uc6{Rpj@nLuQxbybjEW2pPdpHqx>!=if zy_<-fcV_+@d%CDB&>o2hRl-p6Bl? z$Qq1QRQ&MNs(FH2831n!L#q0TJk+t5e|*4a6Pm+$Y4Q9yKevn~f>onXSTl^#0c^hU zRd#%6uowb4;IOxeLfXPcF%CJz7YuND5JC~yO~&8OD#)!z9m3KH60<5-ZngUIomSo| ziA6??sZS*&xQhpMnmJWSaI>Uhjmf)j+!w15F)DbzdliQHtblnfMKqXdDV%SqhZ;|E zu=tC3LJ$tYYj7$yu6by>^O&#)Bvci;-*0nR=GcG)^W#_60rkqUB{a4?aLLf

63D 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 literal 0 HcmV?d00001 diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/NodeTypeDefinition.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/NodeTypeDefinition.java new file mode 100644 index 0000000000..99639f8d8e --- /dev/null +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/NodeTypeDefinition.java @@ -0,0 +1,14 @@ +package org.openecomp.sdc.be.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Map; + +@Getter +@AllArgsConstructor +public class NodeTypeDefinition { + + private Map.Entry mappedNodeType; + private NodeTypeMetadata nodeTypeMetadata; +} -- 2.16.6