From 9a2fd3e23edb63b55ce0b5a2f3c96a47ecc3263e Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Fri, 23 Jul 2021 22:47:09 +0200 Subject: [PATCH] - started to implement functional naming for LDs --- config/stack_config.h | 2 +- .../server_example_basic_io.c | 2 + .../simpleIO_direct_control.cid | 2 +- .../server_example_basic_io/static_model.c | 35 +++---- src/iec61850/inc/iec61850_model.h | 13 ++- src/iec61850/server/impl/ied_server.c | 52 +++++++--- src/iec61850/server/mms_mapping/mms_mapping.c | 93 ++++++++++++------ src/iec61850/server/model/model.c | 49 ++++++--- tools/model_generator/genmodel.jar | Bin 96982 -> 96995 bytes .../tools/StaticModelGenerator.java | 22 +++-- 10 files changed, 184 insertions(+), 86 deletions(-) diff --git a/config/stack_config.h b/config/stack_config.h index 8bbe5d1e..369ef2f1 100644 --- a/config/stack_config.h +++ b/config/stack_config.h @@ -17,7 +17,7 @@ #define DEBUG_COTP 0 #define DEBUG_ISO_SERVER 0 #define DEBUG_ISO_CLIENT 0 -#define DEBUG_IED_SERVER 0 +#define DEBUG_IED_SERVER 1 #define DEBUG_IED_CLIENT 0 #define DEBUG_MMS_CLIENT 0 #define DEBUG_MMS_SERVER 0 diff --git a/examples/server_example_basic_io/server_example_basic_io.c b/examples/server_example_basic_io/server_example_basic_io.c index b6f86630..954be4d2 100644 --- a/examples/server_example_basic_io/server_example_basic_io.c +++ b/examples/server_example_basic_io/server_example_basic_io.c @@ -177,6 +177,7 @@ main(int argc, char** argv) if (((int) t % 2) == 0) Timestamp_setClockNotSynchronized(&iecTimestamp, true); +#if 1 IedServer_lockDataModel(iedServer); IedServer_updateTimestampAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn1_t, &iecTimestamp); @@ -192,6 +193,7 @@ main(int argc, char** argv) IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn4_mag_f, an4); IedServer_unlockDataModel(iedServer); +#endif Thread_sleep(100); } diff --git a/examples/server_example_basic_io/simpleIO_direct_control.cid b/examples/server_example_basic_io/simpleIO_direct_control.cid index a0228a20..ef8f1b7c 100644 --- a/examples/server_example_basic_io/simpleIO_direct_control.cid +++ b/examples/server_example_basic_io/simpleIO_direct_control.cid @@ -52,7 +52,7 @@ - + diff --git a/examples/server_example_basic_io/static_model.c b/examples/server_example_basic_io/static_model.c index 6084f911..9f9243ad 100644 --- a/examples/server_example_basic_io/static_model.c +++ b/examples/server_example_basic_io/static_model.c @@ -20,7 +20,7 @@ extern DataSetEntry iedModelds_GenericIO_LLN0_Events_fcda3; DataSetEntry iedModelds_GenericIO_LLN0_Events_fcda0 = { "GenericIO", false, - "GGIO1$ST$SPCSO1$stVal", + "GGIO1$ST$SPCSO1$stVal", -1, NULL, NULL, @@ -30,7 +30,7 @@ DataSetEntry iedModelds_GenericIO_LLN0_Events_fcda0 = { DataSetEntry iedModelds_GenericIO_LLN0_Events_fcda1 = { "GenericIO", false, - "GGIO1$ST$SPCSO2$stVal", + "GGIO1$ST$SPCSO2$stVal", -1, NULL, NULL, @@ -40,7 +40,7 @@ DataSetEntry iedModelds_GenericIO_LLN0_Events_fcda1 = { DataSetEntry iedModelds_GenericIO_LLN0_Events_fcda2 = { "GenericIO", false, - "GGIO1$ST$SPCSO3$stVal", + "GGIO1$ST$SPCSO3$stVal", -1, NULL, NULL, @@ -50,7 +50,7 @@ DataSetEntry iedModelds_GenericIO_LLN0_Events_fcda2 = { DataSetEntry iedModelds_GenericIO_LLN0_Events_fcda3 = { "GenericIO", false, - "GGIO1$ST$SPCSO4$stVal", + "GGIO1$ST$SPCSO4$stVal", -1, NULL, NULL, @@ -73,7 +73,7 @@ extern DataSetEntry iedModelds_GenericIO_LLN0_Events2_fcda3; DataSetEntry iedModelds_GenericIO_LLN0_Events2_fcda0 = { "GenericIO", false, - "GGIO1$ST$SPCSO1", + "GGIO1$ST$SPCSO1", -1, NULL, NULL, @@ -83,7 +83,7 @@ DataSetEntry iedModelds_GenericIO_LLN0_Events2_fcda0 = { DataSetEntry iedModelds_GenericIO_LLN0_Events2_fcda1 = { "GenericIO", false, - "GGIO1$ST$SPCSO2", + "GGIO1$ST$SPCSO2", -1, NULL, NULL, @@ -93,7 +93,7 @@ DataSetEntry iedModelds_GenericIO_LLN0_Events2_fcda1 = { DataSetEntry iedModelds_GenericIO_LLN0_Events2_fcda2 = { "GenericIO", false, - "GGIO1$ST$SPCSO3", + "GGIO1$ST$SPCSO3", -1, NULL, NULL, @@ -103,7 +103,7 @@ DataSetEntry iedModelds_GenericIO_LLN0_Events2_fcda2 = { DataSetEntry iedModelds_GenericIO_LLN0_Events2_fcda3 = { "GenericIO", false, - "GGIO1$ST$SPCSO4", + "GGIO1$ST$SPCSO4", -1, NULL, NULL, @@ -130,7 +130,7 @@ extern DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda7; DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda0 = { "GenericIO", false, - "GGIO1$MX$AnIn1$mag$f", + "GGIO1$MX$AnIn1$mag$f", -1, NULL, NULL, @@ -140,7 +140,7 @@ DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda0 = { DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda1 = { "GenericIO", false, - "GGIO1$MX$AnIn1$q", + "GGIO1$MX$AnIn1$q", -1, NULL, NULL, @@ -150,7 +150,7 @@ DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda1 = { DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda2 = { "GenericIO", false, - "GGIO1$MX$AnIn2$mag$f", + "GGIO1$MX$AnIn2$mag$f", -1, NULL, NULL, @@ -160,7 +160,7 @@ DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda2 = { DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda3 = { "GenericIO", false, - "GGIO1$MX$AnIn2$q", + "GGIO1$MX$AnIn2$q", -1, NULL, NULL, @@ -170,7 +170,7 @@ DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda3 = { DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda4 = { "GenericIO", false, - "GGIO1$MX$AnIn3$mag$f", + "GGIO1$MX$AnIn3$mag$f", -1, NULL, NULL, @@ -180,7 +180,7 @@ DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda4 = { DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda5 = { "GenericIO", false, - "GGIO1$MX$AnIn3$q", + "GGIO1$MX$AnIn3$q", -1, NULL, NULL, @@ -190,7 +190,7 @@ DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda5 = { DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda6 = { "GenericIO", false, - "GGIO1$MX$AnIn4$mag$f", + "GGIO1$MX$AnIn4$mag$f", -1, NULL, NULL, @@ -200,7 +200,7 @@ DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda6 = { DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda7 = { "GenericIO", false, - "GGIO1$MX$AnIn4$q", + "GGIO1$MX$AnIn4$q", -1, NULL, NULL, @@ -220,7 +220,8 @@ LogicalDevice iedModel_GenericIO = { "GenericIO", (ModelNode*) &iedModel, NULL, - (ModelNode*) &iedModel_GenericIO_LLN0 + (ModelNode*) &iedModel_GenericIO_LLN0, + "Q1E1P2" }; LogicalNode iedModel_GenericIO_LLN0 = { diff --git a/src/iec61850/inc/iec61850_model.h b/src/iec61850/inc/iec61850_model.h index dc5fa918..b788838c 100644 --- a/src/iec61850/inc/iec61850_model.h +++ b/src/iec61850/inc/iec61850_model.h @@ -187,6 +187,7 @@ struct sLogicalDevice { ModelNode* parent; ModelNode* sibling; ModelNode* firstChild; + char* ldName; }; struct sModelNode { @@ -212,7 +213,8 @@ struct sDataObject { ModelNode* sibling; ModelNode* firstChild; - int elementCount; /* > 0 if this is an array */ + int elementCount; /* value > 0 if this is an array */ + //int arrayIndex; /* value > -1 when this is an array element */ }; struct sDataAttribute { @@ -222,7 +224,8 @@ struct sDataAttribute { ModelNode* sibling; ModelNode* firstChild; - int elementCount; /* > 0 if this is an array */ + int elementCount; /* value > 0 if this is an array */ + // int arrayIndex; /* value > -1 when this is an array element */ FunctionalConstraint fc; DataAttributeType type; @@ -235,7 +238,7 @@ struct sDataAttribute { }; typedef struct sDataSetEntry { - char* logicalDeviceName; + char* logicalDeviceName; /* logical device instance name */ bool isLDNameDynamicallyAllocated; char* variableName; int index; @@ -245,7 +248,7 @@ typedef struct sDataSetEntry { } DataSetEntry; struct sDataSet { - char* logicalDeviceName; + char* logicalDeviceName; /* logical device instance name */ char* name; /* eg. MMXU1$dataset1 */ int elementCount; DataSetEntry* fcdas; @@ -425,6 +428,8 @@ IedModel_setIedName(IedModel* self, const char* iedName); * This function uses the full logical device name as part of the object reference * as it happens to appear on the wire. E.g. if IED name in SCL file would be "IED1" * and the logical device "WD1" the resulting LD name would be "IED1WD". + * When using functional naming in the LD (with ldName attribute) then the logical + * device name is identical with the ldName attribute. * * \param self the IedModel instance that holds the model node * \param objectReference the IEC 61850 object reference diff --git a/src/iec61850/server/impl/ied_server.c b/src/iec61850/server/impl/ied_server.c index ccf6e3d0..5aba1695 100644 --- a/src/iec61850/server/impl/ied_server.c +++ b/src/iec61850/server/impl/ied_server.c @@ -221,7 +221,7 @@ createMmsServerCache(IedServer self) goto exit_function; if (DEBUG_IED_SERVER) - printf("ied_server.c: Insert into cache %s - %s\n", logicalDevice->domainName, variableName); + printf("IED_SERVER: Insert into cache %s - %s\n", logicalDevice->domainName, variableName); MmsServer_insertIntoCache(self->mmsServer, logicalDevice, variableName, defaultValue); } @@ -236,7 +236,7 @@ exit_function: } static void -installDefaultValuesForDataAttribute(IedServer self, DataAttribute* dataAttribute, +installDefaultValuesForDataAttribute(IedServer self, LogicalDevice* ld, DataAttribute* dataAttribute, char* objectReference, int position) { sprintf(objectReference + position, ".%s", dataAttribute->name); @@ -248,8 +248,12 @@ installDefaultValuesForDataAttribute(IedServer self, DataAttribute* dataAttribut MmsMapping_createMmsVariableNameFromObjectReference(objectReference, dataAttribute->fc, mmsVariableName); char domainName[65]; + domainName[0] = 0; - strncpy(domainName, self->model->name, 64); + if (ld->ldName == NULL) { + strncpy(domainName, self->model->name, 64); + domainName[64] = 0; + } MmsMapping_getMmsDomainFromObjectReference(objectReference, domainName + strlen(domainName)); @@ -284,14 +288,14 @@ installDefaultValuesForDataAttribute(IedServer self, DataAttribute* dataAttribut DataAttribute* subDataAttribute = (DataAttribute*) dataAttribute->firstChild; while (subDataAttribute != NULL) { - installDefaultValuesForDataAttribute(self, subDataAttribute, objectReference, childPosition); + installDefaultValuesForDataAttribute(self, ld, subDataAttribute, objectReference, childPosition); subDataAttribute = (DataAttribute*) subDataAttribute->sibling; } } static void -installDefaultValuesForDataObject(IedServer self, DataObject* dataObject, +installDefaultValuesForDataObject(IedServer self, LogicalDevice* ld, DataObject* dataObject, char* objectReference, int position) { if (dataObject->elementCount > 0) { @@ -309,10 +313,10 @@ installDefaultValuesForDataObject(IedServer self, DataObject* dataObject, while (childNode != NULL) { if (childNode->modelType == DataObjectModelType) { - installDefaultValuesForDataObject(self, (DataObject*) childNode, objectReference, childPosition); + installDefaultValuesForDataObject(self, ld, (DataObject*) childNode, objectReference, childPosition); } else if (childNode->modelType == DataAttributeModelType) { - installDefaultValuesForDataAttribute(self, (DataAttribute*) childNode, objectReference, childPosition); + installDefaultValuesForDataAttribute(self, ld, (DataAttribute*) childNode, objectReference, childPosition); } childNode = childNode->sibling; @@ -329,7 +333,11 @@ installDefaultValuesInCache(IedServer self) LogicalDevice* logicalDevice = model->firstChild; while (logicalDevice != NULL) { - sprintf(objectReference, "%s", logicalDevice->name); + + if (logicalDevice->ldName) + sprintf(objectReference, "%s", logicalDevice->ldName); + else + sprintf(objectReference, "%s", logicalDevice->name); LogicalNode* logicalNode = (LogicalNode*) logicalDevice->firstChild; @@ -343,7 +351,7 @@ installDefaultValuesInCache(IedServer self) int refPosition = strlen(objectReference); while (dataObject != NULL) { - installDefaultValuesForDataObject(self, dataObject, objectReference, refPosition); + installDefaultValuesForDataObject(self, logicalDevice, dataObject, objectReference, refPosition); dataObject = (DataObject*) dataObject->sibling; } @@ -370,12 +378,30 @@ updateDataSetsWithCachedValues(IedServer self) while (dataSetEntry != NULL) { - char domainName[65]; + MmsDomain* domain = NULL; + + LogicalDevice* ld = IedModel_getDeviceByInst(self->model, dataSetEntry->logicalDeviceName); + + if (ld) { + + if (ld->ldName) { + domain = MmsDevice_getDomain(self->mmsDevice, ld->ldName); + } - strncpy(domainName, self->model->name, 64); - strncat(domainName, dataSetEntry->logicalDeviceName, 64 - iedNameLength); + if (domain == NULL) { + char domainName[65]; - MmsDomain* domain = MmsDevice_getDomain(self->mmsDevice, domainName); + strncpy(domainName, self->model->name, 64); + strncat(domainName, dataSetEntry->logicalDeviceName, 64 - iedNameLength); + + domain = MmsDevice_getDomain(self->mmsDevice, domainName); + } + + } + else { + if (DEBUG_IED_SERVER) + printf("IED_SERVER: ERROR - LD %s not found\n", dataSetEntry->logicalDeviceName); + } char variableName[66]; diff --git a/src/iec61850/server/mms_mapping/mms_mapping.c b/src/iec61850/server/mms_mapping/mms_mapping.c index 47348dd3..81d8a12a 100644 --- a/src/iec61850/server/mms_mapping/mms_mapping.c +++ b/src/iec61850/server/mms_mapping/mms_mapping.c @@ -1790,13 +1790,23 @@ createMmsDomainFromIedDevice(MmsMapping* self, LogicalDevice* logicalDevice) MmsDomain* domain = NULL; char domainName[65]; - int modelNameLength = strlen(self->model->name); + if (logicalDevice->ldName == NULL) { + int modelNameLength = strlen(self->model->name); - if (modelNameLength > 64) - goto exit_function; + if (modelNameLength > 64) + goto exit_function; + + strncpy(domainName, self->model->name, 64); + strncat(domainName, logicalDevice->name, 64 - modelNameLength); + domainName[64] = 0; + } + else { + if (strlen(logicalDevice->ldName) > 64) + goto exit_function; - strncpy(domainName, self->model->name, 64); - strncat(domainName, logicalDevice->name, 64 - modelNameLength); + strncpy(domainName, logicalDevice->ldName, 64); + domainName[64] = 0; + } domain = MmsDomain_create(domainName); @@ -1902,45 +1912,72 @@ createDataSets(MmsDevice* mmsDevice, IedModel* iedModel) } while (dataset != NULL) { - strncpy(domainName, iedModel->name, 64); - strncat(domainName, dataset->logicalDeviceName, 64 - iedModelNameLength); - MmsDomain* dataSetDomain = MmsDevice_getDomain(mmsDevice, domainName); + LogicalDevice* ld = IedModel_getDeviceByInst(iedModel, dataset->logicalDeviceName); + + if (ld) { - if (dataSetDomain == NULL) { + if (ld->ldName) { + strncpy(domainName, ld->ldName, 64); + domainName[64] = 0; + } + else { + strncpy(domainName, iedModel->name, 64); + strncat(domainName, dataset->logicalDeviceName, 64 - iedModelNameLength); + domainName[64] = 0; + } + + MmsDomain* dataSetDomain = MmsDevice_getDomain(mmsDevice, domainName); + + if (dataSetDomain == NULL) { + + if (DEBUG_IED_SERVER) + printf("IED_SERVER: MMS domain for dataset does not exist!\n"); + + goto exit_function; + } if (DEBUG_IED_SERVER) - printf("IED_SERVER: LD for dataset does not exist!\n"); + printf("IED_SERVER: create dataset: %s/%s\n", domainName, dataset->name); - goto exit_function; - } + MmsNamedVariableList varList = MmsNamedVariableList_create(dataSetDomain, dataset->name, false); - MmsNamedVariableList varList = MmsNamedVariableList_create(dataSetDomain, dataset->name, false); + DataSetEntry* dataSetEntry = dataset->fcdas; - DataSetEntry* dataSetEntry = dataset->fcdas; + while (dataSetEntry != NULL) { - while (dataSetEntry != NULL) { + MmsAccessSpecifier accessSpecifier; - MmsAccessSpecifier accessSpecifier; + if (ld->ldName) { + strncpy(domainName, ld->ldName, 64); + domainName[64] = 0; + } + else { + strncpy(domainName, iedModel->name, 64); + strncat(domainName, dataset->logicalDeviceName, 64 - iedModelNameLength); + domainName[64] = 0; + } - strncpy(domainName, iedModel->name, 64); - strncat(domainName, dataSetEntry->logicalDeviceName, 64 - iedModelNameLength); + accessSpecifier.domain = MmsDevice_getDomain(mmsDevice, domainName); - accessSpecifier.domain = MmsDevice_getDomain(mmsDevice, domainName); + accessSpecifier.variableName = dataSetEntry->variableName; + accessSpecifier.arrayIndex = dataSetEntry->index; + accessSpecifier.componentName = dataSetEntry->componentName; - accessSpecifier.variableName = dataSetEntry->variableName; - accessSpecifier.arrayIndex = dataSetEntry->index; - accessSpecifier.componentName = dataSetEntry->componentName; + MmsNamedVariableListEntry variableListEntry = + MmsNamedVariableListEntry_create(accessSpecifier); - MmsNamedVariableListEntry variableListEntry = - MmsNamedVariableListEntry_create(accessSpecifier); + MmsNamedVariableList_addVariable(varList, variableListEntry); - MmsNamedVariableList_addVariable(varList, variableListEntry); + dataSetEntry = dataSetEntry->sibling; + } - dataSetEntry = dataSetEntry->sibling; + MmsDomain_addNamedVariableList(dataSetDomain, varList); + } + else { + if (DEBUG_IED_SERVER) + printf("IED_SERVER: LD for dataset does not exist!\n"); } - - MmsDomain_addNamedVariableList(dataSetDomain, varList); dataset = dataset->sibling; } diff --git a/src/iec61850/server/model/model.c b/src/iec61850/server/model/model.c index 0c6e4d62..b8083ea0 100644 --- a/src/iec61850/server/model/model.c +++ b/src/iec61850/server/model/model.c @@ -73,8 +73,6 @@ IedModel_setAttributeValuesToNull(IedModel* iedModel) } } - - int IedModel_getLogicalDeviceCount(IedModel* self) { @@ -113,15 +111,30 @@ IedModel_lookupDataSet(IedModel* self, const char* dataSetReference /* e.g. ied while (dataSet != NULL) { - domainName[modelNameLen] = 0; + LogicalDevice* ld = IedModel_getDeviceByInst(self, dataSet->logicalDeviceName); - strncat(domainName, dataSet->logicalDeviceName, 64); + if (ld) { + if (ld->ldName == NULL) { + domainName[modelNameLen] = 0; - if (strncmp(domainName, dataSetReference, ldNameLen) == 0) { - if (strcmp(dataSet->name, separator + 1) == 0) { - return dataSet; - } - } + strncat(domainName, dataSet->logicalDeviceName, 64); + + if (strncmp(domainName, dataSetReference, ldNameLen) == 0) { + if (strcmp(dataSet->name, separator + 1) == 0) { + return dataSet; + } + } + } + else { + /* functional naming */ + if (strncmp(ld->ldName, dataSetReference, ldNameLen) == 0) { + if (strcmp(dataSet->name, separator + 1) == 0) { + return dataSet; + } + } + } + + } dataSet = dataSet->sibling; } @@ -136,13 +149,21 @@ IedModel_getDevice(IedModel* self, const char* deviceName) while (device != NULL) { - char domainName[65]; + if (device->ldName) { + /* functional naming */ + if (strcmp(device->ldName, deviceName) == 0) + return device; + } + else { + char domainName[65]; - strncpy(domainName, self->name, 64); - strncat(domainName, device->name, 64); + strncpy(domainName, self->name, 64); + strncat(domainName, device->name, 64); + domainName[64] = 0; - if (strcmp(domainName, deviceName) == 0) - return device; + if (strcmp(domainName, deviceName) == 0) + return device; + } device = (LogicalDevice*) device->sibling; } diff --git a/tools/model_generator/genmodel.jar b/tools/model_generator/genmodel.jar index e2b4f93f8b576e0cc82e344d0f0fc2a7118955c3..af9060187104bcf4194f09fb034ada3164dfd36a 100644 GIT binary patch delta 20170 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 delta 20110 zcmY(p18nDA&<0wYTen-=w#|QS+vb+P+O}=m*4DO-ZMWWH+imarec#PZZgP^DJei#2 zB=ekkGBd}2px6FDqbSQmLScfz!NGyGhKQ*oq3}Zeua$57Kl?@Wzcz&wobLY|C2*Gi za~6U~G6pTd30nHWT_FDt@`xbGFt!9I1KLt|9SJ0H!}pu=YJc;!JuY)Nyuq&|mWJ|q znx-tN{@TcCTrq^b^u%9tp_T1f?-TG8q zbK9;r%XpX`3$vepZsrg8dEb1>g0$l)>^}42Nf= zvA)Yd`u4UpZ?JWXXf+nM$YKBxXGhB2Qzfx^{Ws{TY2YX<`n$+(-MgBz;tERh0@lh& zo14)md#g=w;M}ueJw#q?ZDHEwL=187A-d_;b)eu zW`4iNb}hX08QwH{&7482>Soj)>HK#k#>9k|b*mGPCyn#jA~6k%TO+%JsbgbQ7i12P z-}1v>fzyxc9n0V75qTALYJW5h9MVB;bSy8#FmwS6EqYYKQ#+AAV0{(u zlVIEV#c!Mjp`@V5YRE*Cjmu(H!7p{LP}o=+-I8CwcUNq@{2?|`k`bQDPtCU!CKDXV zPZpXIBJ+>^SNY`f-1-Fn9Q$N;U9v>I`LmSRia0}POo;R!)H~}X^(Hm!CnZ(VAXK~= zoElG@6|L399+N7Nt}K&jh|AsYHt&PJm zz%s@;^eBDDL6~hKM6t+Ghu50_Mvu^3NeuDt3yg5l%6g9#&c6X~3fD41^Qt zOKzAJa~8z^gHrw{^gq7ir_>1|0GO-KJOPebd6SmkRAr2->nMZd|RNl3s= ze$!l@aJ1IMq<@aDgiEK<#N?uh7L1JUdwE{5^8dRMf%zzGW$EeV*#dw6uYdpRyyhlP zZ%*)KXZfbf>t+<^%g3G@3@OEk=g`Q{6GHt?RqjmL6@t=@HcNUkDs`sf1fY<^uKX~k zrpV62R&|Y@!r?7S(P_y{W|K=-R#lXRrZkjGS5=jrWRvqt&8>b|&Rq!6QYp$##!p-4 z8=AG^FA85*Y0i!Qga5M3F2aJGT3cvN30_-l&WW{-R=-TkOCD4(IluI}shBxG@AA<0 zp-(NG(BSs)_y!H-L%M1p0Zfi52EZFBUpD^6mm_a^H$6d$do>WfddrRqyh z{=pv*J?35_A>ar|8RzD6*~#Gyh#7ZUeWfbC=8AJ#d&Q31ufON#2&fppUHVZne!KQ6 zh`(Qb@2e3|Fmce975C?yd)J{YuSCB-f>Ul!nN@En(3{t3y~R(RY(E&M`az7h)*l9O0~Pl#oS#AC!Yi-R_+Q$`1!#YjG(NL1 z)*k=hf8_=aEWBpm17Fc+_o#CHYp>k+Uz*2XE3aPoUxvrRXkX|b(nn89_+MGwU-G8| z)*o8Q&jVE-Ia9#;D{<<-gsB()L&eXE6ygI|&VWcd)S3_GxDI2@K)OsS9*Z!#QYuUk z4@Z$|Sa~!Q^)-pC792HYRO&@4g-Wu5EVY~}M^beZM=16skm{}}8IF-JDkn*m)`O<3 zRf}E^wFq)wmq0adzmSz>20g8X>S6d-_Ayf$a4gQ#cHak5{Z;b@Qv@NcjFOl~PZVd{ zS4^OHWlxk?^;5wtw}@bfSGrWvh4UV=r}pF4N1vm(cQ#(+Xr_l#E)R zRN;zuHA$QSP1X&jxm4pdron0om?@DHli8WYQB~PIiWrjFndyU`F~@nP-85?w@E&ljZgtc$he}zL?XYS|l&%l3W@Fk#^^5ax9qQR>VH5#WyD~}# zs$Cn!2j$jBv2(akp#$ku3)LNkB%5L`@lQNy==I zCIh+6>D(h%moTdOl~IlCPF;+3YY32cOs68o`tl=;oTGa*GRId=Wn)ru4sDktMu)8_ zh6UiXJZee3WBaXfjMfpy%lb&M7Trr_NoI03bqD0|qTH;3@lqUt{=z%$^pp zk3L_0#Oou}5N)Y(?b3XD1g&vh=E>$ES`IK7u8j(T3bTYM49iY9LA~`++_}!eHqSYV z8*<}KX;h6Gy=74ymv8Y@d#j_q**^;8h?PyPuaKtvWhSLl{c59>CfL?777J7#@F?R_ z{S>zd3iY`tjd;c~j_Bn+MJIoz`hh07Q~l&8g=yd70|zQjU_l=;R39mH0c)cJxqv+) z`Uj%WSVQ$|2UWoG=xz3^IL4Ptvs6<-vM{Z8L^5P*Ck?NRK95A#NU02fuC(a1BC|lT zOtD_NP`XlDEE_?kp<#>kRGf|P^l!A9ZD9Y(DzUY=c2BFlbn2?$<`EXRR6)4SUQ$O? zd{9e6gtG*fBK0qw-4q1!A48abWx%X@*|Zf0Ni$N*s+JxL zMh*nr0b@=1nT3>Fb;CH$U7E(*+K(%04hDl?byf>)SYj>EzGdsaSGHG>7})Cx#V&NvpDU~DVkK2qset6mx+EEi z1Md6Q)yXwe54ox*Uo+{kYA!T|wzg2T*BY%+vcYOxC?-VF%jhT!Q`XLpJrOWozPA4M zA|@D(>Vak~#Np2J_VF^UROl(WK5#^is^0eQ?xJxmL+rcNH5ObxLVAR1KY72shv6dW zgzu^c%nfvr5OkT=%td|}(}0}{=QQMA^gTNsraPQ?C*(7ZkP~#sp3A$&y5^4>glHArxk8C`W*n2@a?Vq);ofXO!GpziQN%z{Z07@N8@;wI*t6N6thO(NfrCD^Z; zY_UuuX+C1JUF|KYi@XniuuuQ`H@f;dnh_3$*4JJ;BWz}Y49+iw(G4^qIZh&M>!={B zT5syu{W{7v<4>!5|J=<^X+AIRQ;?uyx!}m#Fuj=nu1dL*y(FUZW;15tA%zzrszGI3 zD1BJs&gQIWsBu$AE}LSpg6=Jep1@jGRKBCmm1GgCYH&6pX1Nx;W^O*OVL=9yRlS1e z&dm~rxs_Pov4@#$lm^Hm@oD)?2CGb0Q+aE>PW4H0p5Xs9Z!4iwxhrWtwh8C0hgVU^ zi)Hm6|4`40O`;89I-U3o^s;qu7zNLa=M|)1V?Qo^wL%&n=Zd{y$ug5hKW3X@l_&2X z{oYigBfNdr{Y-_Vi}%E$R}tZF<9;6N?B?!IY{#;Up=0oGkp-YCVNjJ%bR;OjO*J1= z>5ZT3cmmDKnThDx($uEZ0g+Us;!^XQ*+7n zT7CWdw|SLHH5U-MN~%>h8-n_E*19910qIk10VqiqPx3$%9wNrNAf*WLo?Ml$tTiyy zG-RGIHqg~D$27J%*q817#gY+L+2@vOJ0he1BwqQ3?=E7O7s>A!4bGjUxpdrXfz_I6 zF-kh-tO!#Hj|EMvCS2CeCGsaP?(b3;>mf+L;@(KR&jjeDDBIV_!Y?+py*#NrbRKA! z;;8Fj|MUMk$Yhd5jOO6x%c z=?hd%&2^HG%xYWzUDgX*b`ksq@LT`HF;LG4MUy;?B=sp{rBM$X6`_NgEWC4aGgnth zI@CFuEdYj=;$aa0FJn6ryN^8wnXIEUHuAyTub1*Qe2wo2G0_UJS-6#q_0JJImxDiG zzB41qA@IXv#u0lBb{FI7O8{JTCSuB@R_>GQou5iV@X zUt8q$$xRZZ_JSsTQ~hKn6R!F51b^nQ>#+M0kpsi8j)qpg8;E?{(}p6VTX}}FHhT!J z{(Qbkf^{w2@V^+R`oz1uXkUa*g$j3sruxLX)@fe&eDSr?J?jW6NZ8$<1>Z%jzKo5` zX4bQXjIg>n4J@aay07UBy058v%yN4!IwiZWgVL@Ep4;a7%T5Y-bT-wVmn@tv*EY|u z5dnkeB!7=hrDv^EFas0{BBar}gzdzpo^q}O!~foH+t1XeJ9uQFzEm^YTw8eIMtUgcJ@a*BniF?YCiKLXL2UFGu+s=Y{!CrqSwVz87n^ zh72QVm4H%cFV~yJGfyT}8{<0mcH5gpDbjt0ID^V*6;}>NA5bt3UfhM4bE_#kJ>bk@ z5TDdZaHapNZkTe>A^w_6%JcY{Vt*r_O1F*zwYs(}B+0{kMsVWx6cF+JC}@6v_jYS+N89L*Jy@ z-uXut3nH5n>uiA`yKVO1MMe(9X@RU3Fw9uCXqxk=zZA$yR!pr-rBF={2BH{}B)fA- zt=Mo^hBzU9iq;fR{`{5e76joX#hHTL^|Mpyr$Y+CSClP#Czq8+9(O{JSRIZ19uA_7 z`UG3HP2B9H=dybvX%N1gVy2LwQbvmfYq&e1ZfO#^RlMsjfi$y?<=Gwt@g{t)t1&1W zi;{((g@}nE6ZPzj3l~4)R)A64Ncg(OF~VO<<2vbeZZpHNj8RG047_=g>EJz#pGYg4 z(kDYb%A{-Lyz>%U@=>(^wk_pCjZ>$K`xo_HB^v4Kt)4a!i)X3C*b(~wB;@SZ}qMB7Zg=w+W@=!!^KdgBo?JjbBn zj>Wm~W1+<0C0v(0a5<>wa4sDex*=qqmU+b(eotKu&KCGC!-A$`LFD9TPa^m&lixUn{gA}Vbsik9?mC# zW^?+uPA*QaBI*F}=o))wb`+Ax-CjK2KcqNXAmUmf%(8vBZYJ%pqs-K-OjY zWz(y!adb*r76@q-zaEgh%bDhrt*&~RZ>0mzS)7q{IE^P7F-kPS)$r82G&9bp9^JbX z^Al=B^ZB8sa)Al;eN`__;+2Y_)zyHJ=$0l;)Qknms|N`0B0A=!(=qc@!I-*oNzT1A zNltJl%DI95cKnu+2ooqzc<_7smBl^J2@Knh{waJX=%DRocIZ%uoGM4$h!+ka{zuSI827^TcdIC-0pX)ark08 z+^BtmM)Ib4frP&*WJtBU#TO4@K1l5NZr5-laoEI>lo)<#DRy*zCk8v-F>dA4v^1-TSO|~QB&vdHGHXSnVy$1a(cob zXp!Ki@PTS1WC`>XnBo=>*abGhQE^=v*?@MQj@9a9$8kO?3XIF19_yJrDgI1s;ZEHeim;Im7E!(T!G3_N* zCf6muooa>E)3gUVRRwn>t?3$fZ)B{n95HGksNIpa2R;qMhG_zd`vZk*8rI4o=?cw5 zcz{5LE+gV;M<#yOL_$G(OJut!=R`_lFBVL^@)tJ3t7DlthPSMTjZWHrBbsz!zJg>% zM^cfzSkd&XYYg48yLV47WE&aR-^J5BjzNP|4%J>C?!&%_zh0u++iUUaF1Ei%;WsR5 zdbQFnyL%gEX~_PT>Dr7We{(XnaQIJNyZ{||ZLM!)iW#VA-l(dsJ$`V!Ivi?g+wO0T zeiCWh9$g{2!4m!$CK(sv^b<`t60-QxkdExyqVlXttchCw+lH>xnr|0jc2P{kWy*dO z%<2|a20~O`MdJiQz2gKlG{fehWq1{Eox<5o?hs9T#Nelre%W&s56A98SxTaUY!%WCYK%sUvzwN>(Se8#G!ON=b^%5C%dZJYIjFNi+@^pQoRHKfC?HCGHrCfcTR;0a{C+ zTxWxfS*WgvK*K~|kGEn!*)--WSAcl6S8TE-wO4BLDz#U1GAFfH((ZQKmDvGVW_q90 zhEKt}#!)H;9U*xA024LBf_$hZ)(EE*K8#%I_zhTPbmTr{9zE zwvcKv2@ay#x+m_nG{#Hl2xr5$@LS05=PU1YF0=*cJ{j96)=!A&FwoMTLMn~}afEj6 zs84Bx!vd^-RmIO~63~en?SPN<+coq{cn^=gzfl$ex$@_=ov_7pe|xIgj!&rUjz&94 zP#&?c{~n>_HS5Agx*L!v6Yv#+YUv(f6|5w45^9UD$-4a(8b_VL&5bp72$0kE1~H8U zJmG3gSb_BR##~f_?-CG=nRVI3(P*h0c<{u3;;sa_-j1>l90S za5uFzFUuZJ8og$bx}s?spc|)!cH7G*3{s^bI)eO9X;u8GbqWK$sDAF9w z`y}S-5vPUuScNlkmj^wWc@i?+9^B8ZOvxuU%eDp z>s)o5Ej~L4uoX`b%{fIwK|X4FsQB{ME+bvpk@RU!l%$$XtlYRCOM-arhkyoH7`E0@ zl(%=t#l1SA1EAoX+#t>u{(z!6y!cgK?Ho?;TAxH{`5rf9=b6yD5*0ilTE{@VeK(#f z8Oqcw=NTv3+PYb-08o8vmSbO5)-o}-#N#a0D0BaX70>al+SZP)ZV>Lb4}R8kt7irv zVKUUAq%|Xmi4-l{HT>euqH9~?OMnxICVsOI#*G|a3ZVI`m^%}cEWyVNkYE$Rg2b`Y zp?g#8@T;v>v_efMUg?zyWF~meJy>R%9jUfaxTtH(LyT5=(29BJ1?__S$T?G1GVo#Z zkm94*7lPwyNXhWl2HeY-mHTTuYvVuEf$fjK#~*(Ql7ADI9lPgit=zzSB6aHO86DOX z9gj$u0nqR^DULsy8`V@t@X>jEW;t&us--d`WzEE^uejG98%(j1jgRi}(g`sK2x zQB;`YoT}MClWkrs^@sbpQ?UhqH_)Z5X7|S!6hN?gbH*DxEuqid6Wh9A6K*PR<*P+v zAOyIGW96N`F+#}MX2dh+shf9VC5JW9+rG|;R`6Ih^NT5jKQS#I?|iMeK)n<5fp z9>kWvYI@UKG8ov-_HJm2Q@3gs*{A8qux_BWrCi~XHsP$K%&v~}5kBVlSj33e@tFDL z0eJBIvj&Me6SoVINwQX6xEoJ-nkH1;O|}g#7)<$gmuT-UPXUBrE$KSsaG<-lxI9W| z@e_Qp2-g6!-|G8d!zGnh@I304j9&@|K!hS;xWipFZTSEB>FGdu)J1oOh7{ zdx)GktABtSCkcwgwPO{dGs?hA^Y>&tNQHav8oCdT-_N;$gr4dIIK;Z*_^lZ}8OPVi zcBF11R2u7e5Qy7JY21`1GiKw_Wg1d@Jl{&*Oq{Zl8kPddysQ=1TN^o24EE$)fqM47 z3k!OM{s>3!tZue3o-la?`N7^|sa_O+5|h?di4IV8+=RJmR+g53ksDH7Jd-bG+tx%F z2kdT6iJy+nzaMt=+~|Krpg$173UVE3!OiB4qgt%)U%vb9O>pbY3tmGXcdh&M<3fIY z^WB`dZP_x4vH@0YfmvHXu>2n~Q1cH|^RF)RxufpctM=K;Y-_(|YrkVlIMU{8!S;)$ z{L}0?D(NfL-%>!>$_RI!c~firk@(u~_$}_w$C}S)iocb>fR!-rJaL?>@aR8`cf9Ed ztwlo21@H}KUeKWHD9S-9oE!xu0ws!^x?F4S2Vr93aWem4Rtw^{bMByi05X|u(|pEr z*nSE{CT^u%(sr4=EswknFKKH=#vwz-VO^$CE|U$S72C(XB)hq%u>qaPM3u zD|UAe-Vm0ZlnXg~7{Q-uxS{ByIuiU#WxCer-DuO;TLKyQp(Ty>v7%V71bCq(A zcPA&DLo{+y(yy%Jp}1GFqv+WO+NrlZA8|kTp*}!6mX)K-nE~L^fSC`BOeQqEGX%wm zpG-v90@hR^^^YRv+E7tvs*@od7Nof#R%fQ~u;-$*xu_L`&<7zgBw#orn~g+FLGp)u zo!=cp=no7#5rUmL1(4T=g*u7$LJ1Dgb|!f2jq&Zx^A54oAv>BNHio4Jf7?UsOj?SN z=OB8us2S7OguZKI0Xy>_cO-hys7-B+c?Mvj?L^rdFh5dvp?fxt@1XFfQ)=<@EgME! zt|5OA#hIhxj~hNS_J&3epss#kJ=4!Q!&Nf!6slQ#X>K~vy&G5nxL^N>J`=#*7gJD0 zjne*A#LPXLF~cLJlU010!!9^aV9kQXdl*|wiEUA+b^rJE0d+{9$-yjRl{wKKqt=!z zd>9VM2Oj1R1c~9-7w}F)B0mVeZHRhKG)rTByEiian%iXT5TRZwI7W-wftTbp-FRxX z8LJKTHs87@lEmagyFgh3VOQhX&fPFFP*RH%rgI6xjS(m(v8#9e(1tf{oFS=$!V=n7 z_mSvQw1~UQ2Nuo37s=PJ50l!N*wJ?=OWt=(p0X^6%Qn_5xWvvSUn;qMQl;XGH@atv zR8lX5%;JQoas5>-ib8l;aR>;C2I|fQt|bD^=c%PgU$4#$Sb$F^9(VxpOz%!YYip89 zAA`X@SS{N)N!kI?)rFzdlAs%jz->hQCYbWXZ%Pmz=qWVqrzc%6>uwdunDL^;i>JDq zvkUDfIv-KS`_&(N78@{#Bh`ewdZME5x5x1mhk3>{G5#dzJos*%MqIe$7c2Kf+j-!2 z5%0N;*e`MQfdDhOo`|?VDD#RvJ|euxHz2+J51sDN>hAc#o9`o9^Nqkh^h<>NIs*0p z>{?V0*nwrd6RLhVw@!i0GLNldh_Yb_pOG5jwuiWysn&++$@efpZLXIw@hWY? zVG0&>9=e(gu;@d+q6->r#V(ao+cfEsP0~0-lSU=x+c^~ilS9;(rP@HCGLIbqxBU8r z)hxIMk?TmR*Z#r+R|{<|^5|NgXPdo~DSgNRz%08FL&t`24MNNq!~MZr!PJ|P%4E=o zkYSy*XY_GRxup!Hp-ADI7FkNyes+4oJ*1l;_DMgQ;U;cK^1GKs80o8hZYmUP9u?1Z3tAxtD=r3`rwN^eq^%COgHB z$VMuDwld8NlNk4uTO-+gO<3p^tABv_ag}I<0UC-~e#>)pjT!dUr-;f-w zjvxdH0?f-8a`Fblo4oD8bLKT0Q#LlQ%{}1>e%71EZ2qf7@@hQoe1AGZalw0!dF#x{ z8+X&;6pmlLQ_~@IGXC>ndv?C90|_M8oe(!^d@#35Q8coTig=du#OE;ra+|s;<8xT& zO^>6y_IW>23`m45aHc3cn`X?fEQ~y>awnNG9yimLrt6c}8|_YJulc;Wdkp(W98(LL zb536DOO8xCX#6*+ELeI#yjcz^z1Jufygh20qxfk(n}SnZ?W@}KHHGUYG|FAWpTWW! zH!R2Cb&q_g$I0XQ(05f>C-rno|Tk18iG#N_+CWd z3$}AjiX=}IK6#Cv8NWS+R|{{up%@EK6b8Ft))@DDxNqgSGr zRw;E)G>Sw{rW6caEB-~sW#W-NS`4}(@$os^xaN9?>a08?* z9z|;HyS+rX1n|1=6%Wp;SQ0Bn%=hrh9~DwTTB#uJR1j(^h&dJHlp051u?%am{PGoV zuR7d}7vapeCX7j*!$_Dm8?C)5aIq*BEbC0Etvm*#vKJCP@bFV*I;`b$Cz;x671O4S zr^6EHFM5h;S7TOXm-XTMg;w!c793^hx9I> zji$!K9Wmn?yXsRaX>18;sd;BlYV6@)E+qC4NEFQ^zOB8DTfE`1wN|{)VB@&{W@x;9 z{D}sb#XTbHxqmrZ&lCGL-pdfc5@fUk?MVcE{BVnM)C6Wn!}t*xcx-<4CWMOL5A{b( z3QnFE*36~Rg4aSF_?Ba40v3P-?kVQ@l(tq^$q35JRV)zGmY+s9Ca7$URj z=Eo1s(U?tpp^&^`tERGE%ojT9gFSO1z3KB7`Bw-}PT}y~2^{?Dbd(1)I8WRFN{eAQ zKzPUc62$k(_lR`GB8d2h3cN;%H{XP z0{2cfpT?8@Q}>Xjox;JJ`X0B}n9fx2_y|g$t1RzumF%Q*iM8(Yqbq)_+_kR$yY%c4 zCj9lOfR^9ZZO7Dx2SX(5O<)o#9|K#_Ho%KIBxI#>*W0DAIXjf?A8moH)Wy+?Xs0-- zdAbZ*P_PAFha$HM5FKZjq}rIp+W=x*@Lf91IG6RDF+`G+( z9$3>p-3JZyURi7809T!~KK1x>tG#sX{1skuwsboiAzo6cSePK{2%^`Jdd9aFiQmXk z7h^dj{2$4hrN%pV-`WQ3;Uc5ENZrFJ>FO9=jDEDmG>vK<=@d&E|72{k8bx!Oyu#z^ zuo8&ZU-6JOkG7RAuN+rUX#e{5Nh5i;KZO!vc;F~tD* z_&u^S!T|i*z1|}9E&zjiKYK^B4?%pteMm9@S<=F<1LI_F@FrMGygxPm=&M5s1ny1| zo9Dc7wWkTsk)IooyB}|hh z`g;pxOMgJix|2jZsn{e7EKx28l%O}J_JMbs+@sfl7sic}ug}9VUsAE{`<@7F&exm=rc^P67(L4^m=O zi8TuN;$$tU7`e`xTcL3bXSG3BfX6nm1dxcFgEm8{Swoc*#H@{rV_7-VF{?eY zyPs1WCQjfWmvpGN!R~^Q>B>Nrj9ir~T$%7zTY*bk5PXX;se9N9caiHLtGv1~?mP>q zxEG678tr-YE060pKNHgFp624GaArtsH4DT%#aYzO)6{YB0FcIia zhGB@Ydx*0L8GzBJ9ey#}9UWlbh&ven4RSNe6itt+dBZhnb}jOIyXHxA;e=H}bkQ{) zYiu7ycnkL^+;b7`WItBeHI56%J1F+ZVAOgKq;O&e<>)?&*)O4RYN#^GjJf015MSyFUQt;0t!skGyRe zBbw+NDBfCJ+QM{}eTMW{XUFnT&ic@e!Mlm(57ET$3gL1x4Tk_!3lk-x0BOZ!<5TOeet) zCVq<+W#T-Obu6X~UwV&2$v@OxYMkq}Y@-WbBmV|cD<}WJN$Vv|qCcr6{QwSVb4%0w zyQBWt+jp^98lZVB7%)VXgb|;`z|dgO7s}O!rS3Ql^~K3`wbf6yKO*oNq-EMhcS`-DpJ9!Oy4g)#6E=(J)}ML#A= zULA;gxsAsPlUs0x~SgwfdH((!rLzyDiTSla^7(nJp)KPM!7 z35cpYWQ|<%JybX-nVDV1TQ@k=z1(Ya=Kf}e%lV6IEifdyuW@5{8Z88L%|QJkM&ux| z905+*BUW)A$+*-(I#;OYv@FuLnl~pbOeI=$E2PTxCuTM z162Y?1Ei%+!tk1iH$^(qJ(GKf)!fGOwoLg&=k8W=9h8uRV8$Vk*;rAcgIkQ2oAGS~ zBZpJ5<}CDhW2k4wQ$QEOj^bZUc=6x#jN3a26|ubvd3WKtV|osl79)M!xH+PH6A|AI zd#sj|5HZnDb+k+1=76XLa|LR@3T6&hwyNY#RCO2OlW179M`J@{Q_cL*cJm#V<;^?G zgc->mv#t~UQV@=S#i(o&swFU5GL%f<*Nbh1Pesf*mA@lLAM56n-%ZpWx{Sg15 z=6;-sJ5{VB%P6}@IQ~smc4#6?^13v>4QZRJk#Ml{691bk9|2Bq(SHlUrdFJ!Y&D`T zO|edK7N+bcqhUZEF7kG?3dYf*JRvpornz|2(Hu=4sOg}*9a&=brzH2X!{6Gq-WCpy z!wK_mbH&I_3^{9-KaaP`?0q;)cpp1L#F@&KsM`sIAJbQ`ahI}nZ7FHCkxO1faDHlp zPY;_pM$9ppVTisIp!Q?v!0!d3U--70r1lb)oDeSPaNq$i)d*uundJF_2=^3HDoWyU zKd?WJcsr#yMo^kyh0vHqVm7A##^7wy+_U8{JU6M0(bp>WPBEc3w9IO+)9jh{jP+a# z-V42}`2{B3N&D5lhAN>KJd7Q=^(*>KGGiItOOLL9NZvC#9t~hr9l^3nd{9V57mUds z;WX)g=+y$)15tLP#HKYH%+Jw~M<5p&KU$P&%tbO-S*o8hq!n_KiYX{Mv3g#QSU$Fh zouors6KcveBp82mx@4@H2P55=AuAp1xV|oH-9X{X4Zn`NZEOCirBQqv~W?Or? zC}rzMao78*+OAN12?dY3Q;PLFh>%Tqc1E?=cVYhDG@&`^_E5>pP5OS?{U`EDkzzg1 z-fh=Ms(IJrN~K<}0}s@Sv9M0LZO}pVUqELqM}4G(SEeMze~8yiscz2=O<*HABM{|U z%BL~AhrwS1pQM8v9b@5X$56(#P6(}s|NkY%xkMM2St174XtIxA&X0;PeyXipk5IjI zMXC?b@B-PH6bAOT0CRViezO=;mM5Xy>rKrprL=XiW^lC2WStFtJok?c%4HYlYzFqFDnZEIck2iCdI-=Q< zH`kwB+8KoXAmGhGOqy^=>5AEqVfKp8o9>i;{Hn+sG(b;%uXGBSe^%tushTHEBrbO1*SV`c9WIf!@4xw@X0s zZ=#$yo z&xLwQFT^@nzL1Cg7EAd-Q4Kx$LZP02$^+%b0Q0_)6% zRSm51Nx>ip#rKuw>TV0R+NI}4HFuYg@+>S$j20p7BeRFKmd=m+O!3$esb*s^J~<3u z9Hwe~Y_J{}Ptg|7faH9DFjNYraku1QZ)H>fS;^13y&+ZT_oiqp4fRqlI;Ks}a8jEm z(^e(eU39sVo+Tm?Ia8YRfGP(4IuWQjNB&$4Y*gi&`{bTop2#_dKh7|VrWoX9Yo}3< zr8TE$_^KLIDYaxHC&o>z@D{T$l7n`Gp|0?3T$=!T&Iw!grSN&3jPRJ1jyRUk!YeKj zY_SR+g}c;Lu7d&A=tuk^*%Bxne{!1q((iwv7+J+96Pfy=px0>a^HMlJ+lY4)S?Obi zoi(At(8IvXvy9^agDzx?CnAEMRL!T(usP$=S^G<+I3~EZOPm+74IvcXkfjsIEZU9| zQM&-d&j}EVu4A~YD`IyA|AOEy^y8@}O~%Wxt+%i~J#lExiFl)|5R%u#?@C@#>tuct zZYhcRX@k3Bzwdh~O2ZWoHm_1bkirvIhhA^rQyz5EDROkecSgFWaW=rZGU5g+r2A*a zC)YP5x)MO?4b3(W2AT}}mh2}H7r%r|EnETmn$&_uwbP1P#ei}A6P#2304+M15JGC4!Wk`J@&T2)x;bHwiGKccj! zoYbDEI+9h#H=6X7f0a|P%4sTc56po2DK?K3IBp#akLDpvm0;A$E1fGC3|SI}xI{Co z$P%}2En1Y{0@;IRx|tUXeaQ21!^gt*OGGiMp?JriRObPWq0AVRBr{KG9>>WzgtB5V z>qT9{_{hrEahg0L2&say@PV-+MAQ-8;|kAUL?dZ9NhuUP^OMNv*y2byX(@n1w|x3X zn3PMFoJ$ry`mFYrC@qRICUSBb)P(9clh9-+Njd5}x+>?OWRwINyu03H_yJl2o#Lgq zKPo~gQz2FRBr4^4Qg*LYk&Ju-=gEg zzqb2-vei4w$27&Wn9U=M@6EtEo#g_S+nnDCPIwm+ zxt^<3a!`kxJW-$GX(INmh1YG@@rxo>r4kn%wA~E(^sFSD4*gRs2Xl!p_kZq*86X8B z+RHH6hY!_Jp+gKbmaq>sVhl0c!sHQ&da{P)(9-4%$tFY(L-`6HGj+smZ=8NZ68%l0 zj)lBpdrjMZbLAkQT=ERW*S&*U{`5QzTuM_>PLx8?b;AMF*6dZ0hAQ-;W0~r9*Q6=Y zntlJHWVnx&dt`S*5usr$7C?B&VN=?f6|o_lQ&8G93ZYUKY}cC63t6C$`Ls)C5n7XK zHb}xP2G3g6sd5^(4Oa`M9vR-GIxR(0EqcTaDGSo=;@sgI6#%>CJdN_&qAd4c<&Q3P zI`87kgA(g5##57$Z<@CoEOyL22_&b9sgwOEiXrQL{aDeWNew0CmA1N;V z?O71Y;GVbfTzN;Xtf@4Fg>^aZizt-VeCxkeDx0kbFAfJE;+~Nkw%hicc6=@e(}c;& zL>s%s^o1=eDF8gw@9b3c@td8*DraqrnXdud@mG1WV5WzKQxMOKEx}(v~GvRRkBeiF(PL@(7dV%5Z!~ zs&&fP7O&_gE94icjpJ@hZN&tVp8Rf}ES=6F8s`@05VP+U4MLNb{&w=3B z;@qNwYlZE&2}V0#H_~>HE2XTq6E;WFoxA8h#&Wzy;^$yDmJO=oZNGGKW{@*ZA>Wai zkx`J{{r1UDsL6dyv6Pg=BY>ql7yVt*7B1ISuXb%`?d-y&dyUeR#)q7jT5&F_r1l~M z|0qiKocbQ-I-OHY-Bgch&qKb4PWQXXhB;qf zKX5bCJM;a?i>6GRCH8V$*ye~t-Pl6Q6D|7Ee$qKe@vjl0_I9$+n*3pCZt4*2#8Ch% zup<73CTQt$LFg*RyhGC2XyY0G8`UTD%W`=f$YGDL3Scyw3C%ch(})?dGb#1=*TjeY1~?@`M0yCeQ$!J&os{^Etc zAi}d@0^E#9aLomqjUoXfE`QGCmaQZ8>>VqHtR{bfa@nhRe8*C4PGtS!60@1D0vJ*> z`z_zP)}LCLwJ(kYipuXkglP}AB&H&_<@p=~ICs|WoL#=6CHYF=c2;R8ZV;t*BPup4 zRR8^(Jq%n+vmM%Vq7}EbAAu}_p%cKZI1jn^$sS_l6gD@+aDp}6R(x*sPn6C!5%HUl zzD}&7)e&v)W0_6+C3_y0mqkrZ4#YVHm({B$C1HnV2wcJ?gGjRK)%kR$CrY=N>Y4aA z+8Gi>yK-Mf2uID|uJt&^%cwkmJM=a@b$ei3}w0IK2-I*Syn5$TOEux{>a!|cu$ZWMDX>zut-fQpj zS|jJ14VV-hXVcNFcbtS6a1lewB;d=p?P`8HBaWYl<4U`eiCL9 znJBGPdEDOp*;yl#wNk>p1!B9oiC)|82Wygq`I=!Ahdj>NWz_pa6;6p+B;H^wX}>}- z(r!)49?1WnI<7P-sv`@(>w?f=3$h5<&<(Z{7TF}o;)N(VKXFeqpg6`UaA27;qTMP)J)<1)9a9@-Di^sj!mzWVNW zZ{51D{=7<_wKmu7>vb)GZ-!*e`NMX{w((IV&y`&tH(mPXe2Ldzf`1C}%$v8jzA87w z-cw_mv2{}P-<>=bbWDjNp@W+ub?S<9SMqPRPl@&kn%Oj0x3WCQ|A%|EZR_%N-eWGd zv^waXy!s$~(B}{DpXsZ+_3EQ=<=VpC%F_*3N;)zu+B!mxbbY5wK6QJG=keg@XO@L) zi`(p7w}*W6)%@_Xr=hyRo{I3of5|rmHTz9n_{e@(d4|F>F!*f#359iaV2%24v){Z& znrT)CLkp_ibP28I;rU%Z`%M}V8h;+oe_p{=ehYM&7q&zw(&M(>o!oS%*k^R8U2Tq& zd3#2UYg5|?{6*dH=Q-hj-4$}Opy8AKZ6T}A=j$529;Nv7d|zE+`=aoT&%fJU*OKa$ z85{J_X_C|08q@F%OAajAb2q3avF4fXL*3w-2fBH>QSJw#obRu(&)#wSsG~#PGuP@j z>)L;Fzn8Ol(&m^~d$w-LE3+O|nxoH6(GKn$S^US&BW9Kr4u zSKAuD?UL_?zb%o6Y0STomCJXTWyV&Nq$O4;XUePGpBy%;sekbJwo9Qhrs=b(%YJs+ zJ*-0cW47?Q#l?W~Sr=law>IQ|(vY$`tl+f~2fa&J7~Q*-XVB z()JVV%FG8ag*8aR&uBE^r|*+7%g1W)5c2kIG-HpT0uLfz4mQG^BPooSP}^DuFd?bS zK`xjadkjpkSEC0xYcToftC)#m1!d)RbBYjNS3ee`d{TRYg+!>w#=4>X7|D}b4?)#n z%AN$T#t~vT=Q=%vFPqLWULmsijFB2)!mZqQdGHYa(_$^BWcVFF4UZJ1!9XGGsh9}i zT<3lxZ>3#@qA2{vzn_)iN)XQI7et~R!0Ff;NM>^kg1w0<1^Vk%{h>b-q<1%gx1xm0 zTD5+L3`W0qp+6>vOcN?e?`sPxaYU0x)#)*p>%>vatuJFVXeUTBKp*7-4_UB!bgeO^ zJOr06fH7hvyk?9Q{-77rvUm!3=-UH8E{aBw2Wia&TYX?KY!U@vK@gQc$jJCC7^0Vr zgHRETGSuXD050*jSzx2j3xlg{we-k)SzM7Ko?-NhB47X$&7bR3>#^czvP%;PW`*ql z{h;}9Lkt49MYFLVAsZa^7BR3{lwKN(xihQ+X^w?)?4MH{h?{D99E332#yFV3{#}WK zMP`N>^wI}1Iv(b#43GZL-G)XvaNNy6j`K5GQjW7S zQ**XOgIzBVKk`-I@9ocVLFODcTry!bo$#*D*wDz05w6A$oJLDp5<%U|L5-UxVlq1D zKnJ5FGmfzt#4Q1wDEZF17sXTYYK`?K9Oo~A&d;Od z6*B1k1h8gFew%7^z(mY=8^XBfw%xuTZ43h{7C6=k+PeFIfEnlW0;4~&$S|9!-I<>nEm82s7pEs%J3Ab#> zZ>im$|1^voY+;eSXp#4d#O!?a@&t^e087YCqT*=>)r;>f2b#dewzXFmqKqoDo_fnW zDY7N4yHa1Kq1OdnR8MJF@APSWS3Ew8PIZ_*X|J+*MJFjM<)nB8*sz*7v;ygZI8wS2 ze95a7U`JCU)a6&TpyFK2;Yf+{dg7N3?07@c(!sH>+yn@uz)-S39oPk1;)oD)F<4v(`jnV((b= z>{7u5G%%5ZUf+F~e9gdsaY%Q_Jrb>fu`Y&UdGT-C%4)2GI9vefGC8`4F)Vh0fg^i1 zp~-c!JuAM$o%46T`8>h5A`G z=EfTr^sx)qMf$!iA8Uli)5b8GeNFZ(ujAMjY;cLB+4m;eEHV4PBsH$gK=HGYSX!@> zrx=l9#ICGjRjW{-eT2~%9#Do7=WMW`Dvvx^9^*cc8#2ZgAeXlNL9;33siJ7$qvk+}CI}m*~j4;^{i*?5R E55*7Tz5oCK diff --git a/tools/model_generator/src/com/libiec61850/tools/StaticModelGenerator.java b/tools/model_generator/src/com/libiec61850/tools/StaticModelGenerator.java index c17b86a4..d47fff4a 100644 --- a/tools/model_generator/src/com/libiec61850/tools/StaticModelGenerator.java +++ b/tools/model_generator/src/com/libiec61850/tools/StaticModelGenerator.java @@ -295,9 +295,9 @@ public class StaticModelGenerator { } } - private String getLogicalDeviceInst(LogicalDevice logicalDevice) { - return logicalDevice.getInst(); - } +// private String getLogicalDeviceInst(LogicalDevice logicalDevice) { +// return logicalDevice.getInst(); +// } private void printDeviceModelDefinitions() { @@ -320,18 +320,18 @@ public class StaticModelGenerator { for (int i = 0; i < logicalDevices.size(); i++) { LogicalDevice logicalDevice = logicalDevices.get(i); - + + String ldInst = logicalDevice.getInst(); + String ldName = modelPrefix + "_" + logicalDevice.getInst(); variablesList.add(ldName); - String logicalDeviceName = getLogicalDeviceInst(logicalDevice); - cOut.println("\nLogicalDevice " + ldName + " = {"); cOut.println(" LogicalDeviceModelType,"); - cOut.println(" \"" + logicalDeviceName + "\","); + cOut.println(" \"" + ldInst + "\","); cOut.println(" (ModelNode*) &" + modelPrefix + ","); @@ -342,7 +342,13 @@ public class StaticModelGenerator { String firstChildName = ldName + "_" + logicalDevice.getLogicalNodes().get(0).getName(); - cOut.println(" (ModelNode*) &" + firstChildName); + cOut.println(" (ModelNode*) &" + firstChildName + ","); + + if (logicalDevice.getLdName() != null) + cOut.println(" \"" + logicalDevice.getLdName() + "\""); + else + cOut.println(" NULL"); + cOut.println("};\n"); printLogicalNodeDefinitions(ldName, logicalDevice, logicalDevice.getLogicalNodes());